diff options
-rw-r--r-- | src/config.c | 4 | ||||
-rw-r--r-- | src/networking.c | 5 | ||||
-rw-r--r-- | src/redis.c | 1 | ||||
-rw-r--r-- | src/redis.h | 3 | ||||
-rw-r--r-- | src/replication.c | 54 |
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; |