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  }