From 5d73073f6eaa391fe01ce202d1de95c27da5ec0b Mon Sep 17 00:00:00 2001 From: antirez Date: Sun, 22 Jul 2012 17:13:49 +0200 Subject: [PATCH] Allow Pub/Sub in contexts where other commands are blocked. Redis loading data from disk, and a Redis slave disconnected from its master with serve-stale-data disabled, are two conditions where commands are normally refused by Redis, returning an error. However there is no reason to disable Pub/Sub commands as well, given that this layer does not interact with the dataset. To allow Pub/Sub in as many contexts as possible is especially interesting now that Redis Sentinel uses Pub/Sub of a Redis master as a communication channel between Sentinels. This commit allows Pub/Sub to be used in the above two contexts where it was previously denied. --- src/redis.c | 31 +++++++++++++++++++------------ src/redis.h | 2 ++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/redis.c b/src/redis.c index fa0603cb3..b6490d57a 100644 --- a/src/redis.c +++ b/src/redis.c @@ -106,6 +106,10 @@ struct redisCommand *commandTable; * results. For instance SPOP and RANDOMKEY are two random commands. * S: Sort command output array if called from script, so that the output * is deterministic. + * l: Allow command while loading the database. + * t: Allow command while a slave has stale data but is not allowed to + * server this data. Normally no command is accepted in this condition + * but just a few. */ struct redisCommand redisCommandTable[] = { {"get",getCommand,2,"r",0,NULL,1,1,1,0,0}, @@ -219,19 +223,19 @@ struct redisCommand redisCommandTable[] = { {"flushdb",flushdbCommand,1,"w",0,NULL,0,0,0,0,0}, {"flushall",flushallCommand,1,"w",0,NULL,0,0,0,0,0}, {"sort",sortCommand,-2,"wmS",0,NULL,1,1,1,0,0}, - {"info",infoCommand,-1,"r",0,NULL,0,0,0,0,0}, + {"info",infoCommand,-1,"rlt",0,NULL,0,0,0,0,0}, {"monitor",monitorCommand,1,"ars",0,NULL,0,0,0,0,0}, {"ttl",ttlCommand,2,"r",0,NULL,1,1,1,0,0}, {"pttl",pttlCommand,2,"r",0,NULL,1,1,1,0,0}, {"persist",persistCommand,2,"w",0,NULL,1,1,1,0,0}, - {"slaveof",slaveofCommand,3,"as",0,NULL,0,0,0,0,0}, + {"slaveof",slaveofCommand,3,"ast",0,NULL,0,0,0,0,0}, {"debug",debugCommand,-2,"as",0,NULL,0,0,0,0,0}, {"config",configCommand,-2,"ar",0,NULL,0,0,0,0,0}, - {"subscribe",subscribeCommand,-2,"rps",0,NULL,0,0,0,0,0}, - {"unsubscribe",unsubscribeCommand,-1,"rps",0,NULL,0,0,0,0,0}, - {"psubscribe",psubscribeCommand,-2,"rps",0,NULL,0,0,0,0,0}, - {"punsubscribe",punsubscribeCommand,-1,"rps",0,NULL,0,0,0,0,0}, - {"publish",publishCommand,3,"pf",0,NULL,0,0,0,0,0}, + {"subscribe",subscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0}, + {"unsubscribe",unsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0}, + {"psubscribe",psubscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0}, + {"punsubscribe",punsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0}, + {"publish",publishCommand,3,"pflt",0,NULL,0,0,0,0,0}, {"watch",watchCommand,-2,"rs",0,noPreloadGetKeys,1,-1,1,0,0}, {"unwatch",unwatchCommand,1,"rs",0,NULL,0,0,0,0,0}, {"cluster",clusterCommand,-2,"ar",0,NULL,0,0,0,0,0}, @@ -1381,6 +1385,8 @@ void populateCommandTable(void) { case 's': c->flags |= REDIS_CMD_NOSCRIPT; break; case 'R': c->flags |= REDIS_CMD_RANDOM; break; case 'S': c->flags |= REDIS_CMD_SORT_FOR_SCRIPT; break; + case 'l': c->flags |= REDIS_CMD_LOADING; break; + case 't': c->flags |= REDIS_CMD_STALE; break; default: redisPanic("Unsupported command flag"); break; } f++; @@ -1622,7 +1628,7 @@ int processCommand(redisClient *c) { return REDIS_OK; } - /* Don't accept wirte commands if this is a read only slave. But + /* Don't accept write commands if this is a read only slave. But * accept write commands if this is our master. */ if (server.masterhost && server.repl_slave_ro && !(c->flags & REDIS_MASTER) && @@ -1647,19 +1653,20 @@ int processCommand(redisClient *c) { * we are a slave with a broken link with master. */ if (server.masterhost && server.repl_state != REDIS_REPL_CONNECTED && server.repl_serve_stale_data == 0 && - c->cmd->proc != infoCommand && c->cmd->proc != slaveofCommand) + !(c->cmd->flags & REDIS_CMD_STALE)) { addReply(c, shared.masterdownerr); return REDIS_OK; } - /* Loading DB? Return an error if the command is not INFO */ - if (server.loading && c->cmd->proc != infoCommand) { + /* Loading DB? Return an error if the command has not the + * REDIS_CMD_LOADING flag. */ + if (server.loading && !(c->cmd->flags & REDIS_CMD_LOADING)) { addReply(c, shared.loadingerr); return REDIS_OK; } - /* Lua script too slow? Only allow SHUTDOWN NOSAVE and SCRIPT KILL. */ + /* Lua script too slow? Only allow commands with REDIS_CMD_STALE flag. */ if (server.lua_timedout && !(c->cmd->proc == shutdownCommand && c->argc == 2 && diff --git a/src/redis.h b/src/redis.h index 9a9b511c0..33a676dc3 100644 --- a/src/redis.h +++ b/src/redis.h @@ -85,6 +85,8 @@ #define REDIS_CMD_NOSCRIPT 64 /* "s" flag */ #define REDIS_CMD_RANDOM 128 /* "R" flag */ #define REDIS_CMD_SORT_FOR_SCRIPT 256 /* "S" flag */ +#define REDIS_CMD_LOADING 512 /* "l" flag */ +#define REDIS_CMD_STALE 1024 /* "t" flag */ /* Object types */ #define REDIS_STRING 0 -- GitLab