summaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c84
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