summaryrefslogtreecommitdiff
path: root/src/db.c
diff options
context:
space:
mode:
authorBinbin <binloveplay1314@qq.com>2022-10-09 13:18:34 +0800
committerGitHub <noreply@github.com>2022-10-09 08:18:34 +0300
commit35b3fbd90c2ad2c503c9e3d28bfbffff13099925 (patch)
tree8ca44f6572095f44f29fcddcefb8bdac3490b806 /src/db.c
parentd2ad01ab3e24ca537efdd1fc6ff1ae2c657f4a51 (diff)
downloadredis-35b3fbd90c2ad2c503c9e3d28bfbffff13099925.tar.gz
Freeze time sampling during command execution, and scripts (#10300)
Freeze time during execution of scripts and all other commands. This means that a key is either expired or not, and doesn't change state during a script execution. resolves #10182 This PR try to add a new `commandTimeSnapshot` function. The function logic is extracted from `keyIsExpired`, but the related calls to `fixed_time_expire` and `mstime()` are removed, see below. In commands, we will avoid calling `mstime()` multiple times and just use the one that sampled in call. The background is, e.g. using `PEXPIRE 1` with valgrind sometimes result in the key being deleted rather than expired. The reason is that both `PEXPIRE` command and `checkAlreadyExpired` call `mstime()` separately. There are other more important changes in this PR: 1. Eliminate `fixed_time_expire`, it is no longer needed. When we want to sample time we should always use a time snapshot. We will use `in_nested_call` instead to update the cached time in `call`. 2. Move the call for `updateCachedTime` from `serverCron` to `afterSleep`. Now `commandTimeSnapshot` will always return the sample time, the `lookupKeyReadWithFlags` call in `getNodeByQuery` will get a outdated cached time (because `processCommand` is out of the `call` context). We put the call to `updateCachedTime` in `aftersleep`. 3. Cache the time each time the module lock Redis. Call `updateCachedTime` in `moduleGILAfterLock`, affecting `RM_ThreadSafeContextLock` and `RM_ThreadSafeContextTryLock` Currently the commandTimeSnapshot change affects the following TTL commands: - SET EX / SET PX - EXPIRE / PEXPIRE - SETEX / PSETEX - GETEX EX / GETEX PX - TTL / PTTL - EXPIRETIME / PEXPIRETIME - RESTORE key TTL And other commands just use the cached mstime (including TIME). This is considered to be a breaking change since it can break a script that uses a loop to wait for a key to expire.
Diffstat (limited to 'src/db.c')
-rw-r--r--src/db.c23
1 files changed, 1 insertions, 22 deletions
diff --git a/src/db.c b/src/db.c
index 7ebf57ac4..1d107e034 100644
--- a/src/db.c
+++ b/src/db.c
@@ -1620,28 +1620,7 @@ int keyIsExpired(redisDb *db, robj *key) {
/* Don't expire anything while loading. It will be done later. */
if (server.loading) return 0;
- /* If we are in the context of a Lua script, we pretend that time is
- * blocked to when the Lua script started. This way a key can expire
- * only the first time it is accessed and not in the middle of the
- * script execution, making propagation to slaves / AOF consistent.
- * See issue #1525 on Github for more information. */
- if (server.script_caller) {
- now = scriptTimeSnapshot();
- }
- /* If we are in the middle of a command execution, we still want to use
- * a reference time that does not change: in that case we just use the
- * cached time, that we update before each call in the call() function.
- * This way we avoid that commands such as RPOPLPUSH or similar, that
- * may re-open the same key multiple times, can invalidate an already
- * open object in a next call, if the next call will see the key expired,
- * while the first did not. */
- else if (server.fixed_time_expire > 0) {
- now = server.mstime;
- }
- /* For the other cases, we want to use the most fresh time we have. */
- else {
- now = mstime();
- }
+ now = commandTimeSnapshot();
/* The key expired if the current (virtual or real) time is greater
* than the expire time of the key. */