github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/puller/frontier/list.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package frontier 15 16 import ( 17 "bytes" 18 "fmt" 19 "math" 20 "strings" 21 _ "unsafe" // required by go:linkname 22 23 "github.com/pingcap/log" 24 ) 25 26 const ( 27 maxHeight = 12 28 ) 29 30 type skipListNode struct { 31 key []byte 32 value *fibonacciHeapNode 33 34 end []byte 35 regionID uint64 36 37 nexts []*skipListNode 38 } 39 40 // Key is the key of the node 41 func (s *skipListNode) Key() []byte { 42 return s.key 43 } 44 45 func (s *skipListNode) End() []byte { 46 return s.end 47 } 48 49 // Value is the value of the node 50 func (s *skipListNode) Value() *fibonacciHeapNode { 51 return s.value 52 } 53 54 // Next returns the next node in the list 55 func (s *skipListNode) Next() *skipListNode { 56 return s.nexts[0] 57 } 58 59 type seekResult []*skipListNode 60 61 // Next points to the next seek seekTempResult 62 func (s seekResult) Next() { 63 next := s.Node().Next() 64 for i := range next.nexts { 65 s[i] = next 66 } 67 } 68 69 // Node returns the node point by the seek seekTempResult 70 func (s seekResult) Node() *skipListNode { 71 if len(s) == 0 { 72 return nil 73 } 74 return s[0] 75 } 76 77 type skipList struct { 78 head skipListNode 79 height int 80 } 81 82 func newSpanList() *skipList { 83 l := new(skipList) 84 l.head.nexts = make([]*skipListNode, maxHeight) 85 return l 86 } 87 88 func (l *skipList) randomHeight() int { 89 h := 1 90 for h < maxHeight && fastrand() < uint32(math.MaxUint32)/4 { 91 h++ 92 } 93 return h 94 } 95 96 //go:linkname fastrand runtime.fastrand 97 func fastrand() uint32 98 99 // Seek returns the seek seekTempResult 100 // the seek seekTempResult is a slice of nodes, 101 // Each element in the slice represents the nearest(left) node to the target value at each level of the skip list. 102 func (l *skipList) Seek(key []byte, result []*skipListNode) seekResult { 103 head := &l.head 104 current := head 105 106 LevelLoop: 107 for level := l.height - 1; level >= 0; level-- { 108 for { 109 next := current.nexts[level] 110 if next == nil { 111 result[level] = current 112 continue LevelLoop 113 } 114 cmp := bytes.Compare(key, next.key) 115 if cmp < 0 { 116 result[level] = current 117 continue LevelLoop 118 } 119 if cmp == 0 { 120 for ; level >= 0; level-- { 121 result[level] = next 122 } 123 return result 124 } 125 current = next 126 } 127 } 128 129 return result 130 } 131 132 // InsertNextToNode insert the specified node after the seek seekTempResult 133 func (l *skipList) InsertNextToNode(seekR seekResult, key []byte, value *fibonacciHeapNode, regionID uint64) { 134 if seekR.Node() != nil && !nextTo(seekR.Node(), key) { 135 log.Panic("the InsertNextToNode function can only append node to the seek result.") 136 } 137 height := l.randomHeight() 138 if l.height < height { 139 l.height = height 140 } 141 n := &skipListNode{ 142 key: key, 143 value: value, 144 regionID: regionID, 145 nexts: make([]*skipListNode, height), 146 } 147 148 for level := 0; level < height; level++ { 149 prev := seekR[level] 150 if prev == nil { 151 prev = &l.head 152 } 153 n.nexts[level] = prev.nexts[level] 154 prev.nexts[level] = n 155 } 156 } 157 158 // Insert inserts the specified node 159 func (l *skipList) Insert(key []byte, value *fibonacciHeapNode) { 160 seekR := l.Seek(key, make(seekResult, maxHeight)) 161 l.InsertNextToNode(seekR, key, value, fakeRegionID) 162 } 163 164 // Remove removes the specified node after the seek seekTempResult 165 func (l *skipList) Remove(seekR seekResult, toRemove *skipListNode) { 166 seekCurrent := seekR.Node() 167 if seekCurrent == nil || seekCurrent.Next() != toRemove { 168 log.Panic("the Remove function can only remove node right next to the seek result.") 169 } 170 for i := range toRemove.nexts { 171 seekR[i].nexts[i] = toRemove.nexts[i] 172 } 173 } 174 175 // First returns the first node in the list 176 func (l *skipList) First() *skipListNode { 177 return l.head.Next() 178 } 179 180 // Entries visit all the nodes in the list 181 func (l *skipList) Entries(fn func(*skipListNode) bool) { 182 for node := l.First(); node != nil; node = node.Next() { 183 if cont := fn(node); !cont { 184 return 185 } 186 } 187 } 188 189 // String implements fmt.Stringer interface. 190 func (l *skipList) String() string { 191 var buf strings.Builder 192 l.Entries(func(node *skipListNode) bool { 193 buf.WriteString(fmt.Sprintf("[%s] ", node.key)) 194 return true 195 }) 196 return buf.String() 197 } 198 199 // nextTo check if the key is right next to the node in list. 200 // the specified node is a node in the list. 201 // the specified key is a bytes to check position. 202 // return true if the key is right next to the node. 203 func nextTo(node *skipListNode, key []byte) bool { 204 cmp := bytes.Compare(node.key, key) 205 switch { 206 case cmp == 0: 207 return true 208 case cmp > 0: 209 return false 210 } 211 // cmp must be less than 0 here 212 next := node.nexts[0] 213 if next == nil { 214 // the node is the last node in the list 215 // we can insert the key after the last node. 216 return true 217 } 218 if bytes.Compare(next.key, key) <= 0 { 219 // the key of next node is less or equal to the specified key, 220 // this specified key should be inserted after the next node. 221 return false 222 } 223 // the key is between with the node and the next node. 224 return true 225 }