diff options
Diffstat (limited to 'src/redis-cli.c')
-rw-r--r-- | src/redis-cli.c | 140 |
1 files changed, 82 insertions, 58 deletions
diff --git a/src/redis-cli.c b/src/redis-cli.c index c82720dd6..11cefdf47 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1335,81 +1335,105 @@ static void pipeMode(void) { static void findBigKeys(void) { unsigned long long biggest[5] = {0,0,0,0,0}; unsigned long long samples = 0; - redisReply *reply1, *reply2, *reply3 = NULL; - char *sizecmd, *typename[] = {"string","list","set","hash","zset"}; + redisReply *reply1, *reply2, *reply3 = NULL, *keys; + char *key, *sizecmd, *typename[] = {"string","list","set","hash","zset"}; char *typeunit[] = {"bytes","items","members","fields","members"}; - int type; + int type, it=0, i; printf("\n# Press ctrl+c when you have had enough of it... :)\n"); - printf("# You can use -i 0.1 to sleep 0.1 sec every 100 sampled keys\n"); + printf("# You can use -i 0.1 to sleep 0.1 sec per 100 SCANS\n"); printf("# in order to reduce server load (usually not needed).\n\n"); - while(1) { - /* Sample with RANDOMKEY */ - reply1 = redisCommand(context,"RANDOMKEY"); - if (reply1 == NULL) { - fprintf(stderr,"\nI/O error\n"); + + do { + /* Grab some keys with SCAN */ + reply1 = redisCommand(context, "SCAN %d", it); + if(reply1 == NULL) { + fprintf(stderr, "\nI/O error\n"); exit(1); - } else if (reply1->type == REDIS_REPLY_ERROR) { - fprintf(stderr, "RANDOMKEY error: %s\n", - reply1->str); + } else if(reply1->type == REDIS_REPLY_ERROR) { + fprintf(stderr, "SCAN error: %s\n", reply1->str); exit(1); - } else if (reply1->type == REDIS_REPLY_NIL) { - fprintf(stderr, "It looks like the database is empty!\n"); + } else if(reply1->type != REDIS_REPLY_ARRAY) { + fprintf(stderr, "Non ARRAY response from SCAN!\n"); exit(1); - } - - /* Get the key type */ - reply2 = redisCommand(context,"TYPE %s",reply1->str); - assert(reply2 && reply2->type == REDIS_REPLY_STATUS); - samples++; - - /* Get the key "size" */ - if (!strcmp(reply2->str,"string")) { - sizecmd = "STRLEN"; - type = TYPE_STRING; - } else if (!strcmp(reply2->str,"list")) { - sizecmd = "LLEN"; - type = TYPE_LIST; - } else if (!strcmp(reply2->str,"set")) { - sizecmd = "SCARD"; - type = TYPE_SET; - } else if (!strcmp(reply2->str,"hash")) { - sizecmd = "HLEN"; - type = TYPE_HASH; - } else if (!strcmp(reply2->str,"zset")) { - sizecmd = "ZCARD"; - type = TYPE_ZSET; - } else if (!strcmp(reply2->str,"none")) { - freeReplyObject(reply1); - freeReplyObject(reply2); - continue; - } else { - fprintf(stderr, "Unknown key type '%s' for key '%s'\n", - reply2->str, reply1->str); + } else if(reply1->elements!=2) { + fprintf(stderr, "Invalid SCAN result!\n"); exit(1); } - - reply3 = redisCommand(context,"%s %s", sizecmd, reply1->str); - if (reply3 && reply3->type == REDIS_REPLY_INTEGER) { - if (biggest[type] < reply3->integer) { - printf("Biggest %-6s found so far '%s' with %llu %s.\n", - typename[type], reply1->str, - (unsigned long long) reply3->integer, - typeunit[type]); - biggest[type] = reply3->integer; + + /* Validate the SCAN response */ + assert(reply1->element[0]->type == REDIS_REPLY_STRING); + assert(reply1->element[1]->type == REDIS_REPLY_ARRAY); + + /* Update iterator and grab pointer to keys */ + it = atoi(reply1->element[0]->str); + keys = reply1->element[1]; + + /* Iterate keys that SCAN returned */ + for(i=0;i<keys->elements;i++) { + /* Make sure we've got a string, grab it, and increment samples */ + assert(keys->element[i]->type == REDIS_REPLY_STRING); + key = keys->element[i]->str; + samples++; + + /* Get the key type */ + reply2 = redisCommand(context, "TYPE %s", key); + assert(reply2 && reply2->type == REDIS_REPLY_STATUS); + + /* Get the key "size" */ + if (!strcmp(reply2->str,"string")) { + sizecmd = "STRLEN"; + type = TYPE_STRING; + } else if (!strcmp(reply2->str,"list")) { + sizecmd = "LLEN"; + type = TYPE_LIST; + } else if (!strcmp(reply2->str,"set")) { + sizecmd = "SCARD"; + type = TYPE_SET; + } else if (!strcmp(reply2->str,"hash")) { + sizecmd = "HLEN"; + type = TYPE_HASH; + } else if (!strcmp(reply2->str,"zset")) { + sizecmd = "ZCARD"; + type = TYPE_ZSET; + } else if (!strcmp(reply2->str,"none")) { + freeReplyObject(reply1); + freeReplyObject(reply2); + continue; + } else { + fprintf(stderr, "Unknown key type '%s' for key '%s'\n", + reply2->str, key); + exit(1); + } + + /* The size command */ + reply3 = redisCommand(context,"%s %s", sizecmd, key); + if (reply3 && reply3->type == REDIS_REPLY_INTEGER) { + if (biggest[type] < reply3->integer) { + printf("Biggest %-6s found so far '%s' with %llu %s.\n", + typename[type], key, + (unsigned long long) reply3->integer, + typeunit[type]); + biggest[type] = reply3->integer; + } } + + freeReplyObject(reply2); + if(reply3) freeReplyObject(reply3); } - if ((samples % 1000000) == 0) + if (samples && (samples % 1000000) == 0) printf("(%llu keys sampled)\n", samples); - if ((samples % 100) == 0 && config.interval) + if (samples && (samples % 100) == 0 && config.interval) usleep(config.interval); freeReplyObject(reply1); - freeReplyObject(reply2); - if (reply3) freeReplyObject(reply3); - } + } while(it != 0); + + /* We've finished scanning the keyspace */ + printf("\n# Scanned all %llu keys in the keyspace!\n", samples); + exit(0); } /*------------------------------------------------------------------------------ |