Optimize KEYS when pattern includes hashtag and implies a single slot. (#12754)

in #12536 we made a similar optimization for SCAN, now that hashtags in
patterns. When we can make sure all keys matching the pettern will be in
the same slot, we can limit the iteration to run only one one.
This commit is contained in:
Chen Tianjie 2023-12-05 22:21:50 +08:00 committed by GitHub
parent 35c8d616cf
commit 991aff1c0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 4 deletions

View File

@ -33,6 +33,7 @@
#include "latency.h"
#include "script.h"
#include "functions.h"
#include "cluster.h"
#include <signal.h>
#include <ctype.h>
@ -993,13 +994,22 @@ void randomkeyCommand(client *c) {
void keysCommand(client *c) {
dictEntry *de;
sds pattern = c->argv[1]->ptr;
int plen = sdslen(pattern), allkeys;
int plen = sdslen(pattern), allkeys, pslot = -1;
long numkeys = 0;
void *replylen = addReplyDeferredLen(c);
dbIterator *dbit = dbIteratorInit(c->db, DB_MAIN);
allkeys = (pattern[0] == '*' && plen == 1);
if (!allkeys) {
pslot = patternHashSlot(pattern, plen);
}
dictIterator *di = NULL;
dbIterator *dbit = NULL;
if (server.cluster_enabled && !allkeys && pslot != -1) {
di = dictGetSafeIterator(c->db->dict[pslot]);
} else {
dbit = dbIteratorInit(c->db, DB_MAIN);
}
robj keyobj;
while ((de = dbIteratorNext(dbit)) != NULL) {
while ((de = di ? dictNext(di) : dbIteratorNext(dbit)) != NULL) {
sds key = dictGetKey(de);
if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
@ -1012,7 +1022,10 @@ void keysCommand(client *c) {
if (c->flags & CLIENT_CLOSE_ASAP)
break;
}
dbReleaseIterator(dbit);
if (di)
dictReleaseIterator(di);
if (dbit)
dbReleaseIterator(dbit);
setDeferredArrayLen(c,replylen,numkeys);
}

View File

@ -34,6 +34,14 @@ start_server {tags {"keyspace"}} {
r dbsize
} {6}
test {KEYS with hashtag} {
foreach key {"{a}x" "{a}y" "{a}z" "{b}a" "{b}b" "{b}c"} {
r set $key hello
}
assert_equal [lsort [r keys "{a}*"]] [list "{a}x" "{a}y" "{a}z"]
assert_equal [lsort [r keys "*{b}*"]] [list "{b}a" "{b}b" "{b}c"]
}
test {DEL all keys} {
foreach key [r keys *] {r del $key}
r dbsize