From 9b30e1a207c3ce25e942c58e2e42021b452cfa3f Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 25 May 2010 19:30:24 +0200 Subject: [PATCH] WATCH is now able to detect keys removed by FLUSHALL and FLUSHDB --- redis.c | 30 ++++++++++++++++++++++++++ tests/support/test.tcl | 1 + tests/unit/cas.tcl | 48 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/redis.c b/redis.c index 08fcd978..40a32282 100644 --- 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; diff --git a/tests/support/test.tcl b/tests/support/test.tcl index 83985e3e..6d5634ea 100644 --- a/tests/support/test.tcl +++ b/tests/support/test.tcl @@ -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]} { diff --git a/tests/unit/cas.tcl b/tests/unit/cas.tcl index 5184391d..b8506796 100644 --- a/tests/unit/cas.tcl +++ b/tests/unit/cas.tcl @@ -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} } -- 2.47.2