summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2015-02-04 11:25:52 +0100
committerantirez <antirez@gmail.com>2015-02-13 08:57:15 +0100
commitabbfbcf1614d661ce3c16183ac4f1f00459beb7b (patch)
treeecf8e9322f5776b5af84611a839f72262b53ff7d
parentb1de179c01d90378b1402526e42a7035d0bc72a0 (diff)
downloadredis-abbfbcf1614d661ce3c16183ac4f1f00459beb7b.tar.gz
Experimental no-sync replication mode.
-rw-r--r--src/config.c4
-rw-r--r--src/networking.c5
-rw-r--r--src/redis.c1
-rw-r--r--src/redis.h3
-rw-r--r--src/replication.c54
5 files changed, 64 insertions, 3 deletions
diff --git a/src/config.c b/src/config.c
index 3963a1218..88ac6c200 100644
--- a/src/config.c
+++ b/src/config.c
@@ -276,6 +276,10 @@ void loadServerConfigFromString(char *config) {
if ((server.repl_diskless_sync = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
+ } else if (!strcasecmp(argv[0],"repl-no-sync") && argc==2) {
+ if ((server.repl_no_sync = yesnotoi(argv[1])) == -1) {
+ err = "argument must be 'yes' or 'no'"; goto loaderr;
+ }
} else if (!strcasecmp(argv[0],"repl-diskless-sync-delay") && argc==2) {
server.repl_diskless_sync_delay = atoi(argv[1]);
if (server.repl_diskless_sync_delay < 0) {
diff --git a/src/networking.c b/src/networking.c
index 607d225fd..46a075a1e 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -673,7 +673,10 @@ void freeClient(redisClient *c) {
*
* Note that before doing this we make sure that the client is not in
* some unexpected state, by checking its flags. */
- if (server.master && c->flags & REDIS_MASTER) {
+ if (server.master &&
+ c->flags & REDIS_MASTER &&
+ server.repl_no_sync == 0)
+ {
redisLog(REDIS_WARNING,"Connection with master lost.");
if (!(c->flags & (REDIS_CLOSE_AFTER_REPLY|
REDIS_CLOSE_ASAP|
diff --git a/src/redis.c b/src/redis.c
index db3af61b0..aace528ff 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -1496,6 +1496,7 @@ void initServerConfig(void) {
server.repl_disable_tcp_nodelay = REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY;
server.repl_diskless_sync = REDIS_DEFAULT_REPL_DISKLESS_SYNC;
server.repl_diskless_sync_delay = REDIS_DEFAULT_REPL_DISKLESS_SYNC_DELAY;
+ server.repl_no_sync = REDIS_DEFAULT_REPL_NO_SYNC;
server.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY;
server.master_repl_offset = 0;
diff --git a/src/redis.h b/src/redis.h
index a675d4f12..d24501120 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -119,6 +119,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_DEFAULT_RDB_FILENAME "dump.rdb"
#define REDIS_DEFAULT_REPL_DISKLESS_SYNC 0
#define REDIS_DEFAULT_REPL_DISKLESS_SYNC_DELAY 5
+#define REDIS_DEFAULT_REPL_NO_SYNC 0
#define REDIS_DEFAULT_SLAVE_SERVE_STALE_DATA 1
#define REDIS_DEFAULT_SLAVE_READ_ONLY 1
#define REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY 0
@@ -258,6 +259,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_READONLY (1<<17) /* Cluster client is in read-only state. */
#define REDIS_PUBSUB (1<<18) /* Client is in Pub/Sub mode. */
#define REDIS_PREVENT_PROP (1<<19) /* Don't propagate to AOF / Slaves. */
+#define REDIS_SLAVE_NO_SYNC (1<<20) /* Result of: REPLCONF use-sync 0. */
/* Client block type (btype field in client structure)
* if REDIS_BLOCKED flag is set. */
@@ -853,6 +855,7 @@ struct redisServer {
int slave_priority; /* Reported in INFO and used by Sentinel. */
char repl_master_runid[REDIS_RUN_ID_SIZE+1]; /* Master run id for PSYNC. */
long long repl_master_initial_offset; /* Master PSYNC offset. */
+ int repl_no_sync; /* Streaming replication, no SYNC. */
/* Replication script cache. */
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */
diff --git a/src/replication.c b/src/replication.c
index 697acbef5..2eca16a98 100644
--- a/src/replication.c
+++ b/src/replication.c
@@ -480,6 +480,9 @@ void syncCommand(redisClient *c) {
return;
}
+ /* Accept the slave ASAP if it is running in no-sync mode. */
+ goto attach_slave;
+
redisLog(REDIS_NOTICE,"Slave %s asks for synchronization",
replicationGetSlaveName(c));
@@ -571,6 +574,8 @@ void syncCommand(redisClient *c) {
}
}
+attach_slave:
+
if (server.repl_disable_tcp_nodelay)
anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */
c->repldbfd = -1;
@@ -579,6 +584,18 @@ void syncCommand(redisClient *c) {
listAddNodeTail(server.slaves,c);
if (listLength(server.slaves) == 1 && server.repl_backlog == NULL)
createReplicationBacklog();
+
+ /* Put the slave fully online right now if it is a no-sync one. */
+ if (c->flags & REDIS_SLAVE_NO_SYNC) {
+ char buf[128];
+ int buflen;
+
+ /* Inform the slave with +NOTNEEDED that the request was accepted. */
+ buflen = snprintf(buf,sizeof(buf),"+NOTNEEDED\r\n");
+ if (write(c->fd,buf,buflen) != buflen) freeClientAsync(c);
+ aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
+ putSlaveOnline(c);
+ }
return;
}
@@ -613,6 +630,18 @@ void replconfCommand(redisClient *c) {
&port,NULL) != REDIS_OK))
return;
c->slave_listening_port = port;
+ } else if (!strcasecmp(c->argv[j]->ptr,"use-sync")) {
+ /* REPLCONF USE-SYNC is used in order for the slave to request
+ * synchronization-less replication, the master will just send
+ * new data without trying to synchronize the slave. */
+ long long val;
+
+ if ((getLongLongFromObject(c->argv[j+1], &val) != REDIS_OK))
+ return;
+ if (val)
+ c->flags &= ~REDIS_SLAVE_NO_SYNC;
+ else
+ c->flags |= REDIS_SLAVE_NO_SYNC;
} else if (!strcasecmp(c->argv[j]->ptr,"ack")) {
/* REPLCONF ACK is used by slave to inform the master the amount
* of replication stream that it processed so far. It is an
@@ -1140,7 +1169,7 @@ int slaveTryPartialResynchronization(int fd) {
* client structure representing the master into server.master. */
server.repl_master_initial_offset = -1;
- if (server.cached_master) {
+ if (server.cached_master && server.repl_no_sync == 0) {
psync_runid = server.cached_master->replrunid;
snprintf(psync_offset,sizeof(psync_offset),"%lld", server.cached_master->reploff+1);
redisLog(REDIS_NOTICE,"Trying a partial resynchronization (request %s:%s).", psync_runid, psync_offset);
@@ -1186,6 +1215,14 @@ int slaveTryPartialResynchronization(int fd) {
return PSYNC_FULLRESYNC;
}
+ if (!strncmp(reply,"+NOTNEEDED",10)) {
+ /* No-sync replication. */
+ redisLog(REDIS_NOTICE, "No-sync slave accepted without SYNC phase.");
+ sdsfree(reply);
+ replicationCreateMasterClient(fd);
+ return PSYNC_CONTINUE;
+ }
+
if (!strncmp(reply,"+CONTINUE",9)) {
/* Partial resync was accepted, set the replication state accordingly */
redisLog(REDIS_NOTICE,
@@ -1292,7 +1329,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
}
/* AUTH with the master if required. */
- if(server.masterauth) {
+ if (server.masterauth) {
err = sendSynchronousCommand(fd,"AUTH",server.masterauth,NULL);
if (err[0] == '-') {
redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",err);
@@ -1302,6 +1339,18 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
sdsfree(err);
}
+ /* Inform the master we don't want to synchronize if we are using
+ * repl-no-sync mode. */
+ if (server.repl_no_sync) {
+ err = sendSynchronousCommand(fd,"REPLCONF","use-sync","0",NULL);
+ if (err[0] == '-') {
+ redisLog(REDIS_WARNING,"Unable to enable no-sync mode: %s",err);
+ sdsfree(err);
+ goto error;
+ }
+ sdsfree(err);
+ }
+
/* Set the slave port, so that Master's INFO command can list the
* slave listening port correctly. */
{
@@ -1698,6 +1747,7 @@ void refreshGoodSlavesCount(void) {
time_t lag = server.unixtime - slave->repl_ack_time;
if (slave->replstate == REDIS_REPL_ONLINE &&
+ !(slave->flags & REDIS_SLAVE_NO_SYNC) &&
lag <= server.repl_min_slaves_max_lag) good++;
}
server.repl_good_slaves_count = good;