summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2012-01-12 16:02:57 +0100
committerantirez <antirez@gmail.com>2012-01-12 16:16:23 +0100
commitfbfe656236ac5cd96b25a71d4aa393b6816ac8b2 (patch)
tree39f770920018d3fa77abb7d578791be2483ec6f2
parente1849b6456bfd09b259292d8cbe2b508efc2c1a2 (diff)
downloadredis-fbfe656236ac5cd96b25a71d4aa393b6816ac8b2.tar.gz
On crash print information about the current client (if any), command vector, and object associated to first argument assuming it is a key.
-rw-r--r--src/debug.c21
-rw-r--r--src/networking.c6
-rw-r--r--src/redis.c40
-rw-r--r--src/redis.h3
4 files changed, 69 insertions, 1 deletions
diff --git a/src/debug.c b/src/debug.c
index 4d34f62a5..123edb735 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -337,6 +337,27 @@ void debugCommand(redisClient *c) {
}
}
+void redisLogObjectDebugInfo(robj *o) {
+ redisLog(REDIS_WARNING,"Object type: %d", o->type);
+ redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
+ redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount);
+ if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_RAW) {
+ redisLog(REDIS_WARNING,"Object raw string len: %d", sdslen(o->ptr));
+ if (sdslen(o->ptr) < 4096)
+ redisLog(REDIS_WARNING,"Object raw string content: \"%s\"", (char*)o->ptr);
+ } else if (o->type == REDIS_LIST) {
+ redisLog(REDIS_WARNING,"List length: %d", (int) listTypeLength(o));
+ } else if (o->type == REDIS_SET) {
+ redisLog(REDIS_WARNING,"Set size: %d", (int) setTypeSize(o));
+ } else if (o->type == REDIS_HASH) {
+ redisLog(REDIS_WARNING,"Hash size: %d", (int) hashTypeLength(o));
+ } else if (o->type == REDIS_ZSET) {
+ redisLog(REDIS_WARNING,"Sorted set size: %d", (int) zsetLength(o));
+ if (o->encoding == REDIS_ENCODING_SKIPLIST)
+ redisLog(REDIS_WARNING,"Skiplist level: %d", (int) ((zset*)o->ptr)->zsl->level);
+ }
+}
+
void _redisAssert(char *estr, char *file, int line) {
bugReportStart();
redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
diff --git a/src/networking.c b/src/networking.c
index 811853877..b48927df7 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -467,6 +467,9 @@ static void freeClientArgv(redisClient *c) {
void freeClient(redisClient *c) {
listNode *ln;
+ /* If this is marked as current client unset it */
+ if (server.current_client == c) server.current_client = NULL;
+
/* Note that if the client we are freeing is blocked into a blocking
* call, we have to set querybuf to NULL *before* to call
* unblockClientWaitingData() to avoid processInputBuffer() will get
@@ -875,6 +878,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
+ server.current_client = c;
nread = read(fd, buf, REDIS_IOBUF_LEN);
if (nread == -1) {
if (errno == EAGAIN) {
@@ -893,6 +897,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
c->querybuf = sdscatlen(c->querybuf,buf,nread);
c->lastinteraction = time(NULL);
} else {
+ server.current_client = NULL;
return;
}
if (sdslen(c->querybuf) > server.client_max_querybuf_len) {
@@ -906,6 +911,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return;
}
processInputBuffer(c);
+ server.current_client = NULL;
}
void getClientsMaxBuffers(unsigned long *longest_output_list,
diff --git a/src/redis.c b/src/redis.c
index d4a9a30d9..34b3d418e 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -716,8 +716,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
call(c);
resetClient(c);
/* There may be more data to process in the input buffer. */
- if (c->querybuf && sdslen(c->querybuf) > 0)
+ if (c->querybuf && sdslen(c->querybuf) > 0) {
+ server.current_client = c;
processInputBuffer(c);
+ server.current_client = NULL;
+ }
}
}
@@ -907,6 +910,7 @@ void initServer() {
}
server.mainthread = pthread_self();
+ server.current_client = NULL;
server.clients = listCreate();
server.slaves = listCreate();
server.monitors = listCreate();
@@ -1797,6 +1801,40 @@ static void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
redisLog(REDIS_WARNING, clients);
/* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */
+ /* Log CURRENT CLIENT info */
+ if (server.current_client) {
+ redisClient *cc = server.current_client;
+ sds client;
+ int j;
+
+ redisLog(REDIS_WARNING, "--- CURRENT CLIENT INFO");
+ client = getClientInfoString(cc);
+ redisLog(REDIS_WARNING,"client: %s", client);
+ /* Missing sdsfree(client) to avoid crash if memory is corrupted. */
+ for (j = 0; j < cc->argc; j++) {
+ robj *decoded;
+
+ decoded = getDecodedObject(cc->argv[j]);
+ redisLog(REDIS_WARNING,"argv[%d]: '%s'", j, (char*)decoded->ptr);
+ decrRefCount(decoded);
+ }
+ /* Check if the first argument, usually a key, is found inside the
+ * selected DB, and if so print info about the associated object. */
+ if (cc->argc >= 1) {
+ robj *val, *key;
+ dictEntry *de;
+
+ key = getDecodedObject(cc->argv[1]);
+ de = dictFind(cc->db->dict, key->ptr);
+ if (de) {
+ val = dictGetEntryVal(de);
+ redisLog(REDIS_WARNING,"key '%s' found in DB containing the following object:", key->ptr);
+ redisLogObjectDebugInfo(val);
+ }
+ decrRefCount(key);
+ }
+ }
+
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"
diff --git a/src/redis.h b/src/redis.h
index aca45ae8c..8a89bf00a 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -400,6 +400,7 @@ struct redisServer {
/* Fast pointers to often looked up command */
struct redisCommand *delCommand, *multiCommand;
list *slaves, *monitors;
+ redisClient *current_client; /* Current client, only used on crash report */
char neterr[ANET_ERR_LEN];
aeEventLoop *el;
int cronloops; /* number of times the cron function run */
@@ -1072,4 +1073,6 @@ void *malloc(size_t size) __attribute__ ((deprecated));
void *realloc(void *ptr, size_t size) __attribute__ ((deprecated));
#endif
+void redisLogObjectDebugInfo(robj *o);
+
#endif