summaryrefslogtreecommitdiff
path: root/src/t_list.c
diff options
context:
space:
mode:
authorMatt Stancliff <matt@genges.com>2014-04-07 21:22:30 -0400
committerMatt Stancliff <matt@genges.com>2014-05-21 09:52:52 -0400
commit33f943b4cddb0bf90b436ccd47d12363e13d0fce (patch)
tree23f56948ff849258a9e4e634d56b1f7be606660c /src/t_list.c
parent56161ca0a444ff6653f884561ab95bd09ecbc1af (diff)
downloadredis-33f943b4cddb0bf90b436ccd47d12363e13d0fce.tar.gz
Fix blocking operations from missing new lists
Behrad Zari discovered [1] and Josiah reported [2]: if you block and wait for a list to exist, but the list creates from a non-push command, the blocked client never gets notified. This commit adds notification of blocked clients into the DB layer and away from individual commands. Lists can be created by [LR]PUSH, SORT..STORE, RENAME, MOVE, and RESTORE. Previously, blocked client notifications were only triggered by [LR]PUSH. Your client would never get notified if a list were created by SORT..STORE or RENAME or a RESTORE, etc. Blocked client notification now happens in one unified place: - dbAdd() triggers notification when adding a list to the DB Two new tests are added that fail prior to this commit. All test pass. Fixes #1668 [1]: https://groups.google.com/forum/#!topic/redis-db/k4oWfMkN1NU [2]: #1668
Diffstat (limited to 'src/t_list.c')
-rw-r--r--src/t_list.c16
1 files changed, 5 insertions, 11 deletions
diff --git a/src/t_list.c b/src/t_list.c
index 70f5cf164..d03879bdd 100644
--- a/src/t_list.c
+++ b/src/t_list.c
@@ -29,8 +29,6 @@
#include "redis.h"
-void signalListAsReady(redisClient *c, robj *key);
-
/*-----------------------------------------------------------------------------
* List API
*----------------------------------------------------------------------------*/
@@ -297,15 +295,12 @@ void listTypeConvert(robj *subject, int enc) {
void pushGenericCommand(redisClient *c, int where) {
int j, waiting = 0, pushed = 0;
robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
- int may_have_waiting_clients = (lobj == NULL);
if (lobj && lobj->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
return;
}
- if (may_have_waiting_clients) signalListAsReady(c,c->argv[1]);
-
for (j = 2; j < c->argc; j++) {
c->argv[j] = tryObjectEncoding(c->argv[j]);
if (!lobj) {
@@ -709,7 +704,6 @@ void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value
if (!dstobj) {
dstobj = createZiplistObject();
dbAdd(c->db,dstkey,dstobj);
- signalListAsReady(c,dstkey);
}
signalModifiedKey(c->db,dstkey);
listTypePush(dstobj,value,REDIS_HEAD);
@@ -849,19 +843,19 @@ void unblockClientWaitingData(redisClient *c) {
* made by a script or in the context of MULTI/EXEC.
*
* The list will be finally processed by handleClientsBlockedOnLists() */
-void signalListAsReady(redisClient *c, robj *key) {
+void signalListAsReady(redisDb *db, robj *key) {
readyList *rl;
/* No clients blocking for this key? No need to queue it. */
- if (dictFind(c->db->blocking_keys,key) == NULL) return;
+ if (dictFind(db->blocking_keys,key) == NULL) return;
/* Key was already signaled? No need to queue it again. */
- if (dictFind(c->db->ready_keys,key) != NULL) return;
+ if (dictFind(db->ready_keys,key) != NULL) return;
/* Ok, we need to queue this key into server.ready_keys. */
rl = zmalloc(sizeof(*rl));
rl->key = key;
- rl->db = c->db;
+ rl->db = db;
incrRefCount(key);
listAddNodeTail(server.ready_keys,rl);
@@ -869,7 +863,7 @@ void signalListAsReady(redisClient *c, robj *key) {
* to avoid adding it multiple times into a list with a simple O(1)
* check. */
incrRefCount(key);
- redisAssert(dictAdd(c->db->ready_keys,key,NULL) == DICT_OK);
+ redisAssert(dictAdd(db->ready_keys,key,NULL) == DICT_OK);
}
/* This is a helper function for handleClientsBlockedOnLists(). It's work