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. * 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 calle
| 6507 | * (If the time it takes to execute 'callback' is negligible the two |
| 6508 | * statements above mean the same) */ |
| 6509 | RedisModuleTimerID RM_CreateTimer(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data) { |
| 6510 | static uint64_t pending_key; |
| 6511 | static mstime_t pending_period = -1; |
| 6512 | |
| 6513 | RedisModuleTimer *timer = (RedisModuleTimer*)zmalloc(sizeof(*timer), MALLOC_LOCAL); |
| 6514 | timer->module = ctx->module; |
| 6515 | timer->callback = callback; |
| 6516 | timer->data = data; |
| 6517 | timer->dbid = ctx->client ? ctx->client->db->id : 0; |
| 6518 | uint64_t expiretime = ustime()+period*1000; |
| 6519 | uint64_t key; |
| 6520 | |
| 6521 | while(1) { |
| 6522 | key = htonu64(expiretime); |
| 6523 | if (raxFind(Timers, (unsigned char*)&key,sizeof(key)) == raxNotFound) { |
| 6524 | raxInsert(Timers,(unsigned char*)&key,sizeof(key),timer,NULL); |
| 6525 | break; |
| 6526 | } else { |
| 6527 | expiretime++; |
| 6528 | } |
| 6529 | } |
| 6530 | |
| 6531 | bool fNeedPost = (pending_period < 0); // If pending_period is already set, then a PostFunction is in flight and we don't need to set a new one |
| 6532 | if (pending_period < 0 || period < pending_period) { |
| 6533 | pending_period = period; |
| 6534 | pending_key = key; |
| 6535 | } |
| 6536 | |
| 6537 | /* We need to install the main event loop timer if it's not already |
| 6538 | * installed, or we may need to refresh its period if we just installed |
| 6539 | * a timer that will expire sooner than any other else (i.e. the timer |
| 6540 | * we just installed is the first timer in the Timers rax). */ |
| 6541 | if (fNeedPost) { |
| 6542 | aePostFunction(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el, []{ |
| 6543 | if (aeTimer != -1) { |
| 6544 | raxIterator ri; |
| 6545 | raxStart(&ri,Timers); |
| 6546 | raxSeek(&ri,"^",NULL,0); |
| 6547 | raxNext(&ri); |
| 6548 | if (memcmp(ri.key,&pending_key,sizeof(key)) == 0) { |
| 6549 | /* This is the first key, we need to re-install the timer according |
| 6550 | * to the just added event. */ |
| 6551 | aeDeleteTimeEvent(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el,aeTimer); |
| 6552 | aeTimer = -1; |
| 6553 | } |
| 6554 | raxStop(&ri); |
| 6555 | } |
| 6556 | |
| 6557 | /* If we have no main timer (the old one was invalidated, or this is the |
| 6558 | * first module timer we have), install one. */ |
| 6559 | if (aeTimer == -1) { |
| 6560 | aeTimer = aeCreateTimeEvent(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el,pending_period,moduleTimerHandler,NULL,NULL); |
| 6561 | } |
| 6562 | |
| 6563 | pending_period = -1; |
| 6564 | }); |
| 6565 | } |
| 6566 |
nothing calls this directly
no test coverage detected