]> git.saurik.com Git - redis.git/commitdiff
WATCH is now able to detect keys removed by FLUSHALL and FLUSHDB
authorantirez <antirez@gmail.com>
Tue, 25 May 2010 17:30:24 +0000 (19:30 +0200)
committerantirez <antirez@gmail.com>
Tue, 25 May 2010 17:30:24 +0000 (19:30 +0200)
redis.c
tests/support/test.tcl
tests/unit/cas.tcl

diff --git a/redis.c b/redis.c
index 08fcd978c4ee297a864377de3dd7f8d52554586b..40a32282d80725f156941ed8cc9cc2cce908c5b8 100644 (file)
--- a/redis.c
+++ b/redis.c
@@ -637,6 +637,7 @@ static int rewriteAppendOnlyFileBackground(void);
 static int vmSwapObjectBlocking(robj *key, robj *val);
 static int prepareForShutdown();
 static void touchWatchedKey(redisDb *db, robj *key);
+static void touchWatchedKeysOnFlush(int dbid);
 static void unwatchAllKeys(redisClient *c);
 
 static void authCommand(redisClient *c);
@@ -6780,12 +6781,14 @@ static void convertToRealHash(robj *o) {
 
 static void flushdbCommand(redisClient *c) {
     server.dirty += dictSize(c->db->dict);
+    touchWatchedKeysOnFlush(c->db->id);
     dictEmpty(c->db->dict);
     dictEmpty(c->db->expires);
     addReply(c,shared.ok);
 }
 
 static void flushallCommand(redisClient *c) {
+    touchWatchedKeysOnFlush(-1);
     server.dirty += emptyDb();
     addReply(c,shared.ok);
     if (server.bgsavechildpid != -1) {
@@ -10475,6 +10478,33 @@ static void touchWatchedKey(redisDb *db, robj *key) {
     }
 }
 
+/* On FLUSHDB or FLUSHALL all the watched keys that are present before the
+ * flush but will be deleted as effect of the flushing operation should
+ * be touched. "dbid" is the DB that's getting the flush. -1 if it is
+ * a FLUSHALL operation (all the DBs flushed). */
+static void touchWatchedKeysOnFlush(int dbid) {
+    listIter li1, li2;
+    listNode *ln;
+
+    /* For every client, check all the waited keys */
+    listRewind(server.clients,&li1);
+    while((ln = listNext(&li1))) {
+        redisClient *c = listNodeValue(ln);
+        listRewind(c->watched_keys,&li2);
+        while((ln = listNext(&li2))) {
+            watchedKey *wk = listNodeValue(ln);
+
+            /* For every watched key matching the specified DB, if the
+             * key exists, mark the client as dirty, as the key will be
+             * removed. */
+            if (dbid == -1 || wk->db->id == dbid) {
+                if (dictFind(wk->db->dict, wk->key) != NULL)
+                    c->flags |= REDIS_DIRTY_CAS;
+            }
+        }
+    }
+}
+
 static void watchCommand(redisClient *c) {
     int j;
 
index 83985e3e1e5aa71b6e22dd318ac2ee25aef5506f..6d5634ea0da09d6ebdf9666b0a82913e326ec51b 100644 (file)
@@ -15,6 +15,7 @@ proc test {name code okpattern} {
                 puts $warnings
             }
         }
+        puts "Script died with $error"
         exit 1
     }
     if {$okpattern eq $retval || [string match $okpattern $retval]} {
index 5184391d7b300d0d266a0c6fe25f8a93ba28cbcd..b850679640aa51188e207f105e7f09de8cefcc37 100644 (file)
@@ -63,4 +63,52 @@ start_server default.conf {} {
     test {UNWATCH when there is nothing watched works as expected} {
         r unwatch
     } {OK}
+
+    test {FLUSHALL is able to touch the watched keys} {
+        r set x 30
+        r watch x
+        r flushall
+        r multi
+        r ping
+        r exec
+    } {}
+
+    test {FLUSHALL does not touch non affected keys} {
+        r del x
+        r watch x
+        r flushall
+        r multi
+        r ping
+        r exec
+    } {PONG}
+
+    test {FLUSHDB is able to touch the watched keys} {
+        r set x 30
+        r watch x
+        r flushdb
+        r multi
+        r ping
+        r exec
+    } {}
+
+    test {FLUSHDB does not touch non affected keys} {
+        r del x
+        r watch x
+        r flushdb
+        r multi
+        r ping
+        r exec
+    } {PONG}
+
+    test {WATCH is able to remember the DB a key belongs to} {
+        r select 5
+        r set x 30
+        r watch x
+        r select 1
+        r set x 10
+        r select 5
+        r multi
+        r ping
+        r exec
+    } {PONG}
 }