From ee789e157c767be9cbf90af5232bfeacc533e308 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 11 Jun 2012 23:44:34 +0200 Subject: [PATCH] Dump ziplist hex value on failed assertion. The ziplist -> hashtable conversion code is triggered every time an hash value must be promoted to a full hash table because the number or size of elements reached the threshold. If a problem in the ziplist causes the same field to be present multiple times, the assertion of successful addition of the element inside the hash table will fail, crashing server with a failed assertion, but providing little information about the problem. This code adds a new logging function to perform the hex dump of binary data, and makes sure that the ziplist -> hashtable conversion code uses this new logging facility to dump the content of the ziplist when the assertion fails. This change was originally made in order to investigate issue #547. --- src/debug.c | 24 ++++++++++++++++++++++++ src/redis.h | 1 + src/t_hash.c | 6 +++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/debug.c b/src/debug.c index 4687fb6c..e5686288 100644 --- a/src/debug.c +++ b/src/debug.c @@ -686,6 +686,30 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) { } #endif /* HAVE_BACKTRACE */ +/* ==================== Logging functions for debugging ===================== */ + +void redisLogHexDump(int level, char *descr, void *value, size_t len) { + char buf[65], *b; + unsigned char *v = value; + char charset[] = "0123456789abcdef"; + + redisLog(level,"%s (hexdump):", descr); + b = buf; + while(len) { + b[0] = charset[(*v)>>4]; + b[1] = charset[(*v)&0xf]; + b[2] = '\0'; + b += 2; + len--; + v++; + if (b-buf == 64 || len == 0) { + redisLogRaw(level|REDIS_LOG_RAW,buf); + b = buf; + } + } + redisLogRaw(level|REDIS_LOG_RAW,"\n"); +} + /* =========================== Software Watchdog ============================ */ #include diff --git a/src/redis.h b/src/redis.h index 273fc241..4ce5311b 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1274,4 +1274,5 @@ sds genRedisInfoString(char *section); void enableWatchdog(int period); void disableWatchdog(void); void watchdogScheduleSignal(int period); +void redisLogHexDump(int level, char *descr, void *value, size_t len); #endif diff --git a/src/t_hash.c b/src/t_hash.c index 5b7a347a..aa021b03 100644 --- a/src/t_hash.c +++ b/src/t_hash.c @@ -403,7 +403,11 @@ void hashTypeConvertZiplist(robj *o, int enc) { value = hashTypeCurrentObject(hi, REDIS_HASH_VALUE); value = tryObjectEncoding(value); ret = dictAdd(dict, field, value); - redisAssert(ret == DICT_OK); + if (ret != DICT_OK) { + redisLogHexDump(REDIS_WARNING,"ziplist with dup elements dump", + o->ptr,ziplistBlobLen(o->ptr)); + redisAssert(ret == DICT_OK); + } } hashTypeReleaseIterator(hi);