Make a light weight version of DEBUG OBJECT, add FAST option (#881)

Adding FAST option to DEBUG OBJECT command.

The light version only shows the light weight infomation,
which mostly O(1). The pre-existing version that show more
stats such as serializedlength sometimes is time consuming.

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.

Somehow like 3ca451c46fed894bf49e7561fa0282d2583f1c06.

Signed-off-by: Binbin <binloveplay1314@qq.com>
This commit is contained in:
Binbin 2024-08-16 10:18:36 +08:00 committed by GitHub
parent 76ad8f7a76
commit fc9f291033
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -425,8 +425,10 @@ void debugCommand(client *c) {
"MALLCTL-STR <key> [<val>]",
" Get or set a malloc tuning string.",
#endif
"OBJECT <key>",
"OBJECT <key> [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 <packet-type>",
" Drop all packets that match the filtered type. Set to -1 allow all packets.",
"CLOSE-CLUSTER-LINK-ON-PACKET-DROP <0|1>",
@ -603,11 +605,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 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);
return;
@ -638,22 +643,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 (!fast) {
/* 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 (!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));
sdsfree(s);
} else if (!strcasecmp(c->argv[1]->ptr, "sdslen") && c->argc == 3) {
dictEntry *de;
robj *val;