Commit acb4cd21 authored by guybe7's avatar guybe7 Committed by Oran Agra
Browse files

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 1a91a270)
parent fb86ecb8
...@@ -5441,7 +5441,10 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client ...@@ -5441,7 +5441,10 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client
raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL); raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL);
zfree(timer); zfree(timer);
} else { } 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; break;
} }
} }
...@@ -5454,7 +5457,16 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client ...@@ -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 /* 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 * 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) { RedisModuleTimerID RM_CreateTimer(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data) {
RedisModuleTimer *timer = zmalloc(sizeof(*timer)); RedisModuleTimer *timer = zmalloc(sizeof(*timer));
timer->module = ctx->module; timer->module = ctx->module;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment