diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/Makefile | 5 | ||||
-rw-r--r-- | src/anet.c | 63 | ||||
-rw-r--r-- | src/anet.h | 4 | ||||
-rwxr-xr-x | src/config.c | 21 | ||||
-rw-r--r-- | src/networking.c | 4 | ||||
-rwxr-xr-x | src/redis.c | 6 | ||||
-rwxr-xr-x | src/redis.h | 2 | ||||
-rwxr-xr-x | src/replication.c | 7 | ||||
-rw-r--r-- | src/sentinel.c | 10 | ||||
-rw-r--r-- | src/t_set.c | 4 | ||||
-rw-r--r-- | src/version.h | 2 | ||||
-rw-r--r-- | src/ziplist.c | 4 |
12 files changed, 117 insertions, 15 deletions
diff --git a/src/Makefile b/src/Makefile index ebf5786e2..7a553d030 100755 --- a/src/Makefile +++ b/src/Makefile @@ -241,7 +241,10 @@ gcov: $(MAKE) REDIS_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_LDFLAGS="-fprofile-arcs -ftest-coverage" noopt: - $(MAKE) OPT="-O0" + $(MAKE) OPTIMIZATION="-O0" + +valgrind: + $(MAKE) OPTIMIZATION="-O0" MALLOC="libc" src/help.h: @$(SRCDIR)/../utils/generate-command-help.rb > help.h diff --git a/src/anet.c b/src/anet.c index 4da3e28db..963b6688e 100644 --- a/src/anet.c +++ b/src/anet.c @@ -75,10 +75,56 @@ int anetNonBlock(char *err, int fd) return ANET_OK; } -int anetTcpNoDelay(char *err, int fd) +/* Set TCP keep alive option to detect dead peers. The interval option + * is only used for Linux as we are using Linux-specific APIs to set + * the probe send time, interval, and count. */ +int anetKeepAlive(char *err, int fd, int interval) { - int yes = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) + int val = 1; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1) + { + anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno)); + return ANET_ERR; + } + +#ifdef __linux__ + /* Default settings are more or less garbage, with the keepalive time + * set to 7200 by default on Linux. Modify settings to make the feature + * actually useful. */ + + /* Send first probe after interval. */ + val = interval; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { + anetSetError(err, "setsockopt TCP_KEEPIDLE: %s\n", strerror(errno)); + return ANET_ERR; + } + + /* Send next probes after the specified interval. Note that we set the + * delay as interval / 3, as we send three probes before detecting + * an error (see the next setsockopt call). */ + val = interval/3; + if (val == 0) val = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { + anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno)); + return ANET_ERR; + } + + /* Consider the socket in error state after three we send three ACK + * probes without getting a reply. */ + val = 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { + anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno)); + return ANET_ERR; + } +#endif + + return ANET_OK; +} + +static int anetSetTcpNoDelay(char *err, int fd, int val) +{ + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1) { anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno)); return ANET_ERR; @@ -86,6 +132,17 @@ int anetTcpNoDelay(char *err, int fd) return ANET_OK; } +int anetEnableTcpNoDelay(char *err, int fd) +{ + return anetSetTcpNoDelay(err, fd, 1); +} + +int anetDisableTcpNoDelay(char *err, int fd) +{ + return anetSetTcpNoDelay(err, fd, 0); +} + + int anetSetSendBuffer(char *err, int fd, int buffsize) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1) diff --git a/src/anet.h b/src/anet.h index 062b22c56..696c2c225 100644 --- a/src/anet.h +++ b/src/anet.h @@ -51,8 +51,10 @@ 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 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); +int anetKeepAlive(char *err, int fd, int interval); #endif diff --git a/src/config.c b/src/config.c index 71157313c..dbea5513d 100755 --- a/src/config.c +++ b/src/config.c @@ -81,6 +81,11 @@ void loadServerConfigFromString(char *config) { if (server.maxidletime < 0) { err = "Invalid timeout value"; goto loaderr; } + } else if (!strcasecmp(argv[0],"tcp-keepalive") && argc == 2) { + server.tcpkeepalive = atoi(argv[1]); + if (server.tcpkeepalive < 0) { + err = "Invalid tcp-keepalive value"; goto loaderr; + } } else if (!strcasecmp(argv[0],"port") && argc == 2) { server.port = atoi(argv[1]); if (server.port < 0 || server.port > 65535) { @@ -238,6 +243,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) { @@ -521,6 +530,10 @@ void configSetCommand(redisClient *c) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0 || ll > LONG_MAX) goto badfmt; server.maxidletime = ll; + } else if (!strcasecmp(c->argv[2]->ptr,"tcp-keepalive")) { + if (getLongLongFromObject(o,&ll) == REDIS_ERR || + ll < 0 || ll > INT_MAX) goto badfmt; + server.tcpkeepalive = ll; } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) { if (!strcasecmp(o->ptr,"no")) { server.aof_fsync = AOF_FSYNC_NO; @@ -719,6 +732,11 @@ void configSetCommand(redisClient *c) { if (yn == -1) goto badfmt; server.rdb_checksum = yn; + } else if (!strcasecmp(c->argv[2]->ptr,"repl-disable-tcp-nodelay")) { + int yn = yesnotoi(o->ptr); + + 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; @@ -784,6 +802,7 @@ void configGetCommand(redisClient *c) { config_get_numerical_field("maxmemory",server.maxmemory); config_get_numerical_field("maxmemory-samples",server.maxmemory_samples); config_get_numerical_field("timeout",server.maxidletime); + config_get_numerical_field("tcp-keepalive",server.tcpkeepalive); config_get_numerical_field("auto-aof-rewrite-percentage", server.aof_rewrite_perc); config_get_numerical_field("auto-aof-rewrite-min-size", @@ -828,6 +847,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. */ diff --git a/src/networking.c b/src/networking.c index 6e5d32489..3f14b17c8 100644 --- a/src/networking.c +++ b/src/networking.c @@ -58,7 +58,9 @@ 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 (server.tcpkeepalive) + anetKeepAlive(NULL,fd,server.tcpkeepalive); if (aeCreateFileEvent(server.el,fd,AE_READABLE, readQueryFromClient, c) == AE_ERR) { diff --git a/src/redis.c b/src/redis.c index 9b4e1ac28..e6faf8ada 100755 --- a/src/redis.c +++ b/src/redis.c @@ -215,7 +215,7 @@ struct redisCommand redisCommandTable[] = { {"bgsaveto",bgsavetoCommand,2,"ar",0,NULL,0,0,0,0,0}, {"bgrewriteaof",bgrewriteaofCommand,1,"ar",0,NULL,0,0,0,0,0}, {"shutdown",shutdownCommand,-1,"ar",0,NULL,0,0,0,0,0}, - {"lastsave",lastsaveCommand,1,"r",0,NULL,0,0,0,0,0}, + {"lastsave",lastsaveCommand,1,"rR",0,NULL,0,0,0,0,0}, {"type",typeCommand,2,"r",0,NULL,1,1,1,0,0}, {"multi",multiCommand,1,"rs",0,NULL,0,0,0,0,0}, {"exec",execCommand,1,"sM",0,NULL,0,0,0,0,0}, @@ -541,7 +541,7 @@ dictType commandTableDictType = { NULL /* val destructor */ }; -/* Hash type hash table (note that small hashes are represented with zipmaps) */ +/* Hash type hash table (note that small hashes are represented with ziplists) */ dictType hashDictType = { dictEncObjHash, /* hash function */ NULL, /* key dup */ @@ -1187,6 +1187,7 @@ void initServerConfig() { server.dbnum = REDIS_DEFAULT_DBNUM; server.verbosity = REDIS_NOTICE; server.maxidletime = REDIS_MAXIDLETIME; + server.tcpkeepalive = 0; server.client_max_querybuf_len = REDIS_MAX_QUERYBUF_LEN; server.saveparams = NULL; server.loading = 0; @@ -1256,6 +1257,7 @@ void initServerConfig() { server.repl_serve_stale_data = 1; server.repl_slave_ro = 1; server.repl_down_since = time(NULL); + server.repl_disable_tcp_nodelay = 0; server.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY; /* Client output buffer limits */ diff --git a/src/redis.h b/src/redis.h index 3319aa87b..b4d58db40 100755 --- a/src/redis.h +++ b/src/redis.h @@ -574,6 +574,7 @@ struct redisServer { /* Configuration */ int verbosity; /* Loglevel in redis.conf */ int maxidletime; /* Client timeout in seconds */ + int tcpkeepalive; /* Set SO_KEEPALIVE if non-zero. */ size_t client_max_querybuf_len; /* Limit for client query buffer length */ int dbnum; /* Total number of configured DBs */ int daemonize; /* True if running as a daemon */ @@ -647,6 +648,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 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 */ diff --git a/src/replication.c b/src/replication.c index 9c6d4dff7..7fbc4591b 100755 --- a/src/replication.c +++ b/src/replication.c @@ -276,7 +276,11 @@ void syncCommand(redisClient *c) { } c->repldbfd = -1; } - + + 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; listAddNodeTail(server.slaves,c); @@ -539,6 +543,7 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) { return; } redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Loading DB in memory"); + signalFlushedDb(-1); emptyDb(); /* Before loading the DB into memory we need to delete the readable * handler, otherwise it will get called recursively since diff --git a/src/sentinel.c b/src/sentinel.c index 8009e5ed9..fc857344c 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -2035,8 +2035,16 @@ void sentinelCommand(redisClient *c) { } else { sentinelAddr *addr = ri->addr; - if ((ri->flags & SRI_FAILOVER_IN_PROGRESS) && ri->promoted_slave) + /* If we are in the middle of a failover, and the slave was + * already successfully switched to master role, we can advertise + * the new address as slave in order to allow clients to talk + * with the new master ASAP. */ + if ((ri->flags & SRI_FAILOVER_IN_PROGRESS) && + ri->promoted_slave && + ri->failover_state >= SENTINEL_FAILOVER_STATE_RECONF_SLAVES) + { addr = ri->promoted_slave->addr; + } addReplyMultiBulkLen(c,2); addReplyBulkCString(c,addr->ip); addReplyBulkLongLong(c,addr->port); diff --git a/src/t_set.c b/src/t_set.c index f384dc76c..2cdcf86c6 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -451,7 +451,7 @@ void srandmemberWithCountCommand(redisClient *c) { * The number of requested elements is greater than the number of * elements inside the set: simply return the whole set. */ if (count >= size) { - sunionDiffGenericCommand(c,c->argv,c->argc-1,NULL,REDIS_OP_UNION); + sunionDiffGenericCommand(c,c->argv+1,1,NULL,REDIS_OP_UNION); return; } @@ -473,7 +473,7 @@ void srandmemberWithCountCommand(redisClient *c) { /* Add all the elements into the temporary dictionary. */ si = setTypeInitIterator(set); while((encoding = setTypeNext(si,&ele,&llele)) != -1) { - int retval; + int retval = DICT_ERR; if (encoding == REDIS_ENCODING_INTSET) { retval = dictAdd(d,createStringObjectFromLongLong(llele),NULL); diff --git a/src/version.h b/src/version.h index 293bd1bfb..765dc9100 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define REDIS_VERSION "2.6.9" +#define REDIS_VERSION "2.6.10" diff --git a/src/ziplist.c b/src/ziplist.c index d4ac4f9b4..8a6b54a7c 100644 --- a/src/ziplist.c +++ b/src/ziplist.c @@ -739,10 +739,10 @@ unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p) { } } -/* Get entry pointer to by 'p' and store in either 'e' or 'v' depending +/* Get entry pointed to by 'p' and store in either 'e' or 'v' depending * on the encoding of the entry. 'e' is always set to NULL to be able * to find out whether the string pointer or the integer value was set. - * Return 0 if 'p' points to the end of the zipmap, 1 otherwise. */ + * Return 0 if 'p' points to the end of the ziplist, 1 otherwise. */ unsigned int ziplistGet(unsigned char *p, unsigned char **sstr, unsigned int *slen, long long *sval) { zlentry entry; if (p == NULL || p[0] == ZIP_END) return 0; |