Do not watch keys for dirty client (#9829)

Currently, the watching clients are marked as dirty when a watched
key is touched, but we continue watching the keys for no reason.
Then, when the same key is touched again, we iterate again on the
watching clients list and mark all clients as dirty again.
Only when the exec/unwatch command is issued will the client be
removed from the key->watching_clients list. The same applies when
a dirty client calls the WATCH command. The key will be added to be
watched by the client even if it has no effect.

In the field, no performance degradation was observed as a result of the
current implementation; it is merely a cleanup with possible memory and
performance gains in some situations.

Co-authored-by: Oran Agra <oran@redislabs.com>
This commit is contained in:
uriyage 2021-11-25 15:23:15 +02:00 committed by GitHub
parent 9630ded313
commit fa48fb2d0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -397,6 +397,10 @@ void touchWatchedKey(redisDb *db, robj *key) {
client *c = listNodeValue(ln);
c->flags |= CLIENT_DIRTY_CAS;
/* As the client is marked as dirty, there is no point in getting here
* again in case that key (or others) are modified again (or keep the
* memory overhead till EXEC). */
unwatchAllKeys(c);
}
}
@ -426,6 +430,9 @@ void touchAllWatchedKeysInDb(redisDb *emptied, redisDb *replaced_with) {
while((ln = listNext(&li))) {
client *c = listNodeValue(ln);
c->flags |= CLIENT_DIRTY_CAS;
/* As the client is marked as dirty, there is no point in getting here
* again for others keys (or keep the memory overhead till EXEC). */
unwatchAllKeys(c);
}
}
}
@ -439,6 +446,11 @@ void watchCommand(client *c) {
addReplyError(c,"WATCH inside MULTI is not allowed");
return;
}
/* No point in watching if the client is already dirty. */
if (c->flags & CLIENT_DIRTY_CAS) {
addReply(c,shared.ok);
return;
}
for (j = 1; j < c->argc; j++)
watchForKey(c,c->argv[j]);
addReply(c,shared.ok);