Commit fbfe6562 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 e1849b64
......@@ -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 ===");
......
......@@ -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,
......
......@@ -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"
......
......@@ -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
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