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  }