diff --git a/src/cluster.c b/src/cluster.c index 66cfe4ff64da1886b7add599d54a428e97ebfcb0..6586a6ce0249c0d3c65702880457e21190d7a24d 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -3274,6 +3274,10 @@ socket_rd_err: return; } +/* ----------------------------------------------------------------------------- + * Cluster functions related to serving / redirecting clients + * -------------------------------------------------------------------------- */ + /* The ASKING command is required after a -ASK redirection. * The client should issue ASKING before to actually send the command to * the target instance. See the Redis Cluster specification for more @@ -3287,9 +3291,23 @@ void askingCommand(redisClient *c) { addReply(c,shared.ok); } -/* ----------------------------------------------------------------------------- - * Cluster functions related to serving / redirecting clients - * -------------------------------------------------------------------------- */ +/* The READONLY command is uesd by clients to enter the read-only mode. + * In this mode slaves will not redirect clients as long as clients access + * with read-only commands to keys that are served by the slave's master. */ +void readonlyCommand(redisClient *c) { + if (server.cluster_enabled == 0) { + addReplyError(c,"This instance has cluster support disabled"); + return; + } + c->flags |= REDIS_READONLY; + addReply(c,shared.ok); +} + +/* The READWRITE command just clears the READONLY command state. */ +void readwriteCommand(redisClient *c) { + c->flags &= ~REDIS_READONLY; + addReply(c,shared.ok); +} /* Return the pointer to the cluster node that is able to serve the command. * For the function to succeed the command should only target a single @@ -3385,6 +3403,16 @@ clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **arg (c->flags & REDIS_ASKING || cmd->flags & REDIS_CMD_ASKING)) { return server.cluster->myself; } + /* Handle the read-only client case reading from a slave: if this + * node is a slave and the request is about an hash slot our master + * is serving, we can reply without redirection. */ + if (c->flags & REDIS_READONLY && + cmd->flags & REDIS_CMD_READONLY && + server.cluster->myself->flags & REDIS_NODE_SLAVE && + server.cluster->myself->slaveof == n) + { + return server.cluster->myself; + } /* It's not a -ASK case. Base case: just return the right node. */ return n; } diff --git a/src/networking.c b/src/networking.c index ff3681f52f535cb47470938f972231ff55849da8..bf16559acbc46f1337d24fd3eac8bc568f0601ea 100644 --- a/src/networking.c +++ b/src/networking.c @@ -1263,6 +1263,7 @@ sds getClientInfoString(redisClient *client) { if (client->flags & REDIS_UNBLOCKED) *p++ = 'u'; if (client->flags & REDIS_CLOSE_ASAP) *p++ = 'A'; if (client->flags & REDIS_UNIX_SOCKET) *p++ = 'U'; + if (client->flags & REDIS_READONLY) *p++ = 'r'; if (p == flags) *p++ = 'N'; *p++ = '\0'; diff --git a/src/redis.c b/src/redis.c index e926e9c8db97c7f43506799e0d45d77814793c6a..ef07d9b25c21e9739a1dd6261065011cf4807a61 100644 --- a/src/redis.c +++ b/src/redis.c @@ -254,6 +254,8 @@ struct redisCommand redisCommandTable[] = { {"restore-asking",restoreCommand,-4,"awmk",0,NULL,1,1,1,0,0}, {"migrate",migrateCommand,-6,"aw",0,NULL,0,0,0,0,0}, {"asking",askingCommand,1,"r",0,NULL,0,0,0,0,0}, + {"readonly",readonlyCommand,1,"r",0,NULL,0,0,0,0,0}, + {"readwrite",readwriteCommand,1,"r",0,NULL,0,0,0,0,0}, {"dump",dumpCommand,2,"ar",0,NULL,1,1,1,0,0}, {"object",objectCommand,-2,"r",0,NULL,2,2,2,0,0}, {"client",clientCommand,-2,"ar",0,NULL,0,0,0,0,0}, diff --git a/src/redis.h b/src/redis.h index ace974ee1563e8f860d20ef815abd12209a4e52a..0a7bc0960f3b07c34e3f607276185d09fe7597d0 100644 --- a/src/redis.h +++ b/src/redis.h @@ -232,6 +232,7 @@ #define REDIS_FORCE_AOF (1<<14) /* Force AOF propagation of current cmd. */ #define REDIS_FORCE_REPL (1<<15) /* Force replication of current cmd. */ #define REDIS_PRE_PSYNC (1<<16) /* Instance don't understand PSYNC. */ +#define REDIS_READONLY (1<<17) /* Cluster client is in read-only state. */ /* Client block type (btype field in client structure) * if REDIS_BLOCKED flag is set. */ @@ -1397,6 +1398,8 @@ void clusterCommand(redisClient *c); void restoreCommand(redisClient *c); void migrateCommand(redisClient *c); void askingCommand(redisClient *c); +void readonlyCommand(redisClient *c); +void readwriteCommand(redisClient *c); void dumpCommand(redisClient *c); void objectCommand(redisClient *c); void clientCommand(redisClient *c);