]> git.saurik.com Git - redis.git/commitdiff
Merge pull request #208 from jbergstroem/jemalloc-2.2.5
authorSalvatore Sanfilippo <antirez@gmail.com>
Fri, 25 Nov 2011 15:29:55 +0000 (07:29 -0800)
committerSalvatore Sanfilippo <antirez@gmail.com>
Fri, 25 Nov 2011 15:29:55 +0000 (07:29 -0800)
Update to jemalloc 2.2.5

src/debug.c
src/multi.c
src/networking.c
src/redis.c
src/redis.h
tests/unit/cas.tcl

index 376e07125df988bf1942813879635619f2877bb3..d610d2a97d4fe96d677d1d7edcff3a12c422b492 100644 (file)
@@ -297,10 +297,14 @@ void debugCommand(redisClient *c) {
 }
 
 void _redisAssert(char *estr, char *file, int line) {
+    bugReportStart();
     redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
     redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
 #ifdef HAVE_BACKTRACE
-    redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
+    server.assert_failed = estr;
+    server.assert_file = file;
+    server.assert_line = line;
+    redisLog(REDIS_WARNING,"(forcing SIGSEGV to print the bug report.)");
     *((char*)-1) = 'x';
 #endif
 }
@@ -308,6 +312,7 @@ void _redisAssert(char *estr, char *file, int line) {
 void _redisAssertPrintClientInfo(redisClient *c) {
     int j;
 
+    bugReportStart();
     redisLog(REDIS_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
     redisLog(REDIS_WARNING,"client->flags = %d", c->flags);
     redisLog(REDIS_WARNING,"client->fd = %d", c->fd);
@@ -331,6 +336,7 @@ void _redisAssertPrintClientInfo(redisClient *c) {
 }
 
 void _redisAssertPrintObject(robj *o) {
+    bugReportStart();
     redisLog(REDIS_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
     redisLog(REDIS_WARNING,"Object type: %d", o->type);
     redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
@@ -349,6 +355,7 @@ void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int l
 }
 
 void _redisPanic(char *msg, char *file, int line) {
+    bugReportStart();
     redisLog(REDIS_WARNING,"------------------------------------------------");
     redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
     redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
index 44036256da50859bc5c2f3bd89709dde7d52b346..5c88340055ce6104171ac3e33febb0105c6ad7b8 100644 (file)
@@ -57,7 +57,7 @@ void discardCommand(redisClient *c) {
 
     freeClientMultiState(c);
     initClientMultiState(c);
-    c->flags &= (~REDIS_MULTI);
+    c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS);;
     unwatchAllKeys(c);
     addReply(c,shared.ok);
 }
index c9286195c3fa05d57a4a8a9002e4f67977b38c4f..f0da4010fe43a109461217eefa2baa76db2ec311 100644 (file)
@@ -36,7 +36,7 @@ redisClient *createClient(int fd) {
     c->reqtype = 0;
     c->argc = 0;
     c->argv = NULL;
-    c->cmd = NULL;
+    c->cmd = c->lastcmd = NULL;
     c->multibulklen = 0;
     c->bulklen = -1;
     c->sentlen = 0;
@@ -695,6 +695,12 @@ int processInlineBuffer(redisClient *c) {
 /* Helper function. Trims query buffer to make the function that processes
  * multi bulk requests idempotent. */
 static void setProtocolError(redisClient *c, int pos) {
+    if (server.verbosity >= REDIS_VERBOSE) {
+        sds client = getClientInfoString(c);
+        redisLog(REDIS_VERBOSE,
+            "Protocol error from client: %s", client);
+        sdsfree(client);
+    }
     c->flags |= REDIS_CLOSE_AFTER_REPLY;
     c->querybuf = sdsrange(c->querybuf,pos,-1);
 }
@@ -966,7 +972,7 @@ sds getClientInfoString(redisClient *client) {
     if (emask & AE_WRITABLE) *p++ = 'w';
     *p = '\0';
     return sdscatprintf(sdsempty(),
-        "addr=%s:%d fd=%d idle=%ld flags=%s db=%d sub=%d psub=%d qbuf=%lu obl=%lu oll=%lu events=%s",
+        "addr=%s:%d fd=%d idle=%ld flags=%s db=%d sub=%d psub=%d qbuf=%lu obl=%lu oll=%lu events=%s cmd=%s",
         ip,port,client->fd,
         (long)(now - client->lastinteraction),
         flags,
@@ -976,7 +982,23 @@ sds getClientInfoString(redisClient *client) {
         (unsigned long) sdslen(client->querybuf),
         (unsigned long) client->bufpos,
         (unsigned long) listLength(client->reply),
-        events);
+        events,
+        client->lastcmd ? client->lastcmd->name : "NULL");
+}
+
+sds getAllClientsInfoString(void) {
+    listNode *ln;
+    listIter li;
+    redisClient *client;
+    sds o = sdsempty();
+
+    listRewind(server.clients,&li);
+    while ((ln = listNext(&li)) != NULL) {
+        client = listNodeValue(ln);
+        o = sdscatsds(o,getClientInfoString(client));
+        o = sdscatlen(o,"\n",1);
+    }
+    return o;
 }
 
 void clientCommand(redisClient *c) {
@@ -985,14 +1007,7 @@ void clientCommand(redisClient *c) {
     redisClient *client;
 
     if (!strcasecmp(c->argv[1]->ptr,"list") && c->argc == 2) {
-        sds o = sdsempty();
-
-        listRewind(server.clients,&li);
-        while ((ln = listNext(&li)) != NULL) {
-            client = listNodeValue(ln);
-            o = sdscatsds(o,getClientInfoString(client));
-            o = sdscatlen(o,"\n",1);
-        }
+        sds o = getAllClientsInfoString();
         addReplyBulkCBuffer(c,o,sdslen(o));
         sdsfree(o);
     } else if (!strcasecmp(c->argv[1]->ptr,"kill") && c->argc == 3) {
index a4eb508091bc0559368e9e40d6b5a6df382cd677..735de9d650897c9b6fc161e7b6d6e87298e45ea2 100644 (file)
@@ -946,6 +946,12 @@ void initServerConfig() {
     /* Slow log */
     server.slowlog_log_slower_than = REDIS_SLOWLOG_LOG_SLOWER_THAN;
     server.slowlog_max_len = REDIS_SLOWLOG_MAX_LEN;
+
+    /* Assert */
+    server.assert_failed = "<no assertion failed>";
+    server.assert_file = "<no file>";
+    server.assert_line = 0;
+    server.bug_report_start = 0;
 }
 
 void initServer() {
@@ -1174,7 +1180,7 @@ int processCommand(redisClient *c) {
 
     /* Now lookup the command and check ASAP about trivial error conditions
      * such as wrong arity, bad command name and so forth. */
-    c->cmd = lookupCommand(c->argv[0]->ptr);
+    c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);
     if (!c->cmd) {
         addReplyErrorFormat(c,"unknown command '%s'",
             (char*)c->argv[0]->ptr);
@@ -1946,32 +1952,56 @@ static void *getMcontextEip(ucontext_t *uc) {
 #endif
 }
 
+void bugReportStart(void) {
+    if (server.bug_report_start == 0) {
+        redisLog(REDIS_WARNING,
+            "=== REDIS BUG REPORT START: Cut & paste starting from here ===");
+        server.bug_report_start = 1;
+    }
+}
+
 static void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
     void *trace[100];
     char **messages = NULL;
     int i, trace_size = 0;
     ucontext_t *uc = (ucontext_t*) secret;
-    sds infostring;
+    sds infostring, clients;
     struct sigaction act;
     REDIS_NOTUSED(info);
 
+    bugReportStart();
     redisLog(REDIS_WARNING,
-        "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
-    infostring = genRedisInfoString("all");
-    redisLogRaw(REDIS_WARNING, infostring);
-    /* It's not safe to sdsfree() the returned string under memory
-     * corruption conditions. Let it leak as we are going to abort */
+        "    Redis %s crashed by signal: %d", REDIS_VERSION, sig);
+    redisLog(REDIS_WARNING,
+        "    Failed assertion: %s (%s:%d)", server.assert_failed,
+                        server.assert_file, server.assert_line);
 
+    /* Generate the stack trace */
     trace_size = backtrace(trace, 100);
+
     /* overwrite sigaction with caller's address */
     if (getMcontextEip(uc) != NULL) {
         trace[1] = getMcontextEip(uc);
     }
     messages = backtrace_symbols(trace, trace_size);
-
+    redisLog(REDIS_WARNING, "--- STACK TRACE");
     for (i=1; i<trace_size; ++i)
         redisLog(REDIS_WARNING,"%s", messages[i]);
 
+    /* Log INFO and CLIENT LIST */
+    redisLog(REDIS_WARNING, "--- INFO OUTPUT");
+    infostring = genRedisInfoString("all");
+    redisLogRaw(REDIS_WARNING, infostring);
+    redisLog(REDIS_WARNING, "--- CLIENT LIST OUTPUT");
+    clients = getAllClientsInfoString();
+    redisLogRaw(REDIS_WARNING, clients);
+    /* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */
+
+    redisLog(REDIS_WARNING,
+"=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
+"    Please report the crash opening an issue on github:\n\n"
+"        http://github.com/antirez/redis/issues\n\n"
+);
     /* free(messages); Don't call free() with possibly corrupted memory. */
     if (server.daemonize) unlink(server.pidfile);
 
index 4a2f6e1e5f4d561a4fcb6942116f9f2051ef93e4..431eeb1404b16487a35631ac54381c333ed2b1ec 100644 (file)
@@ -294,7 +294,7 @@ typedef struct redisClient {
     sds querybuf;
     int argc;
     robj **argv;
-    struct redisCommand *cmd;
+    struct redisCommand *cmd, *lastcmd;
     int reqtype;
     int multibulklen;       /* number of multi bulk arguments left to read */
     long bulklen;           /* length of bulk argument in multi bulk request */
@@ -634,6 +634,11 @@ struct redisServer {
     int lua_timedout;     /* True if we reached the time limit for script
                              execution. */
     int lua_kill;         /* Kill the script if true. */
+    /* Assert & bug reportign */
+    char *assert_failed;
+    char *assert_file;
+    int assert_line;
+    int bug_report_start; /* True if bug report header already logged. */
 };
 
 typedef struct pubsubPattern {
@@ -769,6 +774,7 @@ void *dupClientReplyValue(void *o);
 void getClientsMaxBuffers(unsigned long *longest_output_list,
                           unsigned long *biggest_input_buffer);
 sds getClientInfoString(redisClient *client);
+sds getAllClientsInfoString(void);
 void rewriteClientCommandVector(redisClient *c, int argc, ...);
 void rewriteClientCommandArgument(redisClient *c, int i, robj *newval);
 
@@ -1147,5 +1153,6 @@ void *realloc(void *ptr, size_t size) __attribute__ ((deprecated));
 void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int line);
 void _redisAssert(char *estr, char *file, int line);
 void _redisPanic(char *msg, char *file, int line);
+void bugReportStart(void);
 
 #endif
index d420d9e29fbe8a9cf73f092fe43c4f0bb456bfae..082fba3535815102f0a0bb6ac0022b48219b91f0 100644 (file)
@@ -125,11 +125,32 @@ start_server {tags {"cas"}} {
     test {WATCH will not consider touched expired keys} {
         r del x
         r set x foo
-        r expire x 2
+        r expire x 1
         r watch x
-        after 3000
+        after 1100
         r multi
         r ping
         r exec
     } {PONG}
+
+    test {DISCARD should clear the WATCH dirty flag on the client} {
+        r watch x
+        r set x 10
+        r multi
+        r discard
+        r multi
+        r incr x
+        r exec
+    } {11}
+
+    test {DISCARD should UNWATCH all the keys} {
+        r watch x
+        r set x 10
+        r multi
+        r discard
+        r set x 10
+        r multi
+        r incr x
+        r exec
+    } {11}
 }