From 7d0992dad65a01ff5a56e416956b23a1cd096d4f Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 17 Jun 2014 11:03:21 +0200 Subject: [PATCH] Sentinel: send SLAVEOF with MULTI, CLIENT KILL, CONFIG REWRITE. This implements the new Sentinel-Client protocol for the Sentinel part: now instances are reconfigured using a transaction that ensures that the config is rewritten in the target instance, and that clients lose the connection with the instance, in order to be forced to: ask Sentinel, reconnect to the instance, and verify the instance role with the new ROLE command. --- src/sentinel.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/sentinel.c b/src/sentinel.c index f4f3164c..7f81443b 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -3239,21 +3239,53 @@ int sentinelSendSlaveOf(sentinelRedisInstance *ri, char *host, int port) { ll2string(portstr,sizeof(portstr),port); + /* If host is NULL we send SLAVEOF NO ONE that will turn the instance + * into a master. */ if (host == NULL) { host = "NO"; memcpy(portstr,"ONE",4); } + /* In order to send SLAVEOF in a safe way, we send a transaction performing + * the following tasks: + * 1) Reconfigure the instance according to the specified host/port params. + * 2) Rewrite the configuraiton. + * 3) Disconnect all clients (but this one sending the commnad) in order + * to trigger the ask-master-on-reconnection protocol for connected + * clients. + * + * Note that we don't check the replies returned by commands, since we + * will observe instead the effects in the next INFO output. */ + retval = redisAsyncCommand(ri->cc, + sentinelDiscardReplyCallback, NULL, "MULTI"); + if (retval == REDIS_ERR) return retval; + ri->pending_commands++; + retval = redisAsyncCommand(ri->cc, sentinelDiscardReplyCallback, NULL, "SLAVEOF %s %s", host, portstr); if (retval == REDIS_ERR) return retval; + ri->pending_commands++; + retval = redisAsyncCommand(ri->cc, + sentinelDiscardReplyCallback, NULL, "CONFIG REWRITE"); + if (retval == REDIS_ERR) return retval; ri->pending_commands++; - if (redisAsyncCommand(ri->cc, - sentinelDiscardReplyCallback, NULL, "CONFIG REWRITE") == REDIS_OK) - { - ri->pending_commands++; - } + + /* CLIENT KILL TYPE is only supported starting from Redis 2.8.12, + * however sending it to an instance not understanding this command is not + * an issue because CLIENT is variadic command, so Redis will not + * recognized as a syntax error, and the transaction will not fail (but + * only the unsupported command will fail). */ + retval = redisAsyncCommand(ri->cc, + sentinelDiscardReplyCallback, NULL, "CLIENT KILL TYPE normal"); + if (retval == REDIS_ERR) return retval; + ri->pending_commands++; + + retval = redisAsyncCommand(ri->cc, + sentinelDiscardReplyCallback, NULL, "EXEC"); + if (retval == REDIS_ERR) return retval; + ri->pending_commands++; + return REDIS_OK; } -- GitLab