Prevent Redis from crashing from key tracking invalidations (#11814)
There is a built in limit to client side tracking keys, which when exceeded will invalidate keys. This occurs in two places, one in the server cron and other before executing a command. If it happens in the second scenario, the invalidations will be queued for later since current client is set. This queue is never drained if a command is not executed (through call) such as a multi-exec command getting queued. This results in a later server assert crashing.
This commit is contained in:
parent
4cc2b0dc1a
commit
dca5927ac8
@ -393,10 +393,10 @@ void trackingInvalidateKey(client *c, robj *keyobj, int bcast) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If target is current client, we need schedule key invalidation.
|
/* If target is current client and it's executing a command, we need schedule key invalidation.
|
||||||
* As the invalidation messages may be interleaved with command
|
* As the invalidation messages may be interleaved with command
|
||||||
* response and should after command response */
|
* response and should after command response. */
|
||||||
if (target == server.current_client){
|
if (target == server.current_client && (server.current_client->flags & CLIENT_EXECUTING_COMMAND)) {
|
||||||
incrRefCount(keyobj);
|
incrRefCount(keyobj);
|
||||||
listAddNodeTail(server.tracking_pending_keys, keyobj);
|
listAddNodeTail(server.tracking_pending_keys, keyobj);
|
||||||
} else {
|
} else {
|
||||||
|
@ -742,6 +742,44 @@ start_server {tags {"tracking network"}} {
|
|||||||
assert_equal {} $prefixes
|
assert_equal {} $prefixes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {Regression test for #11715} {
|
||||||
|
# This issue manifests when a client invalidates keys through the max key
|
||||||
|
# limit, which invalidates keys to get Redis below the limit, but no command is
|
||||||
|
# then executed. This can occur in several ways but the simplest is through
|
||||||
|
# multi-exec which queues commands.
|
||||||
|
clean_all
|
||||||
|
r config set tracking-table-max-keys 2
|
||||||
|
|
||||||
|
# The cron will invalidate keys if we're above the limit, so disable it.
|
||||||
|
r debug pause-cron 1
|
||||||
|
|
||||||
|
# Set up a client that has listened to 2 keys and start a multi, this
|
||||||
|
# sets up the crash for later.
|
||||||
|
$rd HELLO 3
|
||||||
|
$rd read
|
||||||
|
$rd CLIENT TRACKING on
|
||||||
|
assert_match "OK" [$rd read]
|
||||||
|
$rd mget "1{tag}" "2{tag}"
|
||||||
|
assert_match "{} {}" [$rd read]
|
||||||
|
$rd multi
|
||||||
|
assert_match "OK" [$rd read]
|
||||||
|
|
||||||
|
# Reduce the tracking table keys to 1, this doesn't immediately take affect, but
|
||||||
|
# instead will apply on the next command.
|
||||||
|
r config set tracking-table-max-keys 1
|
||||||
|
|
||||||
|
# This command will get queued, so make sure this command doesn't crash.
|
||||||
|
$rd ping
|
||||||
|
$rd exec
|
||||||
|
|
||||||
|
# Validate we got some invalidation message and then the command was queued.
|
||||||
|
assert_match "invalidate *{tag}" [$rd read]
|
||||||
|
assert_match "QUEUED" [$rd read]
|
||||||
|
assert_match "PONG" [$rd read]
|
||||||
|
|
||||||
|
r debug pause-cron 0
|
||||||
|
} {OK} {needs:debug}
|
||||||
|
|
||||||
$rd_redirection close
|
$rd_redirection close
|
||||||
$rd close
|
$rd close
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user