Skip to content

Commit

Permalink
TCP_NODELAY after SYNC: changes to the implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
antirez committed Feb 5, 2013
1 parent 45b1b2f commit cf0191d
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 25 deletions.
15 changes: 15 additions & 0 deletions redis.conf
Expand Up @@ -196,6 +196,21 @@ slave-read-only yes
#
# repl-timeout 60

# Disable TCP_NODELAY on the slave socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to slaves. But this can add a delay for
# the data to appear on the slave side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the slave side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and slaves are many hops away, turning this to "yes" may
# be a good idea.
repl-disable-tcp-nodelay no

# The slave priority is an integer number published by Redis in the INFO output.
# It is used by Redis Sentinel in order to select a slave to promote into a
# master if the master is no longer working correctly.
Expand Down
12 changes: 6 additions & 6 deletions src/anet.c
Expand Up @@ -75,24 +75,24 @@ int anetNonBlock(char *err, int fd)
return ANET_OK;
}

static int _anetTcpNoDelay(char *err, int fd, int yes)
static int anetSetTcpNoDelay(char *err, int fd, int val)
{
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1)
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1)
{
anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}

int anetTcpNoDelay(char *err, int fd)
int anetEnableTcpNoDelay(char *err, int fd)
{
return _anetTcpNoDelay(err, fd, 1);
return anetSetTcpNoDelay(err, fd, 1);
}

int anetTcpNoDelayOff(char *err, int fd)
int anetDisableTcpNoDelay(char *err, int fd)
{
return _anetTcpNoDelay(err, fd, 0);
return anetSetTcpNoDelay(err, fd, 0);
}


Expand Down
4 changes: 2 additions & 2 deletions src/anet.h
Expand Up @@ -51,8 +51,8 @@ int anetTcpAccept(char *err, int serversock, char *ip, int *port);
int anetUnixAccept(char *err, int serversock);
int anetWrite(int fd, char *buf, int count);
int anetNonBlock(char *err, int fd);
int anetTcpNoDelay(char *err, int fd);
int anetTcpNoDelayOff(char *err, int fd);
int anetEnableTcpNoDelay(char *err, int fd);
int anetDisableTcpNoDelay(char *err, int fd);
int anetTcpKeepAlive(char *err, int fd);
int anetPeerToString(int fd, char *ip, int *port);

Expand Down
16 changes: 10 additions & 6 deletions src/config.c
Expand Up @@ -230,6 +230,10 @@ void loadServerConfigFromString(char *config) {
err = "repl-timeout must be 1 or greater";
goto loaderr;
}
} else if (!strcasecmp(argv[0],"repl-disable-tcp-nodelay") && argc==2) {
if ((server.repl_disable_tcp_nodelay = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
server.masterauth = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"slave-serve-stale-data") && argc == 2) {
Expand Down Expand Up @@ -378,8 +382,6 @@ void loadServerConfigFromString(char *config) {
if ((server.stop_writes_on_bgsave_err = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"slave-tcp-nodelay-off") && argc == 2) {
server.slave_tcp_nodelay_off = atoi(argv[1]);
} else if (!strcasecmp(argv[0],"slave-priority") && argc == 2) {
server.slave_priority = atoi(argv[1]);
} else if (!strcasecmp(argv[0],"sentinel")) {
Expand Down Expand Up @@ -699,10 +701,11 @@ void configSetCommand(redisClient *c) {

if (yn == -1) goto badfmt;
server.rdb_checksum = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"slave-tcp-nodelay-off")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ) goto badfmt;
} else if (!strcasecmp(c->argv[2]->ptr,"repl-disable-tcp-nodelay")) {
int yn = yesnotoi(o->ptr);

server.slave_tcp_nodelay_off = ll;
if (yn == -1) goto badfmt;
server.repl_disable_tcp_nodelay = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"slave-priority")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll <= 0) goto badfmt;
Expand Down Expand Up @@ -796,7 +799,6 @@ void configGetCommand(redisClient *c) {
config_get_numerical_field("repl-timeout",server.repl_timeout);
config_get_numerical_field("maxclients",server.maxclients);
config_get_numerical_field("watchdog-period",server.watchdog_period);
config_get_numerical_field("slave-tcp-nodelay-off",server.slave_tcp_nodelay_off);
config_get_numerical_field("slave-priority",server.slave_priority);

/* Bool (yes/no) values */
Expand All @@ -812,6 +814,8 @@ void configGetCommand(redisClient *c) {
config_get_bool_field("rdbcompression", server.rdb_compression);
config_get_bool_field("rdbchecksum", server.rdb_checksum);
config_get_bool_field("activerehashing", server.activerehashing);
config_get_bool_field("repl-disable-tcp-nodelay",
server.repl_disable_tcp_nodelay);

/* Everything we can't handle with macros follows. */

Expand Down
2 changes: 1 addition & 1 deletion src/networking.c
Expand Up @@ -58,7 +58,7 @@ redisClient *createClient(int fd) {
* contexts (for instance a Lua script) we need a non connected client. */
if (fd != -1) {
anetNonBlock(NULL,fd);
anetTcpNoDelay(NULL,fd);
anetEnableTcpNoDelay(NULL,fd);
if (aeCreateFileEvent(server.el,fd,AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
Expand Down
2 changes: 1 addition & 1 deletion src/redis.c
Expand Up @@ -1160,7 +1160,7 @@ void initServerConfig() {
server.repl_serve_stale_data = 1;
server.repl_slave_ro = 1;
server.repl_down_since = time(NULL);
server.slave_tcp_nodelay_off = 1;
server.repl_disable_tcp_nodelay = 0;
server.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY;

/* Client output buffer limits */
Expand Down
2 changes: 1 addition & 1 deletion src/redis.h
Expand Up @@ -616,7 +616,7 @@ struct redisServer {
int repl_serve_stale_data; /* Serve stale data when link is down? */
int repl_slave_ro; /* Slave is read only? */
time_t repl_down_since; /* Unix time at which link with master went down */
int slave_tcp_nodelay_off; /* turn off slave's tcp nodelay */
int repl_disable_tcp_nodelay; /* Disable TCP_NODELAY after SYNC? */
int slave_priority; /* Reported in INFO and used by Sentinel. */
/* Limits */
unsigned int maxclients; /* Max number of simultaneous clients */
Expand Down
11 changes: 3 additions & 8 deletions src/replication.c
Expand Up @@ -118,14 +118,6 @@ void syncCommand(redisClient *c) {
/* ignore SYNC if already slave or in monitor mode */
if (c->flags & REDIS_SLAVE) return;

if (server.slave_tcp_nodelay_off) {
redisLog(REDIS_NOTICE, "Turning off slave's :%d TCP NODELAY SETTING", c->fd);
char err[1024];
if (anetTcpNoDelayOff(err, c->fd) == ANET_ERR)
redisLog(REDIS_WARNING,
"Can't turn off %d 's tcp nodelay setting: %s", c->fd, err);
}

/* Refuse SYNC requests if we are a slave but the link with our master
* is not ok... */
if (server.masterhost && server.repl_state != REDIS_REPL_CONNECTED) {
Expand Down Expand Up @@ -180,6 +172,9 @@ void syncCommand(redisClient *c) {
}
c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
}

if (server.repl_disable_tcp_nodelay)
anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */
c->repldbfd = -1;
c->flags |= REDIS_SLAVE;
c->slaveseldb = 0;
Expand Down

0 comments on commit cf0191d

Please sign in to comment.