diff options
Diffstat (limited to 'src/server.c')
-rw-r--r-- | src/server.c | 84 |
1 files changed, 43 insertions, 41 deletions
diff --git a/src/server.c b/src/server.c index 85c48c41d..042d711a1 100644 --- a/src/server.c +++ b/src/server.c @@ -209,24 +209,20 @@ mstime_t mstime(void) { * reflect the same time. * More details can be found in the comments below. */ mstime_t commandTimeSnapshot(void) { - /* 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) { - return 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 + /* When we are in the middle of a command execution, we 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 { - return server.mstime; - } + * while the first did not. + * This is specificlally important in the context of scripts, where we + * pretend that time freezes. 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 for more info. + * Note that we cannot use the cached server.mstime because it can change + * in processEventsWhileBlocked etc. */ + return server.cmd_time_snapshot; } /* After an RDB dump or AOF rewrite we exit from children using _exit() instead of @@ -1722,8 +1718,9 @@ void beforeSleep(struct aeEventLoop *eventLoop) { * releasing the GIL. Redis main thread will not touch anything at this * time. */ if (moduleCount()) moduleReleaseGIL(); - - /* Do NOT add anything below moduleReleaseGIL !!! */ + /********************* WARNING ******************** + * Do NOT add anything below moduleReleaseGIL !!! * + ***************************** ********************/ } /* This function is called immediately after the event loop multiplexing @@ -1731,14 +1728,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) { * the different events callbacks. */ void afterSleep(struct aeEventLoop *eventLoop) { UNUSED(eventLoop); - - /* Update the time cache. */ - updateCachedTime(1); - - /* Do NOT add anything above moduleAcquireGIL !!! */ - - /* Acquire the modules GIL so that their threads won't touch anything. */ + /********************* WARNING ******************** + * Do NOT add anything above moduleAcquireGIL !!! * + ***************************** ********************/ if (!ProcessingEventsWhileBlocked) { + /* Acquire the modules GIL so that their threads won't touch anything. */ if (moduleCount()) { mstime_t latency; latencyStartMonitor(latency); @@ -1751,6 +1745,16 @@ void afterSleep(struct aeEventLoop *eventLoop) { latencyAddSampleIfNeeded("module-acquire-GIL",latency); } } + + /* Update the time cache. */ + updateCachedTime(1); + + /* Update command time snapshot in case it'll be required without a command + * e.g. somehow used by module timers. Don't update it while yielding to a + * blocked command, call() will handle that and restore the original time. */ + if (!ProcessingEventsWhileBlocked) { + server.cmd_time_snapshot = server.mstime; + } } /* =========================== Server initialization ======================== */ @@ -1945,6 +1949,7 @@ void initServerConfig(void) { initConfigValues(); updateCachedTime(1); + server.cmd_time_snapshot = server.mstime; getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE); server.runid[CONFIG_RUN_ID_SIZE] = '\0'; changeReplicationId(); @@ -3435,6 +3440,9 @@ void call(client *c, int flags) { long long dirty; uint64_t client_old_flags = c->flags; struct redisCommand *real_cmd = c->realcmd; + client *prev_client = server.executing_client; + server.executing_client = c; + /* When call() is issued during loading the AOF we don't want commands called * from module, exec or LUA to go into the slowlog or to populate statistics. */ int update_command_stats = !isAOFLoadingContext(); @@ -3466,6 +3474,7 @@ void call(client *c, int flags) { * in case we have nested calls we want to update only on the first call */ if (server.execution_nesting++ == 0) { updateCachedTimeWithUs(0,call_timer); + server.cmd_time_snapshot = server.mstime; c->flags |= CLIENT_EXECUTING_COMMAND; } @@ -3511,16 +3520,6 @@ void call(client *c, int flags) { c->flags |= CLIENT_CLOSE_AFTER_REPLY; } - /* If the caller is Lua, we want to force the EVAL caller to propagate - * the script if the command flag or client flag are forcing the - * propagation. */ - if (c->flags & CLIENT_SCRIPT && server.script_caller) { - if (c->flags & CLIENT_FORCE_REPL) - server.script_caller->flags |= CLIENT_FORCE_REPL; - if (c->flags & CLIENT_FORCE_AOF) - server.script_caller->flags |= CLIENT_FORCE_AOF; - } - /* Note: the code below uses the real command that was executed * c->cmd and c->lastcmd may be different, in case of MULTI-EXEC or * re-written commands such as EXPIRE, GEOADD, etc. */ @@ -3607,18 +3606,19 @@ void call(client *c, int flags) { (CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP); /* If the client has keys tracking enabled for client side caching, - * make sure to remember the keys it fetched via this command. Scripting - * works a bit differently, where if the scripts executes any read command, it - * remembers all of the declared keys from the script. */ + * make sure to remember the keys it fetched via this command. For read-only + * scripts, don't process the script, only the commands it executes. */ if ((c->cmd->flags & CMD_READONLY) && (c->cmd->proc != evalRoCommand) && (c->cmd->proc != evalShaRoCommand) && (c->cmd->proc != fcallroCommand)) { - client *caller = (c->flags & CLIENT_SCRIPT && server.script_caller) ? - server.script_caller : c; - if (caller->flags & CLIENT_TRACKING && - !(caller->flags & CLIENT_TRACKING_BCAST)) + /* We use the tracking flag of the original external client that + * triggered the command, but we take the keys from the actual command + * being executed. */ + if (server.current_client && + (server.current_client->flags & CLIENT_TRACKING) && + !(server.current_client->flags & CLIENT_TRACKING_BCAST)) { - trackingRememberKeys(caller); + trackingRememberKeys(server.current_client, c); } } @@ -3639,6 +3639,8 @@ void call(client *c, int flags) { if (!server.in_exec && server.client_pause_in_transaction) { server.client_pause_in_transaction = 0; } + + server.executing_client = prev_client; } /* Used when a command that is ready for execution needs to be rejected, due to |