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 }