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
Hide 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