From 7fb14b73ba67c70eb6c8a728c892c8d5b3fe954e Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 27 Mar 2014 14:54:57 +0100 Subject: [PATCH] Cluster: save/restore vars that must persist after recovery. This fixes issue #1479. --- src/cluster.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/cluster.c b/src/cluster.c index 42ed6098..5370e5ec 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -121,6 +121,25 @@ int clusterLoadConfig(char *filename) { argv = sdssplitargs(line,&argc); if (argv == NULL) goto fmterr; + /* Handle the special "vars" line. Don't pretend it is the last + * line even if it actually is when generated by Redis. */ + if (strcasecmp(argv[0],"vars") == 0) { + for (j = 1; j < argc; j += 2) { + if (strcasecmp(argv[j],"currentEpoch") == 0) { + server.cluster->currentEpoch = + strtoull(argv[j+1],NULL,10); + } else if (strcasecmp(argv[j],"last_vote_epoch") == 0) { + server.cluster->last_vote_epoch = + strtoull(argv[j+1],NULL,10); + } else { + redisLog(REDIS_WARNING, + "Skipping unknown cluster config variable '%s'", + argv[j]); + } + } + continue; + } + /* Create this node if it does not exist */ n = clusterLookupNode(argv[0]); if (!n) { @@ -227,10 +246,13 @@ int clusterLoadConfig(char *filename) { /* Config sanity check */ redisAssert(server.cluster->myself != NULL); redisLog(REDIS_NOTICE,"Node configuration loaded, I'm %.40s", myself->name); - /* Set the currentEpoch to the max epoch found in the master. - * FIXME: this should actually be part of the persistent state, as - * documented in the Github issue #1479. */ - server.cluster->currentEpoch = clusterGetMaxEpoch(); + + /* Something that should never happen: currentEpoch smaller than + * the max epoch found in the nodes configuration. However we handle this + * as some form of protection against manual editing of critical files. */ + if (clusterGetMaxEpoch() > server.cluster->currentEpoch) { + server.cluster->currentEpoch = clusterGetMaxEpoch(); + } return REDIS_OK; fmterr: @@ -253,10 +275,18 @@ fmterr: * bigger we pad our payload with newlines that are anyway ignored and truncate * the file afterward. */ int clusterSaveConfig(int do_fsync) { - sds ci = clusterGenNodesDescription(REDIS_NODE_HANDSHAKE); - size_t content_size = sdslen(ci); + sds ci; + size_t content_size; struct stat sb; int fd; + + /* Get the nodes description and concatenate our "vars" directive to + * save currentEpoch and last_vote_epoch. */ + ci = clusterGenNodesDescription(REDIS_NODE_HANDSHAKE); + ci = sdscatprintf(ci,"vars currentEpoch %llu last_vote_epoch %llu\n", + (unsigned long long) server.cluster->currentEpoch, + (unsigned long long) server.cluster->last_vote_epoch); + content_size = sdslen(ci); if ((fd = open(server.cluster_configfile,O_WRONLY|O_CREAT,0644)) == -1) goto err;