+ } else if (!strcasecmp(c->argv[1]->ptr,"setslot") && c->argc >= 4) {
+ /* SETSLOT 10 MIGRATING <node ID> */
+ /* SETSLOT 10 IMPORTING <node ID> */
+ /* SETSLOT 10 STABLE */
+ /* SETSLOT 10 NODE <node ID> */
+ int slot;
+ clusterNode *n;
+
+ if ((slot = getSlotOrReply(c,c->argv[2])) == -1) return;
+
+ if (!strcasecmp(c->argv[3]->ptr,"migrating") && c->argc == 5) {
+ if (server.cluster.slots[slot] != server.cluster.myself) {
+ addReplyErrorFormat(c,"I'm not the owner of hash slot %u",slot);
+ return;
+ }
+ 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 (server.cluster.slots[slot] == server.cluster.myself) {
+ addReplyErrorFormat(c,
+ "I'm already the owner of hash slot %u",slot);
+ return;
+ }
+ 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) {
+ /* CLUSTER SETSLOT <SLOT> STABLE */
+ server.cluster.importing_slots_from[slot] = NULL;
+ server.cluster.migrating_slots_to[slot] = NULL;
+ } else if (!strcasecmp(c->argv[3]->ptr,"node") && c->argc == 5) {
+ /* CLUSTER SETSLOT <SLOT> NODE <NODE ID> */
+ clusterNode *n = clusterLookupNode(c->argv[4]->ptr);
+
+ if (!n) addReplyErrorFormat(c,"Unknown node %s",
+ (char*)c->argv[4]->ptr);
+ /* If this hash slot was served by 'myself' before to switch
+ * make sure there are no longer local keys for this hash slot. */
+ if (server.cluster.slots[slot] == server.cluster.myself &&
+ n != server.cluster.myself)
+ {
+ int numkeys;
+ robj **keys;
+
+ keys = zmalloc(sizeof(robj*)*1);
+ numkeys = GetKeysInSlot(slot, keys, 1);
+ zfree(keys);
+ if (numkeys != 0) {
+ addReplyErrorFormat(c, "Can't assign hashslot %d to a different node while I still hold keys for this hash slot.", slot);
+ return;
+ }
+ }
+ /* If this node was the slot owner and the slot was marked as
+ * migrating, assigning the slot to another node will clear
+ * the migratig status. */
+ if (server.cluster.slots[slot] == server.cluster.myself &&
+ server.cluster.migrating_slots_to[slot])
+ server.cluster.migrating_slots_to[slot] = NULL;
+
+ /* If this node was importing this slot, assigning the slot to
+ * itself also clears the importing status. */
+ if (n == server.cluster.myself && server.cluster.importing_slots_from[slot])
+ server.cluster.importing_slots_from[slot] = NULL;
+
+ clusterDelSlot(slot);
+ clusterAddSlot(n,slot);
+ } else {
+ addReplyError(c,"Invalid CLUSTER SETSLOT action or number of arguments");
+ return;
+ }
+ clusterSaveConfigOrDie();
+ addReply(c,shared.ok);