mirror of
https://github.com/fluencelabs/redis
synced 2025-03-17 16:10:50 +00:00
Update --bigkeys to use SCAN
This commit changes the findBigKeys() function in redis-cli.c to use the new SCAN command for iterating the keyspace, rather than RANDOMKEY. Because we can know when we're done using SCAN, it will exit after exhausting the keyspace.
This commit is contained in:
parent
d3a3ef0bc1
commit
013a4ce242
136
src/redis-cli.c
136
src/redis-cli.c
@ -1300,81 +1300,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);
|
||||
} else if(reply1->elements!=2) {
|
||||
fprintf(stderr, "Invalid SCAN result!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Validate the SCAN response */
|
||||
assert(reply1->element[0]->type == REDIS_REPLY_STRING);
|
||||
assert(reply1->element[1]->type == REDIS_REPLY_ARRAY);
|
||||
|
||||
/* Get the key type */
|
||||
reply2 = redisCommand(context,"TYPE %s",reply1->str);
|
||||
assert(reply2 && reply2->type == REDIS_REPLY_STATUS);
|
||||
samples++;
|
||||
/* Update iterator and grab pointer to keys */
|
||||
it = atoi(reply1->element[0]->str);
|
||||
keys = reply1->element[1];
|
||||
|
||||
/* 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);
|
||||
exit(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++;
|
||||
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Return the specified INFO field from the INFO command output "info".
|
||||
|
Loading…
x
Reference in New Issue
Block a user