mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
EXISTS should not alter LRU, OBJECT should not reveal expired keys on replica (#8016)
The bug was introduced by #5021 which only attempted avoid EXIST on an already expired key from returning 1 on a replica. Before that commit, dbExists was used instead of lookupKeyRead (which had an undesired effect to "touch" the LRU/LFU) Other than that, this commit fixes OBJECT to also come empty handed on expired keys in replica. And DEBUG DIGEST-VALUE to behave like DEBUG OBJECT (get the data from the key regardless of it's expired state)
This commit is contained in:
parent
d87a0d0286
commit
f8ae991717
25
src/db.c
25
src/db.c
@ -102,11 +102,8 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
|||||||
/* Key expired. If we are in the context of a master, expireIfNeeded()
|
/* Key expired. If we are in the context of a master, expireIfNeeded()
|
||||||
* returns 0 only when the key does not exist at all, so it's safe
|
* returns 0 only when the key does not exist at all, so it's safe
|
||||||
* to return NULL ASAP. */
|
* to return NULL ASAP. */
|
||||||
if (server.masterhost == NULL) {
|
if (server.masterhost == NULL)
|
||||||
server.stat_keyspace_misses++;
|
goto keymiss;
|
||||||
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* However if we are in the context of a slave, expireIfNeeded() will
|
/* However if we are in the context of a slave, expireIfNeeded() will
|
||||||
* not really try to expire the key, it only returns information
|
* not really try to expire the key, it only returns information
|
||||||
@ -125,19 +122,21 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
|||||||
server.current_client->cmd &&
|
server.current_client->cmd &&
|
||||||
server.current_client->cmd->flags & CMD_READONLY)
|
server.current_client->cmd->flags & CMD_READONLY)
|
||||||
{
|
{
|
||||||
server.stat_keyspace_misses++;
|
goto keymiss;
|
||||||
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val = lookupKey(db,key,flags);
|
val = lookupKey(db,key,flags);
|
||||||
if (val == NULL) {
|
if (val == NULL)
|
||||||
|
goto keymiss;
|
||||||
|
server.stat_keyspace_hits++;
|
||||||
|
return val;
|
||||||
|
|
||||||
|
keymiss:
|
||||||
|
if (!(flags & LOOKUP_NONOTIFY)) {
|
||||||
server.stat_keyspace_misses++;
|
server.stat_keyspace_misses++;
|
||||||
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id);
|
||||||
}
|
}
|
||||||
else
|
return NULL;
|
||||||
server.stat_keyspace_hits++;
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like lookupKeyReadWithFlags(), but does not use any flag, which is the
|
/* Like lookupKeyReadWithFlags(), but does not use any flag, which is the
|
||||||
@ -592,7 +591,7 @@ void existsCommand(client *c) {
|
|||||||
int j;
|
int j;
|
||||||
|
|
||||||
for (j = 1; j < c->argc; j++) {
|
for (j = 1; j < c->argc; j++) {
|
||||||
if (lookupKeyRead(c->db,c->argv[j])) count++;
|
if (lookupKeyReadWithFlags(c->db,c->argv[j],LOOKUP_NOTOUCH)) count++;
|
||||||
}
|
}
|
||||||
addReplyLongLong(c,count);
|
addReplyLongLong(c,count);
|
||||||
}
|
}
|
||||||
|
@ -644,7 +644,11 @@ NULL
|
|||||||
for (int j = 2; j < c->argc; j++) {
|
for (int j = 2; j < c->argc; j++) {
|
||||||
unsigned char digest[20];
|
unsigned char digest[20];
|
||||||
memset(digest,0,20); /* Start with a clean result */
|
memset(digest,0,20); /* Start with a clean result */
|
||||||
robj *o = lookupKeyReadWithFlags(c->db,c->argv[j],LOOKUP_NOTOUCH);
|
|
||||||
|
/* We don't use lookupKey because a debug command should
|
||||||
|
* work on logically expired keys */
|
||||||
|
dictEntry *de;
|
||||||
|
robj *o = ((de = dictFind(c->db->dict,c->argv[j]->ptr)) == NULL) ? NULL : dictGetVal(de);
|
||||||
if (o) xorObjectDigest(c->db,c->argv[j],digest,o);
|
if (o) xorObjectDigest(c->db,c->argv[j],digest,o);
|
||||||
|
|
||||||
sds d = sdsempty();
|
sds d = sdsempty();
|
||||||
|
@ -1229,10 +1229,7 @@ int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
|
|||||||
/* This is a helper function for the OBJECT command. We need to lookup keys
|
/* This is a helper function for the OBJECT command. We need to lookup keys
|
||||||
* without any modification of LRU or other parameters. */
|
* without any modification of LRU or other parameters. */
|
||||||
robj *objectCommandLookup(client *c, robj *key) {
|
robj *objectCommandLookup(client *c, robj *key) {
|
||||||
dictEntry *de;
|
return lookupKeyReadWithFlags(c->db,key,LOOKUP_NOTOUCH|LOOKUP_NONOTIFY);
|
||||||
|
|
||||||
if ((de = dictFind(c->db->dict,key->ptr)) == NULL) return NULL;
|
|
||||||
return (robj*) dictGetVal(de);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
robj *objectCommandLookupOrReply(client *c, robj *key, robj *reply) {
|
robj *objectCommandLookupOrReply(client *c, robj *key, robj *reply) {
|
||||||
|
@ -2179,6 +2179,7 @@ int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
|
|||||||
long long lru_clock, int lru_multiplier);
|
long long lru_clock, int lru_multiplier);
|
||||||
#define LOOKUP_NONE 0
|
#define LOOKUP_NONE 0
|
||||||
#define LOOKUP_NOTOUCH (1<<0)
|
#define LOOKUP_NOTOUCH (1<<0)
|
||||||
|
#define LOOKUP_NONOTIFY (1<<1)
|
||||||
void dbAdd(redisDb *db, robj *key, robj *val);
|
void dbAdd(redisDb *db, robj *key, robj *val);
|
||||||
int dbAddRDBLoad(redisDb *db, sds key, robj *val);
|
int dbAddRDBLoad(redisDb *db, sds key, robj *val);
|
||||||
void dbOverwrite(redisDb *db, robj *key, robj *val);
|
void dbOverwrite(redisDb *db, robj *key, robj *val);
|
||||||
|
@ -3,11 +3,12 @@ proc cmdstat {cmd} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start_server {tags {"introspection"}} {
|
start_server {tags {"introspection"}} {
|
||||||
test {TTL and TYPYE do not alter the last access time of a key} {
|
test {TTL, TYPE and EXISTS do not alter the last access time of a key} {
|
||||||
r set foo bar
|
r set foo bar
|
||||||
after 3000
|
after 3000
|
||||||
r ttl foo
|
r ttl foo
|
||||||
r type foo
|
r type foo
|
||||||
|
r exists foo
|
||||||
assert {[r object idletime foo] >= 2}
|
assert {[r object idletime foo] >= 2}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user