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) {
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) {
......
......@@ -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|
......
......@@ -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;
......
......@@ -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. */
......
......@@ -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;
......
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