summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorguybe7 <guy.benoish@redislabs.com>2020-11-02 17:18:42 +0100
committerOran Agra <oran@redislabs.com>2021-01-12 16:25:37 +0200
commitacb4cd213553f6edddd9d16b8e2906684e5433f7 (patch)
tree183bc8a1137fb2b924d61a6d7968d86872419455
parentfb86ecb802c45fac54aa7087e37592a9cbc0ab14 (diff)
downloadredis-acb4cd213553f6edddd9d16b8e2906684e5433f7.tar.gz
Modules: Improve timer accuracy (#7987)
The bug occurs when 'callback' re-registers itself to a point in the future and the execution time in non-negligible: 'now' refers to time BEFORE callback was executed and is used to calculate 'next_period'. We must get the actual current time when calculating 'next_period' (cherry picked from commit 1a91a2700b24211e90c695d3fdbbfe7e8d75dbe4)
-rw-r--r--src/module.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/src/module.c b/src/module.c
index 3c96c601b..ae7fa22b2 100644
--- a/src/module.c
+++ b/src/module.c
@@ -5441,7 +5441,10 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client
raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL);
zfree(timer);
} else {
- next_period = (expiretime-now)/1000; /* Scale to milliseconds. */
+ /* We call ustime() again instead of using the cached 'now' so that
+ * 'next_period' isn't affected by the time it took to execute
+ * previous calls to 'callback. */
+ next_period = (expiretime-ustime())/1000; /* Scale to milliseconds. */
break;
}
}
@@ -5454,7 +5457,16 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client
/* Create a new timer that will fire after `period` milliseconds, and will call
* the specified function using `data` as argument. The returned timer ID can be
- * used to get information from the timer or to stop it before it fires. */
+ * used to get information from the timer or to stop it before it fires.
+ * Note that for the common use case of a repeating timer (Re-registration
+ * of the timer inside the RedisModuleTimerProc callback) it matters when
+ * this API is called:
+ * If it is called at the beginning of 'callback' it means
+ * the event will triggered every 'period'.
+ * If it is called at the end of 'callback' it means
+ * there will 'period' milliseconds gaps between events.
+ * (If the time it takes to execute 'callback' is negligible the two
+ * statements above mean the same) */
RedisModuleTimerID RM_CreateTimer(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data) {
RedisModuleTimer *timer = zmalloc(sizeof(*timer));
timer->module = ctx->module;