summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2011-07-27 16:37:45 +0200
committerantirez <antirez@gmail.com>2011-07-27 16:37:45 +0200
commitc1b270127c0dc81f901d56e2aa474b85459a7678 (patch)
treed0bf38a7c74fb981acdb4c6c1257e80d09d14c1d
parent62e6f6c29af513c067f5727b8b5545840daa9806 (diff)
parent5960ac9dec5184bf4184dda3010689c1457fd761 (diff)
downloadredis-c1b270127c0dc81f901d56e2aa474b85459a7678.tar.gz
Merge remote-tracking branch 'origin/2.2' into 2.2
-rw-r--r--00-RELEASENOTES16
-rw-r--r--redis.conf5
-rw-r--r--src/Makefile34
-rw-r--r--src/aof.c6
-rw-r--r--src/config.c15
-rw-r--r--src/db.c23
-rw-r--r--src/multi.c11
-rw-r--r--src/networking.c3
-rw-r--r--src/redis.c101
-rw-r--r--src/redis.h7
-rw-r--r--src/t_list.c3
-rw-r--r--src/version.h2
-rw-r--r--src/vm.c8
-rw-r--r--src/zmalloc.c10
-rw-r--r--src/zmalloc.h3
-rw-r--r--tests/integration/aof.tcl18
-rw-r--r--tests/test_helper.tcl2
17 files changed, 178 insertions, 89 deletions
diff --git a/00-RELEASENOTES b/00-RELEASENOTES
index 7234e29f9..e7f91056a 100644
--- a/00-RELEASENOTES
+++ b/00-RELEASENOTES
@@ -12,6 +12,22 @@ for 2.0.
CHANGELOG
---------
+What's new in Redis 2.2.12
+==========================
+
+* The Slowlog feature was backported to Redis 2.2.
+* A number of fixes related blocking operations on lists when mixed with
+ AOF and Replication.
+* Fixed bad interactions between EXPIRE, EXPIREAT, and in general volatile
+ keys when AOF is enabled. More details in the Redis Google Group here:
+ http://groups.google.com/group/redis-db/browse_frm/thread/5a931fefb88b16d5?tvc=1
+* no more allocation stats info in INFO.
+* colorized make for 2.2 as well.
+* Fixed a problem with AOF when it is stopped via CONFIG SET appendonly no.
+* Warn the user enabling VM that VM is deprecated and discouraged.
+* prepareForShutdown() fixed for correctness.
+* Close the listening sockets on exit for faster restarts.
+
What's new in Redis 2.2.11
==========================
diff --git a/redis.conf b/redis.conf
index a545b78b7..a8188a92e 100644
--- a/redis.conf
+++ b/redis.conf
@@ -314,10 +314,13 @@ slowlog-log-slower-than 10000
# There is no limit to this length. Just be aware that it will consume memory.
# You can reclaim memory used by the slow log with SLOWLOG RESET.
-slowlog-log-len 1024
+slowlog-max-len 1024
################################ VIRTUAL MEMORY ###############################
+### WARNING! Virtual Memory is deprecated in Redis 2.4
+### The use of Virtual Memory is strongly discouraged.
+
# Virtual Memory allows Redis to work with datasets bigger than the actual
# amount of RAM needed to hold the whole dataset in memory.
# In order to do so very used keys are taken in memory while the other keys
diff --git a/src/Makefile b/src/Makefile
index c08d50c32..67b09723b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,6 +5,19 @@
release_hdr := $(shell sh -c './mkreleasehdr.sh')
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
OPTIMIZATION?=-O2
+
+CCCOLOR="\033[34m"
+LINKCOLOR="\033[34;1m"
+SRCCOLOR="\033[33m"
+BINCOLOR="\033[37;1m"
+MAKECOLOR="\033[32;1m"
+ENDCOLOR="\033[0m"
+
+ifndef V
+QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR);
+QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR);
+endif
+
ifeq ($(uname_S),SunOS)
CFLAGS?= -std=c99 -pedantic $(OPTIMIZATION) -Wall -W -D__EXTENSIONS__ -D_XPG6
CCLINK?= -ldl -lnsl -lsocket -lm -lpthread
@@ -111,33 +124,36 @@ zipmap.o: zipmap.c zmalloc.h
zmalloc.o: zmalloc.c config.h zmalloc.h
dependencies:
+ @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)hiredis$(ENDCOLOR)
cd ../deps/hiredis && $(MAKE) static ARCH="$(ARCH)"
+ @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)linenoise$(ENDCOLOR)
cd ../deps/linenoise && $(MAKE) ARCH="$(ARCH)"
redis-server: $(OBJ)
- $(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ)
+ $(QUIET_LINK)$(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ)
redis-benchmark: dependencies $(BENCHOBJ)
- cd ../deps/hiredis && $(MAKE) static
- $(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) ../deps/hiredis/libhiredis.a
+ @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)hiredis$(ENDCOLOR)
+ cd ../deps/hiredis && $(MAKE) static ARCH="$(ARCH)"
+ $(QUIET_LINK)$(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) ../deps/hiredis/libhiredis.a
redis-benchmark.o:
- $(CC) -c $(CFLAGS) -I../deps/hiredis $(DEBUG) $(COMPILE_TIME) $<
+ $(QUIET_CC)$(CC) -c $(CFLAGS) -I../deps/hiredis $(DEBUG) $(COMPILE_TIME) $<
redis-cli: dependencies $(CLIOBJ)
- $(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o
+ $(QUIET_LINK)$(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o
redis-cli.o:
- $(CC) -c $(CFLAGS) -I../deps/hiredis -I../deps/linenoise $(DEBUG) $(COMPILE_TIME) $<
+ $(QUIET_CC)$(CC) -c $(CFLAGS) -I../deps/hiredis -I../deps/linenoise $(DEBUG) $(COMPILE_TIME) $<
redis-check-dump: $(CHECKDUMPOBJ)
- $(CC) -o $(CHECKDUMPPRGNAME) $(CCOPT) $(DEBUG) $(CHECKDUMPOBJ)
+ $(QUIET_LINK)$(CC) -o $(CHECKDUMPPRGNAME) $(CCOPT) $(DEBUG) $(CHECKDUMPOBJ)
redis-check-aof: $(CHECKAOFOBJ)
- $(CC) -o $(CHECKAOFPRGNAME) $(CCOPT) $(DEBUG) $(CHECKAOFOBJ)
+ $(QUIET_LINK)$(CC) -o $(CHECKAOFPRGNAME) $(CCOPT) $(DEBUG) $(CHECKAOFOBJ)
.c.o:
- $(CC) -c $(CFLAGS) $(DEBUG) $(COMPILE_TIME) $<
+ $(QUIET_CC)$(CC) -c $(CFLAGS) $(DEBUG) $(COMPILE_TIME) $<
clean:
rm -rf $(PRGNAME) $(BENCHPRGNAME) $(CLIPRGNAME) $(CHECKDUMPPRGNAME) $(CHECKAOFPRGNAME) *.o *.gcda *.gcno *.gcov
diff --git a/src/aof.c b/src/aof.c
index 06c9a47d5..b0852c47f 100644
--- a/src/aof.c
+++ b/src/aof.c
@@ -19,15 +19,15 @@ void stopAppendOnly(void) {
server.appendseldb = -1;
server.appendonly = 0;
/* rewrite operation in progress? kill it, wait child exit */
- if (server.bgsavechildpid != -1) {
+ if (server.bgrewritechildpid != -1) {
int statloc;
- if (kill(server.bgsavechildpid,SIGKILL) != -1)
+ if (kill(server.bgrewritechildpid,SIGKILL) != -1)
wait3(&statloc,0,NULL);
/* reset the buffer accumulating changes while the child saves */
sdsfree(server.bgrewritebuf);
server.bgrewritebuf = sdsempty();
- server.bgsavechildpid = -1;
+ server.bgrewritechildpid = -1;
}
}
diff --git a/src/config.c b/src/config.c
index f2b0d312a..58d1190f3 100644
--- a/src/config.c
+++ b/src/config.c
@@ -30,6 +30,7 @@ void loadServerConfig(char *filename) {
char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL;
int linenum = 0;
sds line = NULL;
+ int really_use_vm = 0;
if (filename[0] == '-' && filename[1] == '\0')
fp = stdin;
@@ -243,6 +244,10 @@ void loadServerConfig(char *filename) {
if ((server.vm_enabled = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
+ } else if (!strcasecmp(argv[0],"really-use-vm") && argc == 2) {
+ if ((really_use_vm = yesnotoi(argv[1])) == -1) {
+ err = "argument must be 'yes' or 'no'"; goto loaderr;
+ }
} else if (!strcasecmp(argv[0],"vm-swap-file") && argc == 2) {
zfree(server.vm_swap_file);
server.vm_swap_file = zstrdup(argv[1]);
@@ -303,6 +308,7 @@ void loadServerConfig(char *filename) {
sdsfree(line);
}
if (fp != stdin) fclose(fp);
+ if (server.vm_enabled && !really_use_vm) goto vm_warning;
return;
loaderr:
@@ -311,6 +317,15 @@ loaderr:
fprintf(stderr, ">>> '%s'\n", line);
fprintf(stderr, "%s\n", err);
exit(1);
+
+vm_warning:
+ fprintf(stderr, "\nARE YOU SURE YOU WANT TO USE VM?\n\n");
+ fprintf(stderr, "Redis Virtual Memory is going to be deprecated soon,\n");
+ fprintf(stderr, "we think you should NOT use it, but use Redis only if\n");
+ fprintf(stderr, "your data is suitable for an in-memory database.\n");
+ fprintf(stderr, "If you *really* want VM add this in the config file:\n");
+ fprintf(stderr, "\n really-use-vm yes\n\n");
+ exit(1);
}
/*-----------------------------------------------------------------------------
diff --git a/src/db.c b/src/db.c
index ede242dbe..e38466d3b 100644
--- a/src/db.c
+++ b/src/db.c
@@ -455,6 +455,9 @@ int expireIfNeeded(redisDb *db, robj *key) {
if (when < 0) return 0; /* No expire for this key */
+ /* Don't expire anything while loading. It will be done later. */
+ if (server.loading) return 0;
+
/* If we are running in the context of a slave, return ASAP:
* the slave key expiration is controlled by the master that will
* send us synthesized DEL operations for expired keys.
@@ -492,10 +495,24 @@ void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) {
addReply(c,shared.czero);
return;
}
- if (seconds <= 0) {
- if (dbDelete(c->db,key)) server.dirty++;
- addReply(c, shared.cone);
+ /* EXPIRE with negative TTL, or EXPIREAT with a timestamp into the past
+ * should never be executed as a DEL when load the AOF or in the context
+ * of a slave instance.
+ *
+ * Instead we take the other branch of the IF statement setting an expire
+ * (possibly in the past) and wait for an explicit DEL from the master. */
+ if (seconds <= 0 && !server.loading && !server.masterhost) {
+ robj *aux;
+
+ redisAssert(dbDelete(c->db,key));
+ server.dirty++;
+
+ /* Replicate/AOF this as an explicit DEL. */
+ aux = createStringObject("DEL",3);
+ rewriteClientCommandVector(c,2,aux,key);
+ decrRefCount(aux);
touchWatchedKey(c->db,key);
+ addReply(c, shared.cone);
return;
} else {
time_t when = time(NULL)+seconds;
diff --git a/src/multi.c b/src/multi.c
index ba3a0cd6c..f0b8fc856 100644
--- a/src/multi.c
+++ b/src/multi.c
@@ -24,14 +24,14 @@ void freeClientMultiState(redisClient *c) {
}
/* Add a new command into the MULTI commands queue */
-void queueMultiCommand(redisClient *c, struct redisCommand *cmd) {
+void queueMultiCommand(redisClient *c) {
multiCmd *mc;
int j;
c->mstate.commands = zrealloc(c->mstate.commands,
sizeof(multiCmd)*(c->mstate.count+1));
mc = c->mstate.commands+c->mstate.count;
- mc->cmd = cmd;
+ mc->cmd = c->cmd;
mc->argc = c->argc;
mc->argv = zmalloc(sizeof(robj*)*c->argc);
memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
@@ -78,6 +78,7 @@ void execCommand(redisClient *c) {
int j;
robj **orig_argv;
int orig_argc;
+ struct redisCommand *orig_cmd;
if (!(c->flags & REDIS_MULTI)) {
addReplyError(c,"EXEC without MULTI");
@@ -105,18 +106,22 @@ void execCommand(redisClient *c) {
unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
orig_argv = c->argv;
orig_argc = c->argc;
+ orig_cmd = c->cmd;
addReplyMultiBulkLen(c,c->mstate.count);
for (j = 0; j < c->mstate.count; j++) {
c->argc = c->mstate.commands[j].argc;
c->argv = c->mstate.commands[j].argv;
- call(c,c->mstate.commands[j].cmd);
+ c->cmd = c->mstate.commands[j].cmd;
+ call(c);
/* Commands may alter argc/argv, restore mstate. */
c->mstate.commands[j].argc = c->argc;
c->mstate.commands[j].argv = c->argv;
+ c->mstate.commands[j].cmd = c->cmd;
}
c->argv = orig_argv;
c->argc = orig_argc;
+ c->cmd = orig_cmd;
freeClientMultiState(c);
initClientMultiState(c);
c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);
diff --git a/src/networking.c b/src/networking.c
index 7d4b96364..b31c89df9 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -31,6 +31,7 @@ redisClient *createClient(int fd) {
c->reqtype = 0;
c->argc = 0;
c->argv = NULL;
+ c->cmd = NULL;
c->multibulklen = 0;
c->bulklen = -1;
c->sentlen = 0;
@@ -444,6 +445,7 @@ static void freeClientArgv(redisClient *c) {
for (j = 0; j < c->argc; j++)
decrRefCount(c->argv[j]);
c->argc = 0;
+ c->cmd = NULL;
}
void freeClient(redisClient *c) {
@@ -896,4 +898,3 @@ void rewriteClientCommandVector(redisClient *c, int argc, ...) {
c->argc = argc;
va_end(ap);
}
-
diff --git a/src/redis.c b/src/redis.c
index 0ea7813a2..1d732e91f 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -677,7 +677,7 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
readQueryFromClient, c);
cmd = lookupCommand(c->argv[0]->ptr);
redisAssert(cmd != NULL);
- call(c,cmd);
+ call(c);
resetClient(c);
/* There may be more data to process in the input buffer. */
if (c->querybuf && sdslen(c->querybuf) > 0)
@@ -958,18 +958,18 @@ struct redisCommand *lookupCommandByCString(char *s) {
}
/* Call() is the core of Redis execution of a command */
-void call(redisClient *c, struct redisCommand *cmd) {
+void call(redisClient *c) {
long long dirty, start = ustime(), duration;
dirty = server.dirty;
- cmd->proc(c);
+ c->cmd->proc(c);
dirty = server.dirty-dirty;
duration = ustime()-start;
slowlogPushEntryIfNeeded(c->argv,c->argc,duration);
if (server.appendonly && dirty)
- feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
- if ((dirty || cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
+ feedAppendOnlyFile(c->cmd,c->db->id,c->argv,c->argc);
+ if ((dirty || c->cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
listLength(server.slaves))
replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
if (listLength(server.monitors))
@@ -986,8 +986,6 @@ void call(redisClient *c, struct redisCommand *cmd) {
* and other operations can be performed by the caller. Otherwise
* if 0 is returned the client was destroied (i.e. after QUIT). */
int processCommand(redisClient *c) {
- struct redisCommand *cmd;
-
/* The QUIT command is handled separately. Normal command procs will
* go through checking for replication and QUIT will cause trouble
* when FORCE_REPLICATION is enabled and would be implemented in
@@ -999,21 +997,22 @@ int processCommand(redisClient *c) {
}
/* Now lookup the command and check ASAP about trivial error conditions
- * such wrong arity, bad command name and so forth. */
- cmd = lookupCommand(c->argv[0]->ptr);
- if (!cmd) {
+ * such as wrong arity, bad command name and so forth. */
+ c->cmd = lookupCommand(c->argv[0]->ptr);
+ if (!c->cmd) {
addReplyErrorFormat(c,"unknown command '%s'",
(char*)c->argv[0]->ptr);
return REDIS_OK;
- } else if ((cmd->arity > 0 && cmd->arity != c->argc) ||
- (c->argc < -cmd->arity)) {
+ } else if ((c->cmd->arity > 0 && c->cmd->arity != c->argc) ||
+ (c->argc < -c->cmd->arity)) {
addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
- cmd->name);
+ c->cmd->name);
return REDIS_OK;
}
/* Check if the user is authenticated */
- if (server.requirepass && !c->authenticated && cmd->proc != authCommand) {
+ if (server.requirepass && !c->authenticated && c->cmd->proc != authCommand)
+ {
addReplyError(c,"operation not permitted");
return REDIS_OK;
}
@@ -1024,7 +1023,7 @@ int processCommand(redisClient *c) {
* keys in the dataset). If there are not the only thing we can do
* is returning an error. */
if (server.maxmemory) freeMemoryIfNeeded();
- if (server.maxmemory && (cmd->flags & REDIS_CMD_DENYOOM) &&
+ if (server.maxmemory && (c->cmd->flags & REDIS_CMD_DENYOOM) &&
zmalloc_used_memory() > server.maxmemory)
{
addReplyError(c,"command not allowed when used memory > 'maxmemory'");
@@ -1034,8 +1033,10 @@ int processCommand(redisClient *c) {
/* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
if ((dictSize(c->pubsub_channels) > 0 || listLength(c->pubsub_patterns) > 0)
&&
- cmd->proc != subscribeCommand && cmd->proc != unsubscribeCommand &&
- cmd->proc != psubscribeCommand && cmd->proc != punsubscribeCommand) {
+ c->cmd->proc != subscribeCommand &&
+ c->cmd->proc != unsubscribeCommand &&
+ c->cmd->proc != psubscribeCommand &&
+ c->cmd->proc != punsubscribeCommand) {
addReplyError(c,"only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context");
return REDIS_OK;
}
@@ -1044,7 +1045,7 @@ int processCommand(redisClient *c) {
* we are a slave with a broken link with master. */
if (server.masterhost && server.replstate != REDIS_REPL_CONNECTED &&
server.repl_serve_stale_data == 0 &&
- cmd->proc != infoCommand && cmd->proc != slaveofCommand)
+ c->cmd->proc != infoCommand && c->cmd->proc != slaveofCommand)
{
addReplyError(c,
"link with MASTER is down and slave-serve-stale-data is set to no");
@@ -1052,22 +1053,22 @@ int processCommand(redisClient *c) {
}
/* Loading DB? Return an error if the command is not INFO */
- if (server.loading && cmd->proc != infoCommand) {
+ if (server.loading && c->cmd->proc != infoCommand) {
addReply(c, shared.loadingerr);
return REDIS_OK;
}
/* Exec the command */
if (c->flags & REDIS_MULTI &&
- cmd->proc != execCommand && cmd->proc != discardCommand &&
- cmd->proc != multiCommand && cmd->proc != watchCommand)
+ c->cmd->proc != execCommand && c->cmd->proc != discardCommand &&
+ c->cmd->proc != multiCommand && c->cmd->proc != watchCommand)
{
- queueMultiCommand(c,cmd);
+ queueMultiCommand(c);
addReply(c,shared.queued);
} else {
if (server.vm_enabled && server.vm_max_threads > 0 &&
- blockClientOnSwappedKeys(c,cmd)) return REDIS_ERR;
- call(c,cmd);
+ blockClientOnSwappedKeys(c)) return REDIS_ERR;
+ call(c);
}
return REDIS_OK;
}
@@ -1075,20 +1076,29 @@ int processCommand(redisClient *c) {
/*================================== Shutdown =============================== */
int prepareForShutdown() {
- redisLog(REDIS_WARNING,"User requested shutdown, saving DB...");
+ redisLog(REDIS_WARNING,"User requested shutdown...");
/* Kill the saving child if there is a background saving in progress.
We want to avoid race conditions, for instance our saving child may
overwrite the synchronous saving did by SHUTDOWN. */
if (server.bgsavechildpid != -1) {
- redisLog(REDIS_WARNING,"There is a live saving child. Killing it!");
+ redisLog(REDIS_WARNING,"There is a child saving an .rdb. Killing it!");
kill(server.bgsavechildpid,SIGKILL);
rdbRemoveTempFile(server.bgsavechildpid);
}
if (server.appendonly) {
+ /* Kill the AOF saving child as the AOF we already have may be longer
+ * but contains the full dataset anyway. */
+ if (server.bgrewritechildpid != -1) {
+ redisLog(REDIS_WARNING,
+ "There is a child rewriting the AOF. Killing it!");
+ kill(server.bgrewritechildpid,SIGKILL);
+ }
/* Append only file: fsync() the AOF and exit */
+ redisLog(REDIS_NOTICE,"Calling fsync() on the AOF file.");
aof_fsync(server.appendfd);
- if (server.vm_enabled) unlink(server.vm_swap_file);
- } else if (server.saveparamslen > 0) {
+ }
+ if (server.saveparamslen > 0) {
+ redisLog(REDIS_NOTICE,"Saving the final RDB snapshot before exiting.");
/* Snapshotting. Perform a SYNC SAVE and exit */
if (rdbSave(server.dbfilename) != REDIS_OK) {
/* Ooops.. error saving! The best we can do is to continue
@@ -1096,14 +1106,23 @@ int prepareForShutdown() {
* in the next cron() Redis will be notified that the background
* saving aborted, handling special stuff like slaves pending for
* synchronization... */
- redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
+ redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit.");
return REDIS_ERR;
}
- } else {
- redisLog(REDIS_WARNING,"Not saving DB.");
}
- if (server.daemonize) unlink(server.pidfile);
- redisLog(REDIS_WARNING,"Server exit now, bye bye...");
+ if (server.vm_enabled) {
+ redisLog(REDIS_NOTICE,"Removing the swap file.");
+ unlink(server.vm_swap_file);
+ }
+ if (server.daemonize) {
+ redisLog(REDIS_NOTICE,"Removing the pid file.");
+ unlink(server.pidfile);
+ }
+ /* Close the listening sockets. Apparently this allows faster restarts. */
+ if (server.ipfd != -1) close(server.ipfd);
+ if (server.sofd != -1) close(server.sofd);
+
+ redisLog(REDIS_WARNING,"Redis is now ready to exit, bye bye...");
return REDIS_OK;
}
@@ -1176,8 +1195,8 @@ sds genRedisInfoString(void) {
"lru_clock:%ld\r\n"
"used_cpu_sys:%.2f\r\n"
"used_cpu_user:%.2f\r\n"
- "used_cpu_sys_childrens:%.2f\r\n"
- "used_cpu_user_childrens:%.2f\r\n"
+ "used_cpu_sys_children:%.2f\r\n"
+ "used_cpu_user_children:%.2f\r\n"
"connected_clients:%d\r\n"
"connected_slaves:%d\r\n"
"client_longest_output_list:%lu\r\n"
@@ -1335,18 +1354,6 @@ sds genRedisInfoString(void) {
);
}
- info = sdscat(info,"allocation_stats:");
- for (j = 0; j <= ZMALLOC_MAX_ALLOC_STAT; j++) {
- size_t count = zmalloc_allocations_for_size(j);
- if (count) {
- if (info[sdslen(info)-1] != ':') info = sdscatlen(info,",",1);
- info = sdscatprintf(info,"%s%d=%zu",
- (j == ZMALLOC_MAX_ALLOC_STAT) ? ">=" : "",
- j,count);
- }
- }
- info = sdscat(info,"\r\n");
-
for (j = 0; j < server.dbnum; j++) {
long long keys, vkeys;
diff --git a/src/redis.h b/src/redis.h
index 8a7a47fda..1fea983f4 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -314,6 +314,7 @@ typedef struct redisClient {
sds querybuf;
int argc;
robj **argv;
+ struct redisCommand *cmd;
int reqtype;
int multibulklen; /* number of multi bulk arguments left to read */
long bulklen; /* length of bulk argument in multi bulk request */
@@ -700,7 +701,7 @@ void popGenericCommand(redisClient *c, int where);
void unwatchAllKeys(redisClient *c);
void initClientMultiState(redisClient *c);
void freeClientMultiState(redisClient *c);
-void queueMultiCommand(redisClient *c, struct redisCommand *cmd);
+void queueMultiCommand(redisClient *c);
void touchWatchedKey(redisDb *db, robj *key);
void touchWatchedKeysOnFlush(int dbid);
@@ -788,7 +789,7 @@ int processCommand(redisClient *c);
void setupSignalHandlers(void);
struct redisCommand *lookupCommand(sds name);
struct redisCommand *lookupCommandByCString(char *s);
-void call(redisClient *c, struct redisCommand *cmd);
+void call(redisClient *c);
int prepareForShutdown();
void redisLog(int level, const char *fmt, ...);
void usage();
@@ -819,7 +820,7 @@ void vmReopenSwapFile(void);
int vmFreePage(off_t page);
void zunionInterBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int argc, robj **argv);
-int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd);
+int blockClientOnSwappedKeys(redisClient *c);
int dontWaitForSwappedKey(redisClient *c, robj *key);
void handleClientsBlockedOnSwappedKey(redisDb *db, robj *key);
vmpointer *vmSwapObjectBlocking(robj *val);
diff --git a/src/t_list.c b/src/t_list.c
index c05bd1ae3..b17bfbdc1 100644
--- a/src/t_list.c
+++ b/src/t_list.c
@@ -904,6 +904,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
if (listTypeLength(o) != 0) {
/* If the list contains elements fall back to the usual
* non-blocking POP operation */
+ struct redisCommand *orig_cmd;
robj *argv[2], **orig_argv;
int orig_argc;
@@ -911,6 +912,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
* popGenericCommand() as the command takes a single key. */
orig_argv = c->argv;
orig_argc = c->argc;
+ orig_cmd = c->cmd;
argv[1] = c->argv[j];
c->argv = argv;
c->argc = 2;
@@ -928,6 +930,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
/* Fix the client structure with the original stuff */
c->argv = orig_argv;
c->argc = orig_argc;
+ c->cmd = orig_cmd;
return;
}
diff --git a/src/version.h b/src/version.h
index 90686116e..f43af6e62 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define REDIS_VERSION "2.2.11"
+#define REDIS_VERSION "2.2.12"
diff --git a/src/vm.c b/src/vm.c
index ac0d92e33..3778856f8 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1064,11 +1064,11 @@ void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int
*
* Return 1 if the client is marked as blocked, 0 if the client can
* continue as the keys it is going to access appear to be in memory. */
-int blockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd) {
- if (cmd->vm_preload_proc != NULL) {
- cmd->vm_preload_proc(c,cmd,c->argc,c->argv);
+int blockClientOnSwappedKeys(redisClient *c) {
+ if (c->cmd->vm_preload_proc != NULL) {
+ c->cmd->vm_preload_proc(c,c->cmd,c->argc,c->argv);
} else {
- waitForMultipleSwappedKeys(c,cmd,c->argc,c->argv);
+ waitForMultipleSwappedKeys(c,c->cmd,c->argc,c->argv);
}
/* If the client was blocked for at least one key, mark it as blocked. */
diff --git a/src/zmalloc.c b/src/zmalloc.c
index aa3ccfe96..af2ffda21 100644
--- a/src/zmalloc.c
+++ b/src/zmalloc.c
@@ -55,16 +55,13 @@
#define update_zmalloc_stat_alloc(__n,__size) do { \
size_t _n = (__n); \
- size_t _stat_slot = (__size < ZMALLOC_MAX_ALLOC_STAT) ? __size : ZMALLOC_MAX_ALLOC_STAT; \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory += _n; \
- zmalloc_allocations[_stat_slot]++; \
pthread_mutex_unlock(&used_memory_mutex); \
} else { \
used_memory += _n; \
- zmalloc_allocations[_stat_slot]++; \
} \
} while(0)
@@ -83,8 +80,6 @@
static size_t used_memory = 0;
static int zmalloc_thread_safe = 0;
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
-/* Note that malloc_allocations elements are initialized to zero by C */
-size_t zmalloc_allocations[ZMALLOC_MAX_ALLOC_STAT+1];
static void zmalloc_oom(size_t size) {
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
@@ -185,11 +180,6 @@ size_t zmalloc_used_memory(void) {
return um;
}
-size_t zmalloc_allocations_for_size(size_t size) {
- if (size > ZMALLOC_MAX_ALLOC_STAT) return 0;
- return zmalloc_allocations[size];
-}
-
void zmalloc_enable_thread_safeness(void) {
zmalloc_thread_safe = 1;
}
diff --git a/src/zmalloc.h b/src/zmalloc.h
index d19979a30..bb6f629af 100644
--- a/src/zmalloc.h
+++ b/src/zmalloc.h
@@ -40,8 +40,5 @@ size_t zmalloc_used_memory(void);
void zmalloc_enable_thread_safeness(void);
float zmalloc_get_fragmentation_ratio(void);
size_t zmalloc_get_rss(void);
-size_t zmalloc_allocations_for_size(size_t size);
-
-#define ZMALLOC_MAX_ALLOC_STAT 256
#endif /* _ZMALLOC_H */
diff --git a/tests/integration/aof.tcl b/tests/integration/aof.tcl
index 927969b62..954edc2c4 100644
--- a/tests/integration/aof.tcl
+++ b/tests/integration/aof.tcl
@@ -101,4 +101,22 @@ tags {"aof"} {
assert_equal 1 [$client scard set]
}
}
+
+ ## Test that EXPIREAT is loaded correctly
+ create_aof {
+ append_to_aof [formatCommand rpush list foo]
+ append_to_aof [formatCommand expireat list 1000]
+ append_to_aof [formatCommand rpush list bar]
+ }
+
+ start_server_aof [list dir $server_path] {
+ test "AOF+EXPIRE: Server should have been started" {
+ assert_equal 1 [is_alive $srv]
+ }
+
+ test "AOF+EXPIRE: List should be empty" {
+ set client [redis [dict get $srv host] [dict get $srv port]]
+ assert_equal 0 [$client llen list]
+ }
+ }
}
diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl
index 9b1ba6347..353c99a47 100644
--- a/tests/test_helper.tcl
+++ b/tests/test_helper.tcl
@@ -128,7 +128,7 @@ proc execute_everything {} {
execute_tests "unit/slowlog"
# run tests with VM enabled
- set ::global_overrides {vm-enabled yes}
+ set ::global_overrides {vm-enabled yes really-use-vm yes}
execute_tests "unit/protocol"
execute_tests "unit/basic"
execute_tests "unit/type/list"