Revert make KEYS to be an exact match if there is no pattern (#964)

In #792, the time complexity became ambiguous, fluctuating between
O(1) and O(n), which is a significant difference. And we agree uncertainty
can potentially bring disaster to the business, the right thing to do is
to persuade users to use EXISTS instead of KEYS in this case, to do the
right thing the right way, rather than accommodating this incorrect usage.

This reverts commit d66a06e8183818c035bb78706f46fd62645db07e.
This reverts #792.

Signed-off-by: Binbin <binloveplay1314@qq.com>
This commit is contained in:
Binbin 2024-08-29 10:58:19 +08:00 committed by GitHub
parent 25dd943087
commit 75b824052d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 1 additions and 89 deletions

View File

@ -808,21 +808,6 @@ void randomkeyCommand(client *c) {
decrRefCount(key);
}
/* Returns 1 if the pattern can be an exact match in KEYS context. */
int patternExactMatch(const char *pattern, int length) {
for (int i = 0; i < length; i++) {
if (pattern[i] == '*' || pattern[i] == '?' || pattern[i] == '[') {
/* Wildcard or character class found. Keys can be in anywhere. */
return 0;
} else if (pattern[i] == '\\') {
/* Escaped character. Computing the key name in this case is not
* implemented. We would need a temp buffer. */
return 0;
}
}
return 1;
}
void keysCommand(client *c) {
dictEntry *de;
sds pattern = c->argv[1]->ptr;
@ -832,27 +817,7 @@ void keysCommand(client *c) {
allkeys = (pattern[0] == '*' && plen == 1);
if (server.cluster_enabled && !allkeys) {
pslot = patternHashSlot(pattern, plen);
} else if (!server.cluster_enabled) {
pslot = 0;
}
/* Once the pattern can do an exact match, we can convert
* it to a kvstoreDictFind to avoid iterating over all data. */
if (patternExactMatch(pattern, plen) && pslot != -1) {
de = kvstoreDictFind(c->db->keys, pslot, pattern);
if (de) {
robj keyobj;
sds key = dictGetKey(de);
initStaticStringObject(keyobj, key);
if (!keyIsExpired(c->db, &keyobj)) {
addReplyBulkCBuffer(c, key, sdslen(key));
numkeys++;
}
}
setDeferredArrayLen(c, replylen, numkeys);
return;
}
kvstoreDictIterator *kvs_di = NULL;
kvstoreIterator *kvs_it = NULL;
if (pslot != -1) {

View File

@ -40,25 +40,7 @@ start_server {tags {"keyspace"}} {
}
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 {KEYS with no pattern} {
r debug populate 1000
r set foo bar
r set foo{t} bar
r set foo\\ bar
r del non-exist
assert_equal [r keys foo] {foo}
assert_equal [r keys foo{t}] {foo{t}}
assert_equal [r keys foo\\] {foo\\}
assert_equal [r keys non-exist] {}
# Make sure the return value is consistent with the * one
assert_equal [r keys foo] [r keys *foo]
assert_equal [r keys foo{t}] [r keys *foo{t}]
assert_equal [r keys foo\\] [r keys *foo\\]
assert_equal [r keys non-exist] [r keys *non-exist]
} {} {needs:debug}
}
test {DEL all keys} {
foreach key [r keys *] {r del $key}
@ -566,38 +548,3 @@ foreach {type large} [array get largevalue] {
r flushall
} {OK} {singledb:skip}
}
start_cluster 1 0 {tags {"keyspace external:skip cluster"}} {
# SET keys for random slots, for random noise.
set num_keys 0
while {$num_keys < 1000} {
set random_key [randomInt 163840]
r SET $random_key VALUE
incr num_keys 1
}
test {KEYS with hashtag in cluster mode} {
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 {KEYS with no pattern in cluster mode} {
r set foo bar
r set foo{t} bar
r set foo\\ bar
r del non-exist
assert_equal [r keys foo] {foo}
assert_equal [r keys foo{t}] {foo{t}}
assert_equal [r keys foo\\] {foo\\}
assert_equal [r keys non-exist] {}
# Make sure the return value is consistent with the * one
assert_equal [r keys foo] [r keys *foo]
assert_equal [r keys foo{t}] [r keys *foo{t}]
assert_equal [r keys foo\\] [r keys *foo\\]
assert_equal [r keys non-exist] [r keys *non-exist]
}
}