Merge branch 'bigkeys_scan' of git://github.com/michael-grunder/redis into unstable

This commit is contained in:
antirez 2014-02-25 14:59:57 +01:00
commit 55e36e1132

View File

@ -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);
} 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);
}
/*------------------------------------------------------------------------------