summaryrefslogtreecommitdiff
path: root/src/dict.c
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2020-02-05 18:24:14 +0200
committerOran Agra <oran@redislabs.com>2020-02-06 11:48:12 +0200
commit28ef18a8946815e0d83a1c0a9b6baf9d27022461 (patch)
treed607923b20717b8e66229377c9d598079502aff3 /src/dict.c
parent44ac202fbfbca4210d016c9f77df987b27c1ae4c (diff)
downloadredis-28ef18a8946815e0d83a1c0a9b6baf9d27022461.tar.gz
RM_Scan disable dict rehashing
The callback approach we took is very efficient, the module can do any filtering of keys without building any list and cloning strings, it can also read data from the key's value. but if the user tries to re-open the key, or any other key, this can cause dict re-hashing (dictFind does that), and that's very bad to do from inside dictScan. this commit protects the dict from doing any rehashing during scan, but also warns the user not to attempt any writes or command calls from within the callback, for fear of unexpected side effects and crashes.
Diffstat (limited to 'src/dict.c')
-rw-r--r--src/dict.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/src/dict.c b/src/dict.c
index 106467ef7..93e6c39a7 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -871,6 +871,10 @@ unsigned long dictScan(dict *d,
if (dictSize(d) == 0) return 0;
+ /* Having a safe iterator means no rehashing can happen, see _dictRehashStep.
+ * This is needed in case the scan callback tries to do dictFind or alike. */
+ d->iterators++;
+
if (!dictIsRehashing(d)) {
t0 = &(d->ht[0]);
m0 = t0->sizemask;
@@ -937,6 +941,9 @@ unsigned long dictScan(dict *d,
} while (v & (m0 ^ m1));
}
+ /* undo the ++ at the top */
+ d->iterators--;
+
return v;
}