From d37299e3b737addf5a2f6cd1ea47afabdf98730c Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 29 Apr 2011 14:18:16 +0200 Subject: [PATCH 1/4] Fixed a bug with replication where SLAVEOF NO ONE caused a slave to close the connection with its slaves --- src/networking.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/networking.c b/src/networking.c index 32d071bd..29eed888 100644 --- a/src/networking.c +++ b/src/networking.c @@ -526,10 +526,16 @@ void freeClient(redisClient *c) { * close the connection with all our slaves if we have any, so * when we'll resync with the master the other slaves will sync again * with us as well. Note that also when the slave is not connected - * to the master it will keep refusing connections by other slaves. */ - while (listLength(server.slaves)) { - ln = listFirst(server.slaves); - freeClient((redisClient*)ln->value); + * to the master it will keep refusing connections by other slaves. + * + * We do this only if server.masterhost != NULL. If it is NULL this + * means the user called SLAVEOF NO ONE and we are freeing our + * link with the master, so no need to close link with slaves. */ + if (server.masterhost != NULL) { + while (listLength(server.slaves)) { + ln = listFirst(server.slaves); + freeClient((redisClient*)ln->value); + } } } /* Release memory */ From 1eb713a4c1e601bfc86963f7eab3fe36a0a65b17 Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 29 Apr 2011 14:31:18 +0200 Subject: [PATCH 2/4] CLUSTER KEYSLOT command --- src/cluster.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cluster.c b/src/cluster.c index b3548755..6c43bbf8 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -1205,6 +1205,10 @@ void clusterCommand(redisClient *c) { (unsigned long)sdslen(info))); addReplySds(c,info); addReply(c,shared.crlf); + } else if (!strcasecmp(c->argv[1]->ptr,"keyslot") && c->argc == 3) { + sds key = c->argv[2]->ptr; + + addReplyLongLong(c,keyHashSlot(key,sdslen(key))); } else { addReplyError(c,"Wrong CLUSTER subcommand or number of arguments"); } From 484354ff95e6e1b93552ef9576422709a1c739c2 Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 29 Apr 2011 16:17:58 +0200 Subject: [PATCH 3/4] CLUSTER GETKEYSINSLOT implemented --- src/cluster.c | 21 +++++++++++++++++++++ src/db.c | 10 +++++++--- src/redis.h | 1 + 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/cluster.c b/src/cluster.c index 6c43bbf8..5b747264 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -1209,6 +1209,27 @@ void clusterCommand(redisClient *c) { sds key = c->argv[2]->ptr; addReplyLongLong(c,keyHashSlot(key,sdslen(key))); + } else if (!strcasecmp(c->argv[1]->ptr,"getkeysinslot") && c->argc == 4) { + long long maxkeys, slot; + unsigned int numkeys; + int j; + robj **keys; + + if (getLongLongFromObjectOrReply(c,c->argv[2],&slot,NULL) != REDIS_OK) + return; + if (getLongLongFromObjectOrReply(c,c->argv[3],&maxkeys,NULL) != REDIS_OK) + return; + if (slot < 0 || slot >= REDIS_CLUSTER_SLOTS || maxkeys < 0 || + maxkeys > 1024*1024) { + addReplyError(c,"Invalid slot or number of keys"); + return; + } + + keys = zmalloc(sizeof(robj*)*maxkeys); + numkeys = GetKeysInSlot(slot, keys, maxkeys); + addReplyMultiBulkLen(c,numkeys); + for (j = 0; j < numkeys; j++) addReplyBulk(c,keys[j]); + zfree(keys); } else { addReplyError(c,"Wrong CLUSTER subcommand or number of arguments"); } diff --git a/src/db.c b/src/db.c index 7d323924..670e2bce 100644 --- a/src/db.c +++ b/src/db.c @@ -725,14 +725,18 @@ void SlotToKeyDel(robj *key) { zslDelete(server.cluster.slots_to_keys,hashslot,key); } -robj *GetKeyInSlot(unsigned int hashslot) { +unsigned int GetKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) { zskiplistNode *n; zrangespec range; + int j = 0; range.min = range.max = hashslot; range.minex = range.maxex = 0; n = zslFirstInRange(server.cluster.slots_to_keys, range); - if (!n) return NULL; - return n->obj; + while(n && n->score == hashslot && count--) { + keys[j++] = n->obj; + n = n->level[0].forward; + } + return j; } diff --git a/src/redis.h b/src/redis.h index 0baa7d81..b6955805 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1065,6 +1065,7 @@ long long emptyDb(); int selectDb(redisClient *c, int id); void signalModifiedKey(redisDb *db, robj *key); void signalFlushedDb(int dbid); +unsigned int GetKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count); /* API to get key arguments from commands */ #define REDIS_GETKEYS_ALL 0 From 2f52dac9effe41f79e502c2c8fb78181c874a704 Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 29 Apr 2011 17:34:03 +0200 Subject: [PATCH 4/4] CLUSTER subcommands to set slots in migrating or importing state. Still a work in progress... --- src/cluster.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/cluster.c b/src/cluster.c index 5b747264..b2af3761 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -1168,6 +1168,44 @@ void clusterCommand(redisClient *c) { clusterUpdateState(); clusterSaveConfigOrDie(); addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"setslot") && c->argc >= 4) { + /* SETSLOT 10 MIGRATING */ + /* SETSLOT 10 IMPORTING */ + /* SETSLOT 10 STABLE */ + long long aux; + unsigned int slot; + clusterNode *n; + + if (getLongLongFromObjectOrReply(c,c->argv[2],&aux,NULL) != REDIS_OK) + return; + if (aux < 0 || aux >= REDIS_CLUSTER_SLOTS) { + addReplyError(c,"Slot out of range"); + return; + } + slot = (unsigned int) aux; + if (server.cluster.slots[slot] != server.cluster.myself) { + addReplyErrorFormat(c,"I'm not the owner of hash slot %u",slot); + return; + } + if (!strcasecmp(c->argv[3]->ptr,"migrating") && c->argc == 5) { + if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) { + addReplyErrorFormat(c,"I don't know about node %s", + (char*)c->argv[4]->ptr); + return; + } + server.cluster.migrating_slots_to[slot] = n; + } else if (!strcasecmp(c->argv[3]->ptr,"importing") && c->argc == 5) { + if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) { + addReplyErrorFormat(c,"I don't know about node %s", + (char*)c->argv[3]->ptr); + return; + } + server.cluster.importing_slots_from[slot] = n; + } else if (!strcasecmp(c->argv[3]->ptr,"stable") && c->argc == 4) { + server.cluster.importing_slots_from[slot] = NULL; + } else { + addReplyError(c,"Invalid CLUSTER SETSLOT action or number of arguments"); + } } else if (!strcasecmp(c->argv[1]->ptr,"info") && c->argc == 2) { char *statestr[] = {"ok","fail","needhelp"}; int slots_assigned = 0, slots_ok = 0, slots_pfail = 0, slots_fail = 0; @@ -1211,8 +1249,7 @@ void clusterCommand(redisClient *c) { addReplyLongLong(c,keyHashSlot(key,sdslen(key))); } else if (!strcasecmp(c->argv[1]->ptr,"getkeysinslot") && c->argc == 4) { long long maxkeys, slot; - unsigned int numkeys; - int j; + unsigned int numkeys, j; robj **keys; if (getLongLongFromObjectOrReply(c,c->argv[2],&slot,NULL) != REDIS_OK)