Commit 6bda18ff authored by antirez's avatar antirez
Browse files

Less blocking dictGetRandomKeys().

Related to issue #2306.
parent cfe21852
...@@ -666,34 +666,42 @@ dictEntry *dictGetRandomKey(dict *d) ...@@ -666,34 +666,42 @@ dictEntry *dictGetRandomKey(dict *d)
* at producing N elements, and the elements are guaranteed to be non * at producing N elements, and the elements are guaranteed to be non
* repeating. */ * repeating. */
unsigned int dictGetRandomKeys(dict *d, dictEntry **des, unsigned int count) { unsigned int dictGetRandomKeys(dict *d, dictEntry **des, unsigned int count) {
int j; /* internal hash table id, 0 or 1. */ unsigned int j; /* internal hash table id, 0 or 1. */
unsigned int stored = 0; unsigned int tables; /* 1 or 2 tables? */
unsigned int stored = 0, maxsizemask;
if (dictSize(d) < count) count = dictSize(d); if (dictSize(d) < count) count = dictSize(d);
/* Try to do a rehashing work proportional to 'count'. */
for (j = 0; j < count; j++) {
if (dictIsRehashing(d))
_dictRehashStep(d);
else
break;
}
tables = dictIsRehashing(d) ? 2 : 1;
maxsizemask = d->ht[0].sizemask;
if (tables > 1 && maxsizemask < d->ht[1].sizemask)
maxsizemask = d->ht[1].sizemask;
/* Pick a random point inside the larger table. */
unsigned int i = random() & maxsizemask;
while(stored < count) { while(stored < count) {
for (j = 0; j < 2; j++) { for (j = 0; j < tables; j++) {
/* Pick a random point inside the hash table 0 or 1. */ if (i >= d->ht[j].size) continue; /* Out of range for this table. */
unsigned int i = random() & d->ht[j].sizemask; dictEntry *he = d->ht[j].table[i];
int size = d->ht[j].size; while (he) {
/* Collect all the elements of the buckets found non
/* Make sure to visit every bucket by iterating 'size' times. */ * empty while iterating. */
while(size--) { *des = he;
dictEntry *he = d->ht[j].table[i]; des++;
while (he) { he = he->next;
/* Collect all the elements of the buckets found non stored++;
* empty while iterating. */ if (stored == count) return stored;
*des = he;
des++;
he = he->next;
stored++;
if (stored == count) return stored;
}
i = (i+1) & d->ht[j].sizemask;
} }
/* If there is only one table and we iterated it all, we should
* already have 'count' elements. Assert this condition. */
assert(dictIsRehashing(d) != 0);
} }
i = (i+1) & maxsizemask;
} }
return stored; /* Never reached. */ return stored; /* Never reached. */
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment