This is the timer handler that is called by the main event loop. We schedule * this timer to be called when the nearest of our module timers will expire. */
| 6269 | /* This is the timer handler that is called by the main event loop. We schedule |
| 6270 | * this timer to be called when the nearest of our module timers will expire. */ |
| 6271 | int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *clientData) { |
| 6272 | UNUSED(eventLoop); |
| 6273 | UNUSED(id); |
| 6274 | UNUSED(clientData); |
| 6275 | |
| 6276 | /* To start let's try to fire all the timers already expired. */ |
| 6277 | raxIterator ri; |
| 6278 | raxStart(&ri,Timers); |
| 6279 | uint64_t now = ustime(); |
| 6280 | long long next_period = 0; |
| 6281 | while(1) { |
| 6282 | raxSeek(&ri,"^",NULL,0); |
| 6283 | if (!raxNext(&ri)) break; |
| 6284 | uint64_t expiretime; |
| 6285 | memcpy(&expiretime,ri.key,sizeof(expiretime)); |
| 6286 | expiretime = ntohu64(expiretime); |
| 6287 | if (now >= expiretime) { |
| 6288 | RedisModuleTimer *timer = ri.data; |
| 6289 | RedisModuleCtx ctx = REDISMODULE_CTX_INIT; |
| 6290 | |
| 6291 | ctx.module = timer->module; |
| 6292 | ctx.client = moduleFreeContextReusedClient; |
| 6293 | selectDb(ctx.client, timer->dbid); |
| 6294 | timer->callback(&ctx,timer->data); |
| 6295 | moduleFreeContext(&ctx); |
| 6296 | raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL); |
| 6297 | zfree(timer); |
| 6298 | } else { |
| 6299 | /* We call ustime() again instead of using the cached 'now' so that |
| 6300 | * 'next_period' isn't affected by the time it took to execute |
| 6301 | * previous calls to 'callback. |
| 6302 | * We need to cast 'expiretime' so that the compiler will not treat |
| 6303 | * the difference as unsigned (Causing next_period to be huge) in |
| 6304 | * case expiretime < ustime() */ |
| 6305 | next_period = ((long long)expiretime-ustime())/1000; /* Scale to milliseconds. */ |
| 6306 | break; |
| 6307 | } |
| 6308 | } |
| 6309 | raxStop(&ri); |
| 6310 | |
| 6311 | /* Reschedule the next timer or cancel it. */ |
| 6312 | if (next_period <= 0) next_period = 1; |
| 6313 | if (raxSize(Timers) > 0) { |
| 6314 | return next_period; |
| 6315 | } else { |
| 6316 | aeTimer = -1; |
| 6317 | return AE_NOMORE; |
| 6318 | } |
| 6319 | } |
| 6320 | |
| 6321 | /* Create a new timer that will fire after `period` milliseconds, and will call |
| 6322 | * the specified function using `data` as argument. The returned timer ID can be |
nothing calls this directly
no test coverage detected