From 8520066d7b4782adaf9caa56036071ddb3de86fc Mon Sep 17 00:00:00 2001 From: Harmen Date: Mon, 30 Apr 2012 09:57:12 -0600 Subject: [PATCH 1/2] Show problem with 'keys' command with specific command sequence. --- tests/unit/expire.tcl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/expire.tcl b/tests/unit/expire.tcl index 82876ddd..56a59f76 100644 --- a/tests/unit/expire.tcl +++ b/tests/unit/expire.tcl @@ -141,4 +141,15 @@ start_server {tags {"expire"}} { set size2 [r dbsize] list $size1 $size2 } {3 0} + + test {5 keys in, 5 keys out} { + r flushdb + r set a c + r expire a 5 + r set t c + r set e c + r set s c + r set foo b + lsort [r keys *] + } {a e foo s t} } From 9311d2b527b0bb3e72e61b143718e6def51491e6 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 30 Apr 2012 10:16:20 -0700 Subject: [PATCH 2/2] Use safe dictionary iterator from KEYS Every matched key in a KEYS call is checked for expiration. When the key is set to expire, the call to `getExpire` will assert that the key also exists in the main dictionary. This in turn causes a rehashing step to be executed. Rehashing a dictionary when there is an iterator active may result in the iterator emitting duplicate entries, or not emitting some entries at all. By using a safe iterator, the rehash step is omitted. --- src/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db.c b/src/db.c index 3c75f6ba..e65106a5 100644 --- a/src/db.c +++ b/src/db.c @@ -255,7 +255,7 @@ void keysCommand(redisClient *c) { unsigned long numkeys = 0; void *replylen = addDeferredMultiBulkLength(c); - di = dictGetIterator(c->db->dict); + di = dictGetSafeIterator(c->db->dict); allkeys = (pattern[0] == '*' && pattern[1] == '\0'); while((de = dictNext(di)) != NULL) { sds key = dictGetKey(de);