Redis 定时处理机制实现流程

Redis定时器实现原理

1.一个循环体循环检查一个链表

2.链表中的节点主要包含时间戳,回调函数

3.每次循环获取当前系统时间,并与链表节点的时间戳对比

4.如果差值大于时间阈值,则执行链表节点的回调函数,并用当前系统时间更新链表节点的时间戳,然后进入下次循环

Redis定时器实现包含以下几个主要函数

1.一个主循环体aeMain,aeMain不光是定时器还包含其它事件处理,都在这个while中处理

void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
    }
}

2.循环指定的内容,aeProcessEvents中包含了其它事件处理机制,这里只看定时器处理相关的代码

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
    …………
    /* Check time events */
    if (flags & AE_TIME_EVENTS)
        processed += processTimeEvents(eventLoop);
    …………
}

3.processTimeEvents遍历链表,如果时间到了,执行链表节点的回调函数,并更新节点时间戳,进入下次循环

/* 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 代表当前定时器链表的节点数量
    maxId = eventLoop->timeEventNextId-1;
    while(te) {
        long now_sec, now_ms;
        long long id;

        /* Remove events scheduled for deletion. */
        //如果定时器标记为删除执行finalizerProc,并释放该节点
        if (te->id == AE_DELETED_EVENT_ID) {
            aeTimeEvent *next = te->next;
            if (te->prev)
                te->prev->next = te->next;
            else
                eventLoop->timeEventHead = te->next;
            if (te->next)
                te->next->prev = te->prev;
            if (te->finalizerProc)
                te->finalizerProc(eventLoop, te->clientData);
            zfree(te);
            te = next;
            continue;
        }

        /* Make sure we don't process time events created by time events in
         * this iteration. Note that this check is currently useless: we always
         * add new timers on the head, however if we change the implementation
         * detail, this check may be useful again: we keep it here for future
         * defense. */
        if (te->id > maxId) {
            te = te->next;
            continue;
        }
        aeGetTime(&now_sec, &now_ms);
        //如果当前时间超过了定时器设置的when,执行定时器的timeProc函数,如serverCron
        //timeProc执行后如果以后不需要执行了
        //返回AE_NOMORE,则给该定时器赋值DELETE状态,下次循环会删除该节点
        //如果后续还需要继续执行,则返回下次执行的时间间隔,aeAddMillisecondsToNow在
        //when_sec\when_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++;
            if (retval != AE_NOMORE) {
                aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
            } else {
                te->id = AE_DELETED_EVENT_ID;
            }
        }
        te = te->next;
    }
    return processed;
}

链表管理 

1.链表节点,主要包含时间戳、回调函数,回收函数

/* Types and data structures */
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);

/* Time event structure */
typedef struct aeTimeEvent {
    long long id; /* time event identifier. */
    //需要执行的时刻 when = current + time
    long when_sec; /* seconds */
    long when_ms; /* milliseconds */
    aeTimeProc *timeProc;
    aeEventFinalizerProc *finalizerProc;
    void *clientData;
    struct aeTimeEvent *prev;
    struct aeTimeEvent *next;
} aeTimeEvent;

2.创建一个定时器,并注册其回调函数

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) 
    /* Create the timer callback, this is our way to process many background
     * operations incrementally, like clients timeout, eviction of unaccessed
     * expired keys and so forth. */
    if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
        serverPanic("Can't create event loop timers.");
        exit(1);
    }

在aeCreateTimeEvent中申请节点,用回调函数指针赋值节点,并将节点添加到链表中,循环体循环检查链表 


long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
        aeTimeProc *proc, void *clientData,
        aeEventFinalizerProc *finalizerProc)
{
    //产生一个aeTimeEvent结构中的事件id
    long long id = eventLoop->timeEventNextId++;
    aeTimeEvent *te;
    //申请一个新的aeTimeEvent结构
    te = zmalloc(sizeof(*te));
    if (te == NULL) return AE_ERR;
    te->id = id;
    //取当前时间
    aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);
    //需要定时执行的函数,比如serverCron
    te->timeProc = proc;
    //删除定时器时执行finalizerProc
    //serverCron永久定时器注册时finalizerProc为NULL
    te->finalizerProc = finalizerProc;
    //serverCron注册时clientData为NULL
    te->clientData = clientData;
    //将新增的aeTimeEvent添加到表头
    te->prev = NULL;
    te->next = eventLoop->timeEventHead;
    if (te->next)
        te->next->prev = te;
    eventLoop->timeEventHead = te;
    return id;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值