diff --git a/src/cluster.c b/src/cluster.c index 362e03953..18ae0ab0b 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -4022,13 +4022,6 @@ void clusterCommand(client *c) { } clusterDelSlot(slot); clusterAddSlot(n,slot); - } else if (!strcasecmp(c->argv[3]->ptr,"bumpepoch") && c->argc == 2) { - /* CLUSTER BUMPEPOCH */ - int retval = clusterBumpConfigEpochWithoutConsensus(); - sds reply = sdscatprintf(sdsempty(),"%s %llu\r\n", - (retval == C_OK) ? "BUMPED" : "STILL", - (unsigned long long) myself->configEpoch); - addReplySds(c,reply); } else { addReplyError(c, "Invalid CLUSTER SETSLOT action or number of arguments"); @@ -4036,6 +4029,13 @@ void clusterCommand(client *c) { } clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|CLUSTER_TODO_UPDATE_STATE); addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"bumpepoch") && c->argc == 2) { + /* CLUSTER BUMPEPOCH */ + int retval = clusterBumpConfigEpochWithoutConsensus(); + sds reply = sdscatprintf(sdsempty(),"+%s %llu\r\n", + (retval == C_OK) ? "BUMPED" : "STILL", + (unsigned long long) myself->configEpoch); + addReplySds(c,reply); } else if (!strcasecmp(c->argv[1]->ptr,"info") && c->argc == 2) { /* CLUSTER INFO */ char *statestr[] = {"ok","fail","needhelp"}; diff --git a/src/redis-trib.rb b/src/redis-trib.rb index bacbd0d33..112916d7a 100755 --- a/src/redis-trib.rb +++ b/src/redis-trib.rb @@ -499,13 +499,15 @@ class RedisTrib end # Return the owner of the specified slot - def get_slot_owner(slot) + def get_slot_owners(slot) + owners = [] @nodes.each{|n| + next if n.has_flag?("slave") n.slots.each{|s,_| - return n if s == slot + owners << n if s == slot } } - nil + owners end # Return the node, among 'nodes' with the greatest number of keys @@ -532,7 +534,8 @@ class RedisTrib # Try to obtain the current slot owner, according to the current # nodes configuration. - owner = get_slot_owner(slot) + owners = get_slot_owners(slot) + owner = owners[0] if owners.length == 1 migrating = [] importing = [] @@ -585,9 +588,17 @@ class RedisTrib # Note that this case also covers multiple nodes having the slot # in migrating state, since migrating is a valid state only for # slot owners. - # - # TODO: Use CLUSTER BUMPEPOCH in order to make the - # winner able to claim the slot over all the other nodes. + if owners.length > 1 + owner = get_node_with_most_keys_in_slot(owners,slot) + owners.each{|n| + next if n == owner + n.r.cluster('delslots',slot) + n.r.cluster('setslot',slot,'importing',owner.info[:name]) + importing.delete(n) # Avoid duplciates + importing << n + } + owner.r.cluster('bumpepoch') + end # Case 1: The slot is in migrating state in one slot, and in # importing state in 1 slot. That's trivial to address.