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