From ac61f9062583d67dd43f7d698824464d1e30d84b Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 16 Dec 2016 09:02:50 +0100 Subject: [PATCH] DEBUG: new "ziplist" subcommand added. Dumps a ziplist on stdout. The commit improves ziplistRepr() and adds a new debugging subcommand so that we can trigger the dump directly from the Redis API. This command capability was used while investigating issue #3684. --- src/debug.c | 14 ++++++++++++++ src/server.h | 2 ++ src/ziplist.c | 31 ++++++++++++++++++------------- src/ziplist.h | 1 + 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/debug.c b/src/debug.c index f4689d532..b8ad4e511 100644 --- a/src/debug.c +++ b/src/debug.c @@ -280,6 +280,8 @@ void debugCommand(client *c) { blen++; addReplyStatus(c, "sdslen -- Show low level SDS string info representing key and value."); blen++; addReplyStatus(c, + "ziplist -- Show low level info about the ziplist encoding."); + blen++; addReplyStatus(c, "populate [prefix] -- Create string keys named key:. If a prefix is specified is used instead of the 'key' prefix."); blen++; addReplyStatus(c, "digest -- Outputs an hex signature representing the current DB content."); @@ -418,6 +420,18 @@ void debugCommand(client *c) { (long long) sdsavail(val->ptr), (long long) getStringObjectSdsUsedMemory(val)); } + } else if (!strcasecmp(c->argv[1]->ptr,"ziplist") && c->argc == 3) { + robj *o; + + if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr)) + == NULL) return; + + if (o->encoding != OBJ_ENCODING_ZIPLIST) { + addReplyError(c,"Not an sds encoded string."); + } else { + ziplistRepr(o->ptr); + addReplyStatus(c,"Ziplist structure printed on stdout"); + } } else if (!strcasecmp(c->argv[1]->ptr,"populate") && (c->argc == 3 || c->argc == 4)) { long keys, j; diff --git a/src/server.h b/src/server.h index 2a61ea419..7ff151de8 100644 --- a/src/server.h +++ b/src/server.h @@ -1655,6 +1655,8 @@ robj *lookupKeyWrite(redisDb *db, robj *key); robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply); robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply); robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags); +robj *objectCommandLookup(client *c, robj *key); +robj *objectCommandLookupOrReply(client *c, robj *key, robj *reply); #define LOOKUP_NONE 0 #define LOOKUP_NOTOUCH (1<<0) void dbAdd(redisDb *db, robj *key, robj *val); diff --git a/src/ziplist.c b/src/ziplist.c index 7428d30e9..f7d7877f7 100644 --- a/src/ziplist.c +++ b/src/ziplist.c @@ -1029,7 +1029,7 @@ void ziplistRepr(unsigned char *zl) { printf( "{total bytes %d} " - "{length %u}\n" + "{num entries %u}\n" "{tail offset %u}\n", intrev32ifbe(ZIPLIST_BYTES(zl)), intrev16ifbe(ZIPLIST_LENGTH(zl)), @@ -1038,16 +1038,15 @@ void ziplistRepr(unsigned char *zl) { while(*p != ZIP_END) { zipEntry(p, &entry); printf( - "{" - "addr 0x%08lx, " - "index %2d, " - "offset %5ld, " - "rl: %5u, " - "hs %2u, " - "pl: %5u, " - "pls: %2u, " - "payload %5u" - "} ", + "{\n" + "\taddr 0x%08lx,\n" + "\tindex %2d,\n" + "\toffset %5ld,\n" + "\thdr+entry len: %5u,\n" + "\thdr len%2u,\n" + "\tprevrawlen: %5u,\n" + "\tprevrawlensize: %2u,\n" + "\tpayload %5u\n", (long unsigned)p, index, (unsigned long) (p-zl), @@ -1056,8 +1055,14 @@ void ziplistRepr(unsigned char *zl) { entry.prevrawlen, entry.prevrawlensize, entry.len); + printf("\tbytes: "); + for (unsigned int i = 0; i < entry.headersize+entry.len; i++) { + printf("%02x|",p[i]); + } + printf("\n"); p += entry.headersize; if (ZIP_IS_STR(entry.encoding)) { + printf("\t[str]"); if (entry.len > 40) { if (fwrite(p,40,1,stdout) == 0) perror("fwrite"); printf("..."); @@ -1066,9 +1071,9 @@ void ziplistRepr(unsigned char *zl) { fwrite(p,entry.len,1,stdout) == 0) perror("fwrite"); } } else { - printf("%lld", (long long) zipLoadInteger(p,entry.encoding)); + printf("\t[int]%lld", (long long) zipLoadInteger(p,entry.encoding)); } - printf("\n"); + printf("\n}\n"); p += entry.len; index++; } diff --git a/src/ziplist.h b/src/ziplist.h index ae96823f9..964a47f6d 100644 --- a/src/ziplist.h +++ b/src/ziplist.h @@ -48,6 +48,7 @@ unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int sle unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip); unsigned int ziplistLen(unsigned char *zl); size_t ziplistBlobLen(unsigned char *zl); +void ziplistRepr(unsigned char *zl); #ifdef REDIS_TEST int ziplistTest(int argc, char *argv[]);