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. */
| 6445 | /* This is the timer handler that is called by the main event loop. We schedule |
| 6446 | * this timer to be called when the nearest of our module timers will expire. */ |
| 6447 | int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *clientData) { |
| 6448 | UNUSED(eventLoop); |
| 6449 | UNUSED(id); |
| 6450 | UNUSED(clientData); |
| 6451 | |
| 6452 | /* To start let's try to fire all the timers already expired. */ |
| 6453 | raxIterator ri; |
| 6454 | raxStart(&ri,Timers); |
| 6455 | uint64_t now = ustime(); |
| 6456 | long long next_period = 0; |
| 6457 | while(1) { |
| 6458 | raxSeek(&ri,"^",NULL,0); |
| 6459 | if (!raxNext(&ri)) break; |
| 6460 | uint64_t expiretime; |
| 6461 | memcpy(&expiretime,ri.key,sizeof(expiretime)); |
| 6462 | expiretime = ntohu64(expiretime); |
| 6463 | if (now >= expiretime) { |
| 6464 | RedisModuleTimer *timer = (RedisModuleTimer*)ri.data; |
| 6465 | RedisModuleCtx ctx = REDISMODULE_CTX_INIT; |
| 6466 | |
| 6467 | ctx.module = timer->module; |
| 6468 | ctx.client = moduleFreeContextReusedClient; |
| 6469 | selectDb(ctx.client, timer->dbid); |
| 6470 | timer->callback(&ctx,timer->data); |
| 6471 | moduleFreeContext(&ctx); |
| 6472 | raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL); |
| 6473 | zfree(timer); |
| 6474 | } else { |
| 6475 | /* We call ustime() again instead of using the cached 'now' so that |
| 6476 | * 'next_period' isn't affected by the time it took to execute |
| 6477 | * previous calls to 'callback. |
| 6478 | * We need to cast 'expiretime' so that the compiler will not treat |
| 6479 | * the difference as unsigned (Causing next_period to be huge) in |
| 6480 | * case expiretime < ustime() */ |
| 6481 | next_period = ((long long)expiretime-ustime())/1000; /* Scale to milliseconds. */ |
| 6482 | break; |
| 6483 | } |
| 6484 | } |
| 6485 | raxStop(&ri); |
| 6486 | |
| 6487 | /* Reschedule the next timer or cancel it. */ |
| 6488 | if (next_period <= 0) next_period = 1; |
| 6489 | if (raxSize(Timers) > 0) { |
| 6490 | return next_period; |
| 6491 | } else { |
| 6492 | aeTimer = -1; |
| 6493 | return AE_NOMORE; |
| 6494 | } |
| 6495 | } |
| 6496 | |
| 6497 | /* Create a new timer that will fire after `period` milliseconds, and will call |
| 6498 | * the specified function using `data` as argument. The returned timer ID can be |
nothing calls this directly
no test coverage detected