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