@@ -488,24 +488,14 @@ unsigned long long cumulativeKeyCountRead(redisDb *db, int slot, dbKeyType keyTy
488
488
}
489
489
490
490
/* Returns fair random slot, probability of each slot being returned is proportional to the number of elements that slot dictionary holds.
491
- * Implementation uses binary search on top of binary index tree.
492
491
* This function guarantees that it returns a slot whose dict is non-empty, unless the entire db is empty.
493
- * Time complexity of this function is O(log^2 (CLUSTER_SLOTS)). */
492
+ * Time complexity of this function is O(log(CLUSTER_SLOTS)). */
494
493
int getFairRandomSlot (redisDb * db , dbKeyType keyType ) {
495
494
unsigned long target = dbSize (db , keyType ) ? (randomULong () % dbSize (db , keyType )) + 1 : 0 ;
496
495
int slot = findSlotByKeyIndex (db , target , keyType );
497
496
return slot ;
498
497
}
499
498
500
- static inline unsigned long dictSizebySlot (redisDb * db , int slot , dbKeyType keyType ) {
501
- if (keyType == DB_MAIN )
502
- return dictSize (db -> dict [slot ]);
503
- else if (keyType == DB_EXPIRES )
504
- return dictSize (db -> expires [slot ]);
505
- else
506
- serverPanic ("Unknown keyType" );
507
- }
508
-
509
499
/* Finds a slot containing target element in a key space ordered by slot id.
510
500
* Consider this example. Slots are represented by brackets and keys by dots:
511
501
* #0 #1 #2 #3 #4
@@ -516,27 +506,30 @@ static inline unsigned long dictSizebySlot(redisDb *db, int slot, dbKeyType keyT
516
506
* In this case slot #3 contains key that we are trying to find.
517
507
*
518
508
* This function is 1 based and the range of the target is [1..dbSize], dbSize inclusive.
519
- * Time complexity of this function is O(log^2(CLUSTER_SLOTS))
520
- * */
509
+ *
510
+ * To find the slot, we start with the root node of the binary index tree and search through its children
511
+ * from the highest index (2^14 in our case) to the lowest index. At each node, we check if the target
512
+ * value is greater than the node's value. If it is, we remove the node's value from the target and recursively
513
+ * search for the new target using the current node as the parent.
514
+ * Time complexity of this function is O(log(CLUSTER_SLOTS))
515
+ */
521
516
int findSlotByKeyIndex (redisDb * db , unsigned long target , dbKeyType keyType ) {
522
517
if (!server .cluster_enabled || dbSize (db , keyType ) == 0 ) return 0 ;
523
518
serverAssert (target <= dbSize (db , keyType ));
524
- int lo = 0 , hi = CLUSTER_SLOTS - 1 ;
525
- /* We use binary search to find a slot, we are allowed to do this, because we have a quick way to find a total number of keys
526
- * up until certain slot, using binary index tree. */
527
- while (lo <= hi ) {
528
- int mid = lo + (hi - lo ) / 2 ;
529
- unsigned long keys_up_to_mid = cumulativeKeyCountRead (db , mid , keyType ); /* Total number of keys up until a given slot (inclusive). */
530
- unsigned long keys_in_mid = dictSizebySlot (db , mid , keyType );
531
- if (target > keys_up_to_mid ) { /* Target is to the right from mid. */
532
- lo = mid + 1 ;
533
- } else if (target <= keys_up_to_mid - keys_in_mid ) { /* Target is to the left from mid. */
534
- hi = mid - 1 ;
535
- } else { /* Located target. */
536
- return mid ;
519
+
520
+ int result = 0 , bit_mask = 1 << CLUSTER_SLOT_MASK_BITS ;
521
+ for (int i = bit_mask ; i != 0 ; i >>= 1 ) {
522
+ int current = result + i ;
523
+ /* When the target index is greater than 'current' node value the we will update
524
+ * the target and search in the 'current' node tree. */
525
+ if (target > db -> sub_dict [keyType ].slot_size_index [current ]) {
526
+ target -= db -> sub_dict [keyType ].slot_size_index [current ];
527
+ result = current ;
537
528
}
538
529
}
539
- serverPanic ("Unable to find a slot that contains target key." );
530
+ /* Unlike BIT, slots are 0-based, so we need to subtract 1, but we also need to add 1,
531
+ * since we want the next slot. */
532
+ return result ;
540
533
}
541
534
542
535
/* Helper for sync and async delete. */
0 commit comments