Commit 00010fa9 authored by antirez's avatar antirez
Browse files

On crash print information about the current client (if any), command vector,...

On crash print information about the current client (if any), command vector, and object associated to first argument assuming it is a key.
parent d8bd12f9
...@@ -336,9 +336,7 @@ void _redisAssertPrintClientInfo(redisClient *c) { ...@@ -336,9 +336,7 @@ void _redisAssertPrintClientInfo(redisClient *c) {
} }
} }
void _redisAssertPrintObject(robj *o) { void redisLogObjectDebugInfo(robj *o) {
bugReportStart();
redisLog(REDIS_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
redisLog(REDIS_WARNING,"Object type: %d", o->type); redisLog(REDIS_WARNING,"Object type: %d", o->type);
redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding); redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount); redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount);
...@@ -346,9 +344,25 @@ void _redisAssertPrintObject(robj *o) { ...@@ -346,9 +344,25 @@ void _redisAssertPrintObject(robj *o) {
redisLog(REDIS_WARNING,"Object raw string len: %d", sdslen(o->ptr)); redisLog(REDIS_WARNING,"Object raw string len: %d", sdslen(o->ptr));
if (sdslen(o->ptr) < 4096) if (sdslen(o->ptr) < 4096)
redisLog(REDIS_WARNING,"Object raw string content: \"%s\"", (char*)o->ptr); 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 _redisAssertPrintObject(robj *o) {
bugReportStart();
redisLog(REDIS_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
redisLogObjectDebugInfo(o);
}
void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int line) { void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int line) {
if (c) _redisAssertPrintClientInfo(c); if (c) _redisAssertPrintClientInfo(c);
if (o) _redisAssertPrintObject(o); if (o) _redisAssertPrintObject(o);
......
...@@ -481,6 +481,9 @@ static void freeClientArgv(redisClient *c) { ...@@ -481,6 +481,9 @@ static void freeClientArgv(redisClient *c) {
void freeClient(redisClient *c) { void freeClient(redisClient *c) {
listNode *ln; 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 /* Note that if the client we are freeing is blocked into a blocking
* call, we have to set querybuf to NULL *before* to call * call, we have to set querybuf to NULL *before* to call
* unblockClientWaitingData() to avoid processInputBuffer() will get * unblockClientWaitingData() to avoid processInputBuffer() will get
...@@ -900,6 +903,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { ...@@ -900,6 +903,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
REDIS_NOTUSED(el); REDIS_NOTUSED(el);
REDIS_NOTUSED(mask); REDIS_NOTUSED(mask);
server.current_client = c;
readlen = REDIS_IOBUF_LEN; readlen = REDIS_IOBUF_LEN;
/* If this is a multi bulk request, and we are processing a bulk reply /* If this is a multi bulk request, and we are processing a bulk reply
* that is large enough, try to maximize the probabilty that the query * that is large enough, try to maximize the probabilty that the query
...@@ -935,6 +939,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { ...@@ -935,6 +939,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
sdsIncrLen(c->querybuf,nread); sdsIncrLen(c->querybuf,nread);
c->lastinteraction = time(NULL); c->lastinteraction = time(NULL);
} else { } else {
server.current_client = NULL;
return; return;
} }
if (sdslen(c->querybuf) > server.client_max_querybuf_len) { if (sdslen(c->querybuf) > server.client_max_querybuf_len) {
...@@ -948,6 +953,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { ...@@ -948,6 +953,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return; return;
} }
processInputBuffer(c); processInputBuffer(c);
server.current_client = NULL;
} }
void getClientsMaxBuffers(unsigned long *longest_output_list, void getClientsMaxBuffers(unsigned long *longest_output_list,
......
...@@ -787,8 +787,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) { ...@@ -787,8 +787,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
c->flags &= ~REDIS_UNBLOCKED; c->flags &= ~REDIS_UNBLOCKED;
/* Process remaining data in the input buffer. */ /* Process remaining data in the input buffer. */
if (c->querybuf && sdslen(c->querybuf) > 0) if (c->querybuf && sdslen(c->querybuf) > 0) {
server.current_client = c;
processInputBuffer(c); processInputBuffer(c);
server.current_client = NULL;
}
} }
/* Write the AOF buffer on disk */ /* Write the AOF buffer on disk */
...@@ -1002,6 +1005,7 @@ void initServer() { ...@@ -1002,6 +1005,7 @@ void initServer() {
server.syslog_facility); server.syslog_facility);
} }
server.current_client = NULL;
server.clients = listCreate(); server.clients = listCreate();
server.slaves = listCreate(); server.slaves = listCreate();
server.monitors = listCreate(); server.monitors = listCreate();
...@@ -2005,6 +2009,40 @@ static void sigsegvHandler(int sig, siginfo_t *info, void *secret) { ...@@ -2005,6 +2009,40 @@ static void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
redisLogRaw(REDIS_WARNING, clients); redisLogRaw(REDIS_WARNING, clients);
/* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */ /* 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 = dictGetVal(de);
redisLog(REDIS_WARNING,"key '%s' found in DB containing the following object:", key->ptr);
redisLogObjectDebugInfo(val);
}
decrRefCount(key);
}
}
redisLog(REDIS_WARNING, redisLog(REDIS_WARNING,
"=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n" "=== 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" " Please report the crash opening an issue on github:\n\n"
......
...@@ -519,6 +519,7 @@ struct redisServer { ...@@ -519,6 +519,7 @@ struct redisServer {
int cfd; /* Cluster bus lisetning socket */ int cfd; /* Cluster bus lisetning socket */
list *clients; /* List of active clients */ list *clients; /* List of active clients */
list *slaves, *monitors; /* List of slaves and MONITORs */ list *slaves, *monitors; /* List of slaves and MONITORs */
redisClient *current_client; /* Current client, only used on crash report */
char neterr[ANET_ERR_LEN]; /* Error buffer for anet.c */ char neterr[ANET_ERR_LEN]; /* Error buffer for anet.c */
/* RDB / AOF loading information */ /* RDB / AOF loading information */
int loading; /* We are loading data from disk if true */ int loading; /* We are loading data from disk if true */
...@@ -1159,5 +1160,6 @@ void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int l ...@@ -1159,5 +1160,6 @@ void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int l
void _redisAssert(char *estr, char *file, int line); void _redisAssert(char *estr, char *file, int line);
void _redisPanic(char *msg, char *file, int line); void _redisPanic(char *msg, char *file, int line);
void bugReportStart(void); void bugReportStart(void);
void redisLogObjectDebugInfo(robj *o);
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment