github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/puller/frontier/heap.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 type fibonacciHeapNode struct { 17 key uint64 18 19 left *fibonacciHeapNode 20 right *fibonacciHeapNode 21 children *fibonacciHeapNode 22 parent *fibonacciHeapNode 23 rank int 24 marked bool 25 } 26 27 type fibonacciHeap struct { 28 root *fibonacciHeapNode 29 min *fibonacciHeapNode 30 31 dirty bool 32 } 33 34 // GetMinKey returns the minimum key in the heap 35 func (h *fibonacciHeap) GetMinKey() uint64 { 36 if h.dirty { 37 h.consolidate() 38 h.dirty = false 39 } 40 return h.min.key 41 } 42 43 // Insert inserts a new node into the heap and returns this new node 44 func (h *fibonacciHeap) Insert(key uint64) *fibonacciHeapNode { 45 x := &fibonacciHeapNode{key: key} 46 h.addToRoot(x) 47 if h.min == nil || h.min.key > x.key { 48 h.min = x 49 } 50 return x 51 } 52 53 // Remove removes a node from the heap 54 func (h *fibonacciHeap) Remove(x *fibonacciHeapNode) { 55 if x == h.min { 56 h.dirty = true 57 } 58 59 child := x.children 60 isLast := child == nil 61 62 for !isLast { 63 next := child.right 64 isLast = next == x.children 65 h.removeChildren(x, child) 66 h.addToRoot(child) 67 child = next 68 } 69 70 parent := x.parent 71 if parent != nil { 72 h.removeChildren(parent, x) 73 if parent.marked { 74 h.cascadingCut(parent) 75 } else { 76 parent.marked = true 77 } 78 } else { 79 h.cutFromRoot(x) 80 } 81 } 82 83 // UpdateKey updates the key of the node in the heap 84 func (h *fibonacciHeap) UpdateKey(x *fibonacciHeapNode, key uint64) { 85 switch { 86 case x.key == key: 87 return 88 case x.key > key: 89 h.decreaseKey(x, key) 90 case x.key < key: 91 h.increaseKey(x, key) 92 } 93 } 94 95 func (h *fibonacciHeap) increaseKey(x *fibonacciHeapNode, key uint64) { 96 if x == h.min { 97 h.dirty = true 98 } 99 100 x.key = key 101 child := x.children 102 cascadingCut := false 103 isLast := child == nil 104 105 for !isLast { 106 next := child.right 107 isLast = next == x.children 108 109 if child.key < x.key { 110 h.removeChildren(x, child) 111 h.addToRoot(child) 112 if x.marked { 113 cascadingCut = true 114 } 115 x.marked = true 116 } 117 118 child = next 119 } 120 121 if cascadingCut { 122 h.cascadingCut(x) 123 } 124 } 125 126 func (h *fibonacciHeap) decreaseKey(x *fibonacciHeapNode, key uint64) { 127 x.key = key 128 parent := x.parent 129 if parent != nil && parent.key > x.key { 130 h.removeChildren(parent, x) 131 h.addToRoot(x) 132 if parent.marked { 133 h.cascadingCut(parent) 134 } else { 135 parent.marked = true 136 } 137 } 138 if x.parent == nil && h.min.key > key { 139 h.min = x 140 } 141 } 142 143 func (h *fibonacciHeap) cascadingCut(x *fibonacciHeapNode) { 144 x.marked = false 145 for p := x.parent; p != nil; p = p.parent { 146 h.removeChildren(p, x) 147 h.addToRoot(x) 148 x.marked = false 149 if !p.marked { 150 p.marked = true 151 break 152 } 153 x = p 154 } 155 } 156 157 // The upper bound of fibonacci heap's rank is log1.618(n). 158 // So if we allow 1 << 32 (4294967296) spans tracked by this heap, 159 // we can know the size of consolidate table is around 46.09545510610244. 160 const consolidateTableSize = 47 161 162 func (h *fibonacciHeap) consolidate() { 163 var table [consolidateTableSize]*fibonacciHeapNode 164 x := h.root 165 maxOrder := 0 166 h.min = h.root 167 168 for { 169 y := x 170 x = x.right 171 z := table[y.rank] 172 for z != nil { 173 table[y.rank] = nil 174 if y.key > z.key { 175 y, z = z, y 176 } 177 h.addChildren(y, z) 178 z = table[y.rank] 179 } 180 table[y.rank] = y 181 if y.rank > maxOrder { 182 maxOrder = y.rank 183 } 184 185 if x == h.root { 186 break 187 } 188 } 189 190 h.root = nil 191 for _, n := range table { 192 if n == nil { 193 continue 194 } 195 if h.min.key > n.key { 196 h.min = n 197 } 198 h.addToRoot(n) 199 } 200 } 201 202 func (h *fibonacciHeap) addChildren(root, x *fibonacciHeapNode) { 203 root.children = h.insertInto(root.children, x) 204 root.rank++ 205 x.parent = root 206 } 207 208 func (h *fibonacciHeap) removeChildren(root, x *fibonacciHeapNode) { 209 root.children = h.cutFrom(root.children, x) 210 root.rank-- 211 x.parent = nil 212 } 213 214 func (h *fibonacciHeap) addToRoot(x *fibonacciHeapNode) { 215 h.root = h.insertInto(h.root, x) 216 } 217 218 func (h *fibonacciHeap) cutFromRoot(x *fibonacciHeapNode) { 219 h.root = h.cutFrom(h.root, x) 220 } 221 222 func (h *fibonacciHeap) insertInto(head *fibonacciHeapNode, x *fibonacciHeapNode) *fibonacciHeapNode { 223 if head == nil { 224 x.left = x 225 x.right = x 226 } else { 227 head.left.right = x 228 x.right = head 229 x.left = head.left 230 head.left = x 231 } 232 return x 233 } 234 235 func (h *fibonacciHeap) cutFrom(head *fibonacciHeapNode, x *fibonacciHeapNode) *fibonacciHeapNode { 236 if x.right == x { 237 x.right = nil 238 x.left = nil 239 return nil 240 } 241 242 x.right.left = x.left 243 x.left.right = x.right 244 ret := x.right 245 x.right = nil 246 x.left = nil 247 if head == x { 248 return ret 249 } 250 return head 251 }