Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
c45570f4
Commit
c45570f4
authored
Jan 26, 2023
by
Vitaly Arbuzov
Browse files
Make random dict selection fair
parent
2a9c77a2
Changes
2
Show whitespace changes
Inline
Side-by-side
src/db.c
View file @
c45570f4
...
@@ -387,17 +387,26 @@ robj *dbRandomKey(redisDb *db) {
...
@@ -387,17 +387,26 @@ robj *dbRandomKey(redisDb *db) {
/* Return random non-empty dictionary from this DB. */
/* Return random non-empty dictionary from this DB. */
dict *getRandomDict(redisDb *db) {
dict *getRandomDict(redisDb *db) {
if (db->dict_count == 1) return db->dict[0];
if (db->dict_count == 1) return db->dict[0];
unsigned long long target = rand();
int i = 0, r = 0;
/* If number of keys is greater than max target value, then we should call target once more and get more entropy. */
for (int j = 0; j < CLUSTER_SLOTS; j++) {
if (db->key_count > RAND_MAX) {
/* Skip empty dicts or if we want only rehashing dicts and the dict isn't rehashing. */
target <<= 32;
if (dictSize(db->dict[j]) == 0) continue;
target |= rand();
if (i == 0 || (rand() % (i + 1)) == 0) {
}
r = j; /* Select K-th non-empty bucket with 1/K probability, this keeps balanced probabilities for all non-empty buckets. */
unsigned long long int key_count = dbSize(db);
target = key_count ? target % key_count : 0; /* Random key index in range [0..KEY_COUNT), or 0 if db is empty. */
/* In linearly enumerated key space, find a slot that contains target key. */
dbIterator dbit;
dbInitIterator(&dbit, db);
dict *d = NULL;
while ((d = dbNextDict(&dbit))) {
unsigned long long int ds = dictSize(d);
if (target < ds) { /* Found dict that contains target key. */
break;
}
}
i++
;
target -= ds
;
}
}
return d
b->dict[r]
;
return d;
}
}
/* Helper for sync and async delete. */
/* Helper for sync and async delete. */
...
@@ -427,6 +436,7 @@ int dbGenericDelete(redisDb *db, robj *key, int async, int flags) {
...
@@ -427,6 +436,7 @@ int dbGenericDelete(redisDb *db, robj *key, int async, int flags) {
* the key, because it is shared with the main dictionary. */
* the key, because it is shared with the main dictionary. */
if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr);
if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr);
dictTwoPhaseUnlinkFree(d,de,plink,table);
dictTwoPhaseUnlinkFree(d,de,plink,table);
db->key_count--;
return 1;
return 1;
} else {
} else {
return 0;
return 0;
...
...
src/server.h
View file @
c45570f4
...
@@ -960,6 +960,7 @@ typedef struct redisDb {
...
@@ -960,6 +960,7 @@ typedef struct redisDb {
list *rehashing; /* List of dictionaries in this DB that are currently rehashing. */
list *rehashing; /* List of dictionaries in this DB that are currently rehashing. */
int dict_count; /* Indicates total number of dictionaires owned by this DB, 1 dict per slot in cluster mode. */
int dict_count; /* Indicates total number of dictionaires owned by this DB, 1 dict per slot in cluster mode. */
int command_slot; /* Slot that is used by the current command that uses DB, -1 if cluster mode is disabled, or if command uses multiple slots. */
int command_slot; /* Slot that is used by the current command that uses DB, -1 if cluster mode is disabled, or if command uses multiple slots. */
unsigned long long key_count; /* Total number of keys in this DB. */
} redisDb;
} redisDb;
/* forward declaration for functions ctx */
/* forward declaration for functions ctx */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment