From 4ebfc45528dea7a3b0e4bc2a8efd4238ea48347b Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 4 Nov 2010 19:59:21 +0100 Subject: [PATCH] config option to select if when replication link with master a slave should or not serve stale data --- redis.conf | 13 +++++++++++++ src/config.c | 14 ++++++++++++++ src/redis.c | 12 ++++++++++++ src/redis.h | 4 +++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/redis.conf b/redis.conf index 36f650ed..bb30dcae 100644 --- a/redis.conf +++ b/redis.conf @@ -110,6 +110,19 @@ dir ./ # # masterauth +# When a slave lost the connection with the master, or when the replication +# is still in progress, the slave can act in two different ways: +# +# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will +# still reply to client requests, possibly with out of data data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) if slave-serve-stale data is set to 'no' the slave will reply with +# an error "SYNC with master in progress" to all the kind of commands +# but to INFO and SLAVEOF. +# +slave-serve-stale-data yes + ################################## SECURITY ################################### # Require clients to issue AUTH before processing any other diff --git a/src/config.c b/src/config.c index 2b5063c8..772ac764 100644 --- a/src/config.c +++ b/src/config.c @@ -152,6 +152,10 @@ void loadServerConfig(char *filename) { server.replstate = REDIS_REPL_CONNECT; } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) { server.masterauth = zstrdup(argv[1]); + } else if (!strcasecmp(argv[0],"slave-serve-stale-data") && argc == 2) { + if ((server.repl_serve_stale_data = yesnotoi(argv[1])) == -1) { + err = "argument must be 'yes' or 'no'"; goto loaderr; + } } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) { if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; @@ -379,6 +383,11 @@ void configSetCommand(redisClient *c) { appendServerSaveParams(seconds, changes); } sdsfreesplitres(v,vlen); + } else if (!strcasecmp(c->argv[2]->ptr,"slave-serve-stale-data")) { + int yn = yesnotoi(o->ptr); + + if (yn == -1) goto badfmt; + server.repl_serve_stale_data = yn; } else { addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s", (char*)c->argv[2]->ptr); @@ -488,6 +497,11 @@ void configGetCommand(redisClient *c) { sdsfree(buf); matches++; } + if (stringmatch(pattern,"slave-serve-stale-data",0)) { + addReplyBulkCString(c,"slave-serve-stale-data"); + addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no"); + matches++; + } setDeferredMultiBulkLength(c,replylen,matches*2); } diff --git a/src/redis.c b/src/redis.c index 971dfeca..8519f46f 100644 --- a/src/redis.c +++ b/src/redis.c @@ -786,6 +786,7 @@ void initServerConfig() { server.masterport = 6379; server.master = NULL; server.replstate = REDIS_REPL_NONE; + server.repl_serve_stale_data = 1; /* Double constants initialization */ R_Zero = 0.0; @@ -994,6 +995,17 @@ int processCommand(redisClient *c) { return REDIS_OK; } + /* Only allow INFO and SLAVEOF when slave-serve-stale-data is no and + * we are a slave with a broken link with master. */ + if (server.masterhost && server.replstate != REDIS_REPL_CONNECTED && + server.repl_serve_stale_data == 0 && + cmd->proc != infoCommand && cmd->proc != slaveofCommand) + { + addReplyError(c, + "link with MASTER is down and slave-serve-stale-data is set to no"); + return REDIS_OK; + } + /* Exec the command */ if (c->flags & REDIS_MULTI && cmd->proc != execCommand && cmd->proc != discardCommand && diff --git a/src/redis.h b/src/redis.h index d26e3c79..043825af 100644 --- a/src/redis.h +++ b/src/redis.h @@ -361,7 +361,8 @@ struct redisServer { long long dirty_before_bgsave; /* used to restore dirty on failed BGSAVE */ list *clients; dict *commands; /* Command table hahs table */ - struct redisCommand *delCommand, *multiCommand; /* often lookedup cmds */ + /* Fast pointers to often looked up command */ + struct redisCommand *delCommand, *multiCommand; list *slaves, *monitors; char neterr[ANET_ERR_LEN]; aeEventLoop *el; @@ -413,6 +414,7 @@ struct redisServer { int repl_transfer_fd; /* slave -> master SYNC temp file descriptor */ char *repl_transfer_tmpfile; /* slave-> master SYNC temp file name */ time_t repl_transfer_lastio; /* unix time of the latest read, for timeout */ + int repl_serve_stale_data; /* Serve stale data when link is down? */ /* Limits */ unsigned int maxclients; unsigned long long maxmemory; -- 2.45.2