Commit abbfbcf1 authored by antirez's avatar antirez
Browse files

Experimental no-sync replication mode.

parent b1de179c
...@@ -276,6 +276,10 @@ void loadServerConfigFromString(char *config) { ...@@ -276,6 +276,10 @@ void loadServerConfigFromString(char *config) {
if ((server.repl_diskless_sync = yesnotoi(argv[1])) == -1) { if ((server.repl_diskless_sync = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr; 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) { } else if (!strcasecmp(argv[0],"repl-diskless-sync-delay") && argc==2) {
server.repl_diskless_sync_delay = atoi(argv[1]); server.repl_diskless_sync_delay = atoi(argv[1]);
if (server.repl_diskless_sync_delay < 0) { if (server.repl_diskless_sync_delay < 0) {
......
...@@ -673,7 +673,10 @@ void freeClient(redisClient *c) { ...@@ -673,7 +673,10 @@ void freeClient(redisClient *c) {
* *
* Note that before doing this we make sure that the client is not in * Note that before doing this we make sure that the client is not in
* some unexpected state, by checking its flags. */ * 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."); redisLog(REDIS_WARNING,"Connection with master lost.");
if (!(c->flags & (REDIS_CLOSE_AFTER_REPLY| if (!(c->flags & (REDIS_CLOSE_AFTER_REPLY|
REDIS_CLOSE_ASAP| REDIS_CLOSE_ASAP|
......
...@@ -1496,6 +1496,7 @@ void initServerConfig(void) { ...@@ -1496,6 +1496,7 @@ void initServerConfig(void) {
server.repl_disable_tcp_nodelay = REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY; server.repl_disable_tcp_nodelay = REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY;
server.repl_diskless_sync = REDIS_DEFAULT_REPL_DISKLESS_SYNC; server.repl_diskless_sync = REDIS_DEFAULT_REPL_DISKLESS_SYNC;
server.repl_diskless_sync_delay = REDIS_DEFAULT_REPL_DISKLESS_SYNC_DELAY; 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.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY;
server.master_repl_offset = 0; server.master_repl_offset = 0;
......
...@@ -119,6 +119,7 @@ typedef long long mstime_t; /* millisecond time type. */ ...@@ -119,6 +119,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_DEFAULT_RDB_FILENAME "dump.rdb" #define REDIS_DEFAULT_RDB_FILENAME "dump.rdb"
#define REDIS_DEFAULT_REPL_DISKLESS_SYNC 0 #define REDIS_DEFAULT_REPL_DISKLESS_SYNC 0
#define REDIS_DEFAULT_REPL_DISKLESS_SYNC_DELAY 5 #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_SERVE_STALE_DATA 1
#define REDIS_DEFAULT_SLAVE_READ_ONLY 1 #define REDIS_DEFAULT_SLAVE_READ_ONLY 1
#define REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY 0 #define REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY 0
...@@ -258,6 +259,7 @@ typedef long long mstime_t; /* millisecond time type. */ ...@@ -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_READONLY (1<<17) /* Cluster client is in read-only state. */
#define REDIS_PUBSUB (1<<18) /* Client is in Pub/Sub mode. */ #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_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) /* Client block type (btype field in client structure)
* if REDIS_BLOCKED flag is set. */ * if REDIS_BLOCKED flag is set. */
...@@ -853,6 +855,7 @@ struct redisServer { ...@@ -853,6 +855,7 @@ struct redisServer {
int slave_priority; /* Reported in INFO and used by Sentinel. */ int slave_priority; /* Reported in INFO and used by Sentinel. */
char repl_master_runid[REDIS_RUN_ID_SIZE+1]; /* Master run id for PSYNC. */ char repl_master_runid[REDIS_RUN_ID_SIZE+1]; /* Master run id for PSYNC. */
long long repl_master_initial_offset; /* Master PSYNC offset. */ long long repl_master_initial_offset; /* Master PSYNC offset. */
int repl_no_sync; /* Streaming replication, no SYNC. */
/* Replication script cache. */ /* Replication script cache. */
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */ dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */ list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */
......
...@@ -480,6 +480,9 @@ void syncCommand(redisClient *c) { ...@@ -480,6 +480,9 @@ void syncCommand(redisClient *c) {
return; return;
} }
/* Accept the slave ASAP if it is running in no-sync mode. */
goto attach_slave;
redisLog(REDIS_NOTICE,"Slave %s asks for synchronization", redisLog(REDIS_NOTICE,"Slave %s asks for synchronization",
replicationGetSlaveName(c)); replicationGetSlaveName(c));
...@@ -571,6 +574,8 @@ void syncCommand(redisClient *c) { ...@@ -571,6 +574,8 @@ void syncCommand(redisClient *c) {
} }
} }
attach_slave:
if (server.repl_disable_tcp_nodelay) if (server.repl_disable_tcp_nodelay)
anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */ anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */
c->repldbfd = -1; c->repldbfd = -1;
...@@ -579,6 +584,18 @@ void syncCommand(redisClient *c) { ...@@ -579,6 +584,18 @@ void syncCommand(redisClient *c) {
listAddNodeTail(server.slaves,c); listAddNodeTail(server.slaves,c);
if (listLength(server.slaves) == 1 && server.repl_backlog == NULL) if (listLength(server.slaves) == 1 && server.repl_backlog == NULL)
createReplicationBacklog(); 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; return;
} }
...@@ -613,6 +630,18 @@ void replconfCommand(redisClient *c) { ...@@ -613,6 +630,18 @@ void replconfCommand(redisClient *c) {
&port,NULL) != REDIS_OK)) &port,NULL) != REDIS_OK))
return; return;
c->slave_listening_port = port; 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")) { } else if (!strcasecmp(c->argv[j]->ptr,"ack")) {
/* REPLCONF ACK is used by slave to inform the master the amount /* REPLCONF ACK is used by slave to inform the master the amount
* of replication stream that it processed so far. It is an * of replication stream that it processed so far. It is an
...@@ -1140,7 +1169,7 @@ int slaveTryPartialResynchronization(int fd) { ...@@ -1140,7 +1169,7 @@ int slaveTryPartialResynchronization(int fd) {
* client structure representing the master into server.master. */ * client structure representing the master into server.master. */
server.repl_master_initial_offset = -1; 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; psync_runid = server.cached_master->replrunid;
snprintf(psync_offset,sizeof(psync_offset),"%lld", server.cached_master->reploff+1); 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); redisLog(REDIS_NOTICE,"Trying a partial resynchronization (request %s:%s).", psync_runid, psync_offset);
...@@ -1186,6 +1215,14 @@ int slaveTryPartialResynchronization(int fd) { ...@@ -1186,6 +1215,14 @@ int slaveTryPartialResynchronization(int fd) {
return PSYNC_FULLRESYNC; 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)) { if (!strncmp(reply,"+CONTINUE",9)) {
/* Partial resync was accepted, set the replication state accordingly */ /* Partial resync was accepted, set the replication state accordingly */
redisLog(REDIS_NOTICE, redisLog(REDIS_NOTICE,
...@@ -1292,7 +1329,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) { ...@@ -1292,7 +1329,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
} }
/* AUTH with the master if required. */ /* AUTH with the master if required. */
if(server.masterauth) { if (server.masterauth) {
err = sendSynchronousCommand(fd,"AUTH",server.masterauth,NULL); err = sendSynchronousCommand(fd,"AUTH",server.masterauth,NULL);
if (err[0] == '-') { if (err[0] == '-') {
redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",err); redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",err);
...@@ -1302,6 +1339,18 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) { ...@@ -1302,6 +1339,18 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
sdsfree(err); 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 /* Set the slave port, so that Master's INFO command can list the
* slave listening port correctly. */ * slave listening port correctly. */
{ {
...@@ -1698,6 +1747,7 @@ void refreshGoodSlavesCount(void) { ...@@ -1698,6 +1747,7 @@ void refreshGoodSlavesCount(void) {
time_t lag = server.unixtime - slave->repl_ack_time; time_t lag = server.unixtime - slave->repl_ack_time;
if (slave->replstate == REDIS_REPL_ONLINE && if (slave->replstate == REDIS_REPL_ONLINE &&
!(slave->flags & REDIS_SLAVE_NO_SYNC) &&
lag <= server.repl_min_slaves_max_lag) good++; lag <= server.repl_min_slaves_max_lag) good++;
} }
server.repl_good_slaves_count = good; server.repl_good_slaves_count = good;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment