From 5753a85d7376bbda1683a760a860d565670e7da1 Mon Sep 17 00:00:00 2001 From: Binbin Date: Fri, 9 Aug 2024 11:33:01 +0800 Subject: [PATCH 1/2] Make a light weight version (default) of DEBUG OBJECT The light version only shows the light weight infomation, which mostly O(1). The pre-existing version that show more stats such as serializedlength is reachable with the `full` argument. This should allow looking into debug stats (the key expired but not deleted), even on huge object, on which we're afraid to run the command for fear of causing a server freeze. Like 3ca451c46fed894bf49e7561fa0282d2583f1c06. Signed-off-by: Binbin --- src/debug.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/debug.c b/src/debug.c index 27bc481767..edae6b6cbb 100644 --- a/src/debug.c +++ b/src/debug.c @@ -426,7 +426,7 @@ void debugCommand(client *c) { "MALLCTL-STR []", " Get or set a malloc tuning string.", #endif - "OBJECT ", + "OBJECT [full]", " Show low level info about `key` and associated value.", "DROP-CLUSTER-PACKET-FILTER ", " Drop all packets that match the filtered type. Set to -1 allow all packets.", @@ -604,11 +604,14 @@ void debugCommand(client *c) { } else if (!strcasecmp(c->argv[1]->ptr, "close-cluster-link-on-packet-drop") && c->argc == 3) { server.debug_cluster_close_link_on_packet_drop = atoi(c->argv[2]->ptr); addReply(c, shared.ok); - } else if (!strcasecmp(c->argv[1]->ptr, "object") && c->argc == 3) { + } else if (!strcasecmp(c->argv[1]->ptr, "object") && (c->argc == 3 || c->argc == 4)) { dictEntry *de; robj *val; char *strenc; + int full = 0; + if (c->argc == 4 && !strcasecmp(c->argv[3]->ptr, "full")) full = 1; + if ((de = dbFind(c->db, c->argv[2]->ptr)) == NULL) { addReplyErrorObject(c, shared.nokeyerr); return; @@ -639,22 +642,25 @@ void debugCommand(client *c) { used = snprintf(nextra, remaining, " ql_compressed:%d", compressed); nextra += used; remaining -= used; - /* Add total uncompressed size */ - unsigned long sz = 0; - for (quicklistNode *node = ql->head; node; node = node->next) { - sz += node->sz; + if (full) { + /* Add total uncompressed size */ + unsigned long sz = 0; + for (quicklistNode *node = ql->head; node; node = node->next) { + sz += node->sz; + } + used = snprintf(nextra, remaining, " ql_uncompressed_size:%lu", sz); + nextra += used; + remaining -= used; } - used = snprintf(nextra, remaining, " ql_uncompressed_size:%lu", sz); - nextra += used; - remaining -= used; } - addReplyStatusFormat(c, - "Value at:%p refcount:%d " - "encoding:%s serializedlength:%zu " - "lru:%d lru_seconds_idle:%llu%s", - (void *)val, val->refcount, strenc, rdbSavedObjectLen(val, c->argv[2], c->db->id), - val->lru, estimateObjectIdleTime(val) / 1000, extra); + sds s = sdsempty(); + s = sdscatprintf(s, "Value at:%p refcount:%d encoding:%s", (void *)val, val->refcount, strenc); + if (full) s = sdscatprintf(s, " serializedlength:%zu", rdbSavedObjectLen(val, c->argv[2], c->db->id)); + s = sdscatprintf(s, " lru:%d lru_seconds_idle:%llu", val->lru, estimateObjectIdleTime(val) / 1000); + s = sdscatprintf(s, "%s", extra); + addReplyStatusLength(c, s, sdslen(s)); + sdsfree(s); } else if (!strcasecmp(c->argv[1]->ptr, "sdslen") && c->argc == 3) { dictEntry *de; robj *val; From 23fcddd50c9aca4a387179ae9a43a140b223fa9e Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 14 Aug 2024 11:23:14 +0800 Subject: [PATCH 2/2] Add debug object fast Signed-off-by: Binbin --- src/debug.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/debug.c b/src/debug.c index edae6b6cbb..4bd560e040 100644 --- a/src/debug.c +++ b/src/debug.c @@ -426,8 +426,10 @@ void debugCommand(client *c) { "MALLCTL-STR []", " Get or set a malloc tuning string.", #endif - "OBJECT [full]", + "OBJECT [fast]", " Show low level info about `key` and associated value.", + " Some fields of the default behavior may be time consuming to fetch,", + " and `fast` can be passed to avoid fetching them.", "DROP-CLUSTER-PACKET-FILTER ", " Drop all packets that match the filtered type. Set to -1 allow all packets.", "CLOSE-CLUSTER-LINK-ON-PACKET-DROP <0|1>", @@ -609,8 +611,8 @@ void debugCommand(client *c) { robj *val; char *strenc; - int full = 0; - if (c->argc == 4 && !strcasecmp(c->argv[3]->ptr, "full")) full = 1; + int fast = 0; + if (c->argc == 4 && !strcasecmp(c->argv[3]->ptr, "fast")) fast = 1; if ((de = dbFind(c->db, c->argv[2]->ptr)) == NULL) { addReplyErrorObject(c, shared.nokeyerr); @@ -642,7 +644,7 @@ void debugCommand(client *c) { used = snprintf(nextra, remaining, " ql_compressed:%d", compressed); nextra += used; remaining -= used; - if (full) { + if (!fast) { /* Add total uncompressed size */ unsigned long sz = 0; for (quicklistNode *node = ql->head; node; node = node->next) { @@ -656,7 +658,7 @@ void debugCommand(client *c) { sds s = sdsempty(); s = sdscatprintf(s, "Value at:%p refcount:%d encoding:%s", (void *)val, val->refcount, strenc); - if (full) s = sdscatprintf(s, " serializedlength:%zu", rdbSavedObjectLen(val, c->argv[2], c->db->id)); + if (!fast) s = sdscatprintf(s, " serializedlength:%zu", rdbSavedObjectLen(val, c->argv[2], c->db->id)); s = sdscatprintf(s, " lru:%d lru_seconds_idle:%llu", val->lru, estimateObjectIdleTime(val) / 1000); s = sdscatprintf(s, "%s", extra); addReplyStatusLength(c, s, sdslen(s));