github.com/songzhibin97/gkit@v1.2.13/structure/zset/skiplist.go (about)

     1  // Copyright 2021 ByteDance 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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package zset
    15  
    16  import (
    17  	"github.com/songzhibin97/gkit/sys/fastrand"
    18  	"math"
    19  	"unsafe"
    20  )
    21  
    22  //
    23  // Skip list implementation.
    24  //
    25  
    26  const (
    27  	maxLevel    = 32   // same to ZSKIPLIST_MAXLEVEL, should be enough for 2^64 elements
    28  	probability = 0.25 // same to ZSKIPLIST_P, 1/4
    29  )
    30  
    31  // float64ListNode is node of float64List.
    32  type float64ListNode struct {
    33  	score float64 // key for sorting, which is allowed to be repeated
    34  	value string
    35  	prev  *float64ListNode // back pointer that only available at level 1
    36  	level int              // the length of optionalArray
    37  	oparr optionalArray
    38  }
    39  
    40  func newFloat64ListNode(score float64, value string, level int) *float64ListNode {
    41  	node := &float64ListNode{
    42  		score: score,
    43  		value: value,
    44  		level: level,
    45  	}
    46  	node.oparr.init(level)
    47  	return node
    48  }
    49  
    50  func (n *float64ListNode) loadNext(i int) *float64ListNode {
    51  	return (*float64ListNode)(n.oparr.loadNext(i))
    52  }
    53  
    54  func (n *float64ListNode) storeNext(i int, node *float64ListNode) {
    55  	n.oparr.storeNext(i, unsafe.Pointer(node))
    56  }
    57  
    58  func (n *float64ListNode) loadSpan(i int) int {
    59  	return n.oparr.loadSpan(i)
    60  }
    61  
    62  func (n *float64ListNode) storeSpan(i int, span int) {
    63  	n.oparr.storeSpan(i, span)
    64  }
    65  
    66  func (n *float64ListNode) loadNextAndSpan(i int) (*float64ListNode, int) {
    67  	return n.loadNext(i), n.loadSpan(i)
    68  }
    69  
    70  func (n *float64ListNode) storeNextAndSpan(i int, next *float64ListNode, span int) {
    71  	n.storeNext(i, next)
    72  	n.storeSpan(i, span)
    73  }
    74  
    75  func (n *float64ListNode) lessThan(score float64, value string) bool {
    76  	if n.score < score {
    77  		return true
    78  	}
    79  	if n.score == score {
    80  		return n.value < value
    81  	}
    82  	return false
    83  }
    84  
    85  func (n *float64ListNode) lessEqual(score float64, value string) bool {
    86  	if n.score < score {
    87  		return true
    88  	}
    89  	if n.score == score {
    90  		return n.value <= value
    91  	}
    92  	return false
    93  }
    94  
    95  func (n *float64ListNode) equal(score float64, value string) bool {
    96  	return n.value == value && n.score == score
    97  }
    98  
    99  // float64List is a specialized skip list implementation for sorted set.
   100  //
   101  // It is almost implement the original
   102  // algorithm described by William Pugh in " Lists: A Probabilistic
   103  // Alternative to Balanced Trees", modified in three ways:
   104  // a) this implementation allows for repeated scores.
   105  // b) the comparison is not just by key (our 'score') but by satellite data(?).
   106  // c) there is a back pointer, so it's a doubly linked list with the back
   107  // pointers being only at "level 1". This allows to traverse the list
   108  // from tail to head, useful for RevRange.
   109  type float64List struct {
   110  	header       *float64ListNode
   111  	tail         *float64ListNode
   112  	length       int
   113  	highestLevel int // highest level for now
   114  }
   115  
   116  func newFloat64List() *float64List {
   117  	l := &float64List{
   118  		header:       newFloat64ListNode(-math.MaxFloat64, "__HEADER", maxLevel), // FIXME:
   119  		highestLevel: 1,
   120  	}
   121  	return l
   122  }
   123  
   124  // Insert inserts a new node in the skiplist. Assumes the element does not already
   125  // exist (up to the caller to enforce that).
   126  func (l *float64List) Insert(score float64, value string) *float64ListNode {
   127  	var (
   128  		update [maxLevel]*float64ListNode
   129  		rank   [maxLevel + 1]int // +1 for eliminating a boundary judgment
   130  	)
   131  
   132  	x := l.header
   133  	for i := l.highestLevel - 1; i >= 0; i-- {
   134  		rank[i] = rank[i+1] // also fine when i == maxLevel - 1
   135  		next := x.loadNext(i)
   136  		for next != nil && next.lessThan(score, value) {
   137  			rank[i] += x.loadSpan(i)
   138  			x = next
   139  			next = x.loadNext(i)
   140  		}
   141  		update[i] = x
   142  	}
   143  
   144  	// We assume the element is not already inside, since we allow duplicated
   145  	// scores, reinserting the same element should never happen since the
   146  	// caller of Add() should test in the hash table if the element is
   147  	// already inside or not.
   148  	level := l.randomLevel()
   149  	if level > l.highestLevel {
   150  		// Create higher levels.
   151  		for i := l.highestLevel; i < level; i++ {
   152  			rank[i] = 0
   153  			update[i] = l.header
   154  			update[i].storeSpan(i, l.length)
   155  		}
   156  		l.highestLevel = level
   157  	}
   158  	x = newFloat64ListNode(score, value, level)
   159  	for i := 0; i < level; i++ {
   160  		// update --> x --> update.next
   161  		x.storeNext(i, update[i].loadNext(i))
   162  		update[i].storeNext(i, x)
   163  		// update[i].span is splitted to: new update[i].span and x.span
   164  		x.storeSpan(i, update[i].loadSpan(i)-(rank[0]-rank[i]))
   165  		update[i].storeSpan(i, (rank[0]-rank[i])+1)
   166  	}
   167  	// Increment span for untouched levels.
   168  	for i := level; i < l.highestLevel; i++ {
   169  		update[i].storeSpan(i, update[i].loadSpan(i)+1)
   170  	}
   171  
   172  	// Update back pointer.
   173  	if update[0] != l.header {
   174  		x.prev = update[0]
   175  	}
   176  
   177  	if next := x.loadNext(0); next != nil { // not tail of skiplist
   178  		next.prev = x
   179  	} else {
   180  		l.tail = x
   181  	}
   182  	l.length++
   183  
   184  	return x
   185  }
   186  
   187  // randomLevel returns a level between [1, maxLevel] for insertion.
   188  func (l *float64List) randomLevel() int {
   189  	level := 1
   190  	for fastrand.Uint32n(1/probability) == 0 {
   191  		level++
   192  	}
   193  	if level > maxLevel {
   194  		return maxLevel
   195  	}
   196  	return level
   197  }
   198  
   199  // Rank finds the rank for an element by both score and value.
   200  // Returns 0 when the element cannot be found, rank otherwise.
   201  //
   202  // NOTE: the rank is 1-based due to the span of l->header to the
   203  // first element.
   204  func (l *float64List) Rank(score float64, value string) int {
   205  	rank := 0
   206  	x := l.header
   207  	for i := l.highestLevel - 1; i >= 0; i-- {
   208  		next := x.loadNext(i)
   209  		for next != nil && next.lessEqual(score, value) {
   210  			rank += x.loadSpan(i)
   211  			x = next
   212  			next = x.loadNext(i)
   213  		}
   214  
   215  		// x might be equal to l->header, so test if obj is non-nil
   216  		// TODO: Why not use if x != l.header?
   217  		if x.equal(score, value) {
   218  			return rank
   219  		}
   220  	}
   221  	return 0
   222  }
   223  
   224  // deleteNode is a internal function for deleting node x in O(1) time by giving a
   225  // update position matrix.
   226  func (l *float64List) deleteNode(x *float64ListNode, update *[maxLevel]*float64ListNode) {
   227  	for i := 0; i < l.highestLevel; i++ {
   228  		if update[i].loadNext(i) == x {
   229  			// Remove x, updaet[i].span = updaet[i].span + x.span - 1 (x removed).
   230  			next, span := x.loadNextAndSpan(i)
   231  			span += update[i].loadSpan(i) - 1
   232  			update[i].storeNextAndSpan(i, next, span)
   233  		} else {
   234  			// x does not appear on this level, just update span.
   235  			update[i].storeSpan(i, update[i].loadSpan(i)-1)
   236  		}
   237  	}
   238  	if next := x.loadNext(0); next != nil { // not tail of skiplist
   239  		next.prev = x.prev
   240  	} else {
   241  		l.tail = x.prev
   242  	}
   243  	for l.highestLevel > 1 && l.header.loadNext(l.highestLevel-1) != nil {
   244  		// Clear the pointer and span for safety.
   245  		l.header.storeNextAndSpan(l.highestLevel-1, nil, 0)
   246  		l.highestLevel--
   247  	}
   248  	l.length--
   249  }
   250  
   251  // Delete deletes an element with matching score/element from the skiplist.
   252  // The deleted node is returned if the node was found, otherwise 0 is returned.
   253  func (l *float64List) Delete(score float64, value string) *float64ListNode {
   254  	var update [maxLevel]*float64ListNode
   255  
   256  	x := l.header
   257  	for i := l.highestLevel - 1; i >= 0; i-- {
   258  		next := x.loadNext(i)
   259  		for next != nil && next.lessThan(score, value) {
   260  			x = next
   261  			next = x.loadNext(i)
   262  		}
   263  		update[i] = x
   264  	}
   265  	x = x.loadNext(0)
   266  	if x != nil && x.equal(score, value) {
   267  		l.deleteNode(x, &update)
   268  		return x
   269  	}
   270  	return nil // not found
   271  }
   272  
   273  // UpdateScore updates the score of an element inside the sorted set skiplist.
   274  //
   275  // NOTE: the element must exist and must match 'score'.
   276  // This function does not update the score in the hash table side, the
   277  // caller should take care of it.
   278  //
   279  // NOTE: this function attempts to just update the node, in case after
   280  // the score update, the node would be exactly at the same position.
   281  // Otherwise the skiplist is modified by removing and re-adding a new
   282  // element, which is more costly.
   283  //
   284  // The function returns the updated element skiplist node pointer.
   285  func (l *float64List) UpdateScore(oldScore float64, value string, newScore float64) *float64ListNode {
   286  	var update [maxLevel]*float64ListNode
   287  
   288  	x := l.header
   289  	for i := l.highestLevel - 1; i >= 0; i-- {
   290  		next := x.loadNext(i)
   291  		for next != nil && next.lessThan(oldScore, value) {
   292  			x = next
   293  			next = x.loadNext(i)
   294  		}
   295  		update[i] = x
   296  	}
   297  
   298  	// Jump to our element: note that this function assumes that the
   299  	// element with the matching score exists.
   300  	x = x.loadNext(0)
   301  
   302  	// Fastpath: If the node, after the score update, would be still exactly
   303  	// at the same position, we can just update the score without
   304  	// actually removing and re-inserting the element in the skiplist.
   305  	if next := x.loadNext(0); (x.prev == nil || x.prev.score < newScore) &&
   306  		(next == nil || next.score > newScore) {
   307  		x.score = newScore
   308  		return x
   309  	}
   310  
   311  	// No way to reuse the old node: we need to remove and insert a new
   312  	// one at a different place.
   313  	v := x.value
   314  	l.deleteNode(x, &update)
   315  	newNode := l.Insert(newScore, v)
   316  	return newNode
   317  }
   318  
   319  func greaterThanMin(value float64, min float64, ex bool) bool {
   320  	if ex {
   321  		return value > min
   322  	}
   323  	return value >= min
   324  }
   325  
   326  func lessThanMax(value float64, max float64, ex bool) bool {
   327  	if ex {
   328  		return value < max
   329  	}
   330  	return value <= max
   331  }
   332  
   333  // DeleteRangeByScore deletes all the elements with score between min and max
   334  // from the skiplist.
   335  // Both min and max can be inclusive or exclusive (see RangeOpt).
   336  // When inclusive a score >= min && score <= max is deleted.
   337  //
   338  // This function returns count of deleted elements.
   339  func (l *float64List) DeleteRangeByScore(min, max float64, opt RangeOpt, dict map[string]float64) []Float64Node {
   340  	var (
   341  		update  [maxLevel]*float64ListNode
   342  		removed []Float64Node
   343  	)
   344  
   345  	x := l.header
   346  	for i := l.highestLevel - 1; i >= 0; i-- {
   347  		next := x.loadNext(i)
   348  		for next != nil && !greaterThanMin(next.score, min, opt.ExcludeMin) {
   349  			x = next
   350  			next = x.loadNext(i)
   351  		}
   352  		update[i] = x
   353  	}
   354  
   355  	// Current node is the last with score not greater than min.
   356  	x = x.loadNext(0)
   357  
   358  	// Delete nodes in range.
   359  	for x != nil && lessThanMax(x.score, max, opt.ExcludeMax) {
   360  		next := x.loadNext(0)
   361  		l.deleteNode(x, &update)
   362  		delete(dict, x.value)
   363  		removed = append(removed, Float64Node{
   364  			Value: x.value,
   365  			Score: x.score,
   366  		})
   367  		x = next
   368  	}
   369  
   370  	return removed
   371  }
   372  
   373  // Delete all the elements with rank between start and end from the skiplist.
   374  // Start and end are inclusive.
   375  //
   376  // NOTE: start and end need to be 1-based
   377  func (l *float64List) DeleteRangeByRank(start, end int, dict map[string]float64) []Float64Node {
   378  	var (
   379  		update    [maxLevel]*float64ListNode
   380  		removed   []Float64Node
   381  		traversed int
   382  	)
   383  
   384  	x := l.header
   385  	for i := l.highestLevel - 1; i >= 0; i-- {
   386  		next, span := x.loadNextAndSpan(i)
   387  		for next != nil && traversed+span < start {
   388  			traversed += span
   389  			x = next
   390  			next, span = x.loadNextAndSpan(i)
   391  		}
   392  		update[i] = x
   393  	}
   394  
   395  	traversed++
   396  	x = x.loadNext(0)
   397  	// Delete nodes in range.
   398  	for x != nil && traversed <= end {
   399  		next := x.loadNext(0)
   400  		l.deleteNode(x, &update)
   401  		delete(dict, x.value)
   402  		removed = append(removed, Float64Node{
   403  			Value: x.value,
   404  			Score: x.score,
   405  		})
   406  		traversed++
   407  		x = next
   408  	}
   409  	return removed
   410  }
   411  
   412  // GetNodeByRank finds an element by its rank. The rank argument needs to be 1-based.
   413  func (l *float64List) GetNodeByRank(rank int) *float64ListNode {
   414  	var traversed int
   415  
   416  	x := l.header
   417  	for i := l.highestLevel - 1; i >= 0; i-- {
   418  		next, span := x.loadNextAndSpan(i)
   419  		for next != nil && traversed+span <= rank {
   420  			traversed += span
   421  			x = next
   422  			next, span = x.loadNextAndSpan(i)
   423  		}
   424  		if traversed == rank {
   425  			return x
   426  		}
   427  	}
   428  	return nil
   429  }
   430  
   431  // FirstInRange finds the first node that is contained in the specified range.
   432  func (l *float64List) FirstInRange(min, max float64, opt RangeOpt) *float64ListNode {
   433  	if !l.IsInRange(min, max, opt) {
   434  		return nil
   435  	}
   436  
   437  	x := l.header
   438  	for i := l.highestLevel - 1; i >= 0; i-- {
   439  		next := x.loadNext(i)
   440  		for next != nil && !greaterThanMin(next.score, min, opt.ExcludeMin) {
   441  			x = next
   442  			next = x.loadNext(i)
   443  		}
   444  	}
   445  
   446  	// The next node MUST not be NULL (excluded by IsInRange).
   447  	x = x.loadNext(0)
   448  	if !lessThanMax(x.score, max, opt.ExcludeMax) {
   449  		return nil
   450  	}
   451  	return x
   452  }
   453  
   454  // LastInRange finds the last node that is contained in the specified range.
   455  func (l *float64List) LastInRange(min, max float64, opt RangeOpt) *float64ListNode {
   456  	if !l.IsInRange(min, max, opt) {
   457  		return nil
   458  	}
   459  
   460  	x := l.header
   461  	for i := l.highestLevel - 1; i >= 0; i-- {
   462  		next := x.loadNext(i)
   463  		for next != nil && lessThanMax(next.score, max, opt.ExcludeMax) {
   464  			x = next
   465  			next = x.loadNext(i)
   466  		}
   467  	}
   468  
   469  	// The node x must not be NULL (excluded by IsInRange).
   470  	if !greaterThanMin(x.score, min, opt.ExcludeMin) {
   471  		return nil
   472  	}
   473  	return x
   474  }
   475  
   476  // IsInRange returns whether there is a port of sorted set in given range.
   477  func (l *float64List) IsInRange(min, max float64, opt RangeOpt) bool {
   478  	// Test empty range.
   479  	if min > max || (min == max && (opt.ExcludeMin || opt.ExcludeMax)) {
   480  		return false
   481  	}
   482  	if l.tail == nil || !greaterThanMin(l.tail.score, min, opt.ExcludeMin) {
   483  		return false
   484  	}
   485  	if next := l.header.loadNext(0); next == nil || !lessThanMax(next.score, max, opt.ExcludeMax) {
   486  		return false
   487  	}
   488  	return true
   489  }