redis时间事件

来源:互联网 发布:招聘软件排名 编辑:程序博客网 时间:2024/05/16 11:08

数据结构

文件:ae.h

时间事件的三个属性:

  • when :以毫秒格式的 UNIX 时间戳为单位,记录了应该在什么时间点执行事件处理函数。
  • timeProc :事件处理函数。
  • next 指向下一个时间事件,形成链表。
/* Time event structure */typedef struct aeTimeEvent {    long long id; /* time event identifier. */    long when_sec; /* seconds */    long when_ms; /* milliseconds */    aeTimeProc *timeProc;    aeEventFinalizerProc *finalizerProc;    void *clientData;    struct aeTimeEvent *next;} aeTimeEvent;

api

文件:ae.c(v3.0.1 L 203)
函数 aeCreateTimeEvent

long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,        aeTimeProc *proc, void *clientData,        aeEventFinalizerProc *finalizerProc){    long long id = eventLoop->timeEventNextId++;    aeTimeEvent *te;    te = zmalloc(sizeof(*te));    if (te == NULL) return AE_ERR;    te->id = id;    aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);    te->timeProc = proc;    te->finalizerProc = finalizerProc;    te->clientData = clientData;    te->next = eventLoop->timeEventHead;    eventLoop->timeEventHead = te;    return id;}

示例serverCron 使用

redis-server启动时,Redis做了很多初始化的工作,这些工作大多是在initServer()这个函数中执行的,初始化一些相关的list,dict等;调用了aeCreateTimeEvent()函数来初始化一下定时器,定期地执行serverCron()这个函数。

文件redis.c(v3.0.1 L1837)

/* Create the serverCron() time event, that's our main way to process     * background operations. */    if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {        redisPanic("Can't create the serverCron time event.");        exit(1);    }

触发定时任务执行

整个执行流程:
main->aeMain->aeProcessEvents->processTimeEvents->serverCron

文件: ae.c

/* Process time events */static int processTimeEvents(aeEventLoop *eventLoop) {    int processed = 0;    aeTimeEvent *te;    long long maxId;    time_t now = time(NULL);    /* If the system clock is moved to the future, and then set back to the     * right value, time events may be delayed in a random way. Often this     * means that scheduled operations will not be performed soon enough.     *     * Here we try to detect system clock skews, and force all the time     * events to be processed ASAP when this happens: the idea is that     * processing events earlier is less dangerous than delaying them     * indefinitely, and practice suggests it is. */    if (now < eventLoop->lastTime) {        te = eventLoop->timeEventHead;        while(te) {            te->when_sec = 0;            te = te->next;        }    }    eventLoop->lastTime = now;    te = eventLoop->timeEventHead;    maxId = eventLoop->timeEventNextId-1;    while(te) {        long now_sec, now_ms;        long long id;        if (te->id > maxId) {            te = te->next;            continue;        }        aeGetTime(&now_sec, &now_ms);        if (now_sec > te->when_sec ||            (now_sec == te->when_sec && now_ms >= te->when_ms))        {            int retval;            id = te->id;            retval = te->timeProc(eventLoop, id, te->clientData);            processed++;            /* After an event is processed our time event list may             * no longer be the same, so we restart from head.             * Still we make sure to don't process events registered             * by event handlers itself in order to don't loop forever.             * To do so we saved the max ID we want to handle.             *             * FUTURE OPTIMIZATIONS:             * Note that this is NOT great algorithmically. Redis uses             * a single time event so it's not a problem but the right             * way to do this is to add the new elements on head, and             * to flag deleted elements in a special way for later             * deletion (putting references to the nodes to delete into             * another linked list). */            if (retval != AE_NOMORE) {                aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);            } else {                aeDeleteTimeEvent(eventLoop, id);            }            te = eventLoop->timeEventHead;        } else {            te = te->next;        }    }    return processed;

根据 timeProc 函数的返回值,可以将时间事件划分为两类:

  • 如果事件处理函数返回 ae.h/AE_NOMORE ,那么这个事件为单次执行事件:该事件会在指定的时间被处理一次,之后该事件就会被删除,不再执行。
  • 如果事件处理函数返回一个非 AE_NOMORE 的整数值,那么这个事件为循环执行事件:该事件会在指定的时间被处理,之后它会按照事件处理函数的返回值,更新事件的 when 属性,让这个事件在之后的某个时间点再次运行,并以这种方式一直更新并运行下去。
0 0
原创粉丝点击