On crash print information about the current client (if any), command vector, and object associated to first argument assuming it is a key.

This commit is contained in:
antirez 2012-01-12 16:02:57 +01:00
parent d8bd12f984
commit 00010fa96f
4 changed files with 64 additions and 4 deletions

View File

@ -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) {
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);

View File

@ -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) {
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) {
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) {
return; return;
} }
processInputBuffer(c); processInputBuffer(c);
server.current_client = NULL;
} }
void getClientsMaxBuffers(unsigned long *longest_output_list, void getClientsMaxBuffers(unsigned long *longest_output_list,

View File

@ -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() {
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) {
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"

View File

@ -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
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