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  }