首先我们要获取源码,使用 git 拉取 redis 的代码,使用 git checkout 跳到标签为 1.3.6 处,然后就可以愉快的阅读源码了。
推荐 b 站视频 手写redis ,在阅读源码时,从架构层面分析,忽略一些细枝末节的处理。

主要的代码逻辑集中在 redis.c 大约有一万行左右,从 main() 函数开始分析,一些无关紧要的代码就没有显示出来,以后不再说明。

int main(int argc, char **argv) {

    time_t start;
    
    initServerConfig(); // 对服务器配置的初始化

    initServer(); 初始化服务器,同时注册第一个事件

    aeSetBeforeSleepProc(server.el,beforeSleep); // redis 引入vm 带来的

    aeMain(server.el); // 主循环

    aeDeleteEventLoop(server.el);

    return 0;

}

下面我们就进入 initServer() 看看。

static void initServer() {

    aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL); // 这是定时的任务,现在不做讨论。

    if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,

        acceptHandler , NULL) == AE_ERR) oom("creating file event");
        // 创造了一个事件,并将 acceptHandler 函数注册为回调函数。

    if (server.vm_enabled) vmInit(); // 关于redis 的虚拟内存,在 redis 2.4 后就已经废弃

}

这让我们想要知道 aeCreateFileEventacceptHandler 发生了什么。

int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,

        aeFileProc *proc, void *clientData)

{

    if (fd >= AE_SETSIZE) return AE_ERR;

    aeFileEvent *fe = &eventLoop->events[fd];

  

    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
// 将回调函数使用epoll_ctl注册到 epoll对象上。
        return AE_ERR;

    fe->mask |= mask;

    if (mask & AE_READABLE) fe->rfileProc = proc; 

    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    // 将回调事件赋值到处理上,比如上文的 acceptHandler

    fe->clientData = clientData;

    if (fd > eventLoop->maxfd)

        eventLoop->maxfd = fd;

    return AE_OK;

}
static void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {

 
    cfd = anetAccept(server.neterr, fd, cip, &cport);
    // 通过网络包获取客户端 fd

    if ((c = createClient(cfd)) == NULL) {

        redisLog(REDIS_WARNING,"Error allocating resoures for the client");

        close(cfd); /* May be already closed, just ingore errors */

        return;

    }
    // 创建客户端对象



}

可以很清楚的知道 createClient 是重点,是客户端注册事件。

static redisClient *createClient(int fd) {

    redisClient *c = zmalloc(sizeof(*c));

    if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,

        readQueryFromClient, c) == AE_ERR) {

        freeClient(c);

        return NULL;

    }
//在这里可以看到,同样调用aeCreateFileEvent,注册事件。
    listAddNodeTail(server.clients,c);

    initClientMultiState(c);

    return c;

}

好的下面基本事件已经注册完成,我们可以看看调用 aeMain

void aeMain(aeEventLoop *eventLoop) {
// 显而易见的是这是循环
    eventLoop->stop = 0;

    while (!eventLoop->stop) {

        if (eventLoop->beforesleep != NULL)

            eventLoop->beforesleep(eventLoop); // vm 的遗留

        aeProcessEvents(eventLoop, AE_ALL_EVENTS); // 执行事件

    }

}

主要看 aeProcessEvents

int aeProcessEvents(aeEventLoop *eventLoop, int flags)

{ 
        numevents = aeApiPoll(eventLoop, tvp);
        // I/O多路复用获得,可执行的事件

        for (j = 0; j < numevents; j++) {

            aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];

            int mask = eventLoop->fired[j].mask;

            int fd = eventLoop->fired[j].fd;

            int rfired = 0;

  

        /* note the fe->mask & mask & ... code: maybe an already processed

             * event removed an element that fired and we still didn't

             * processed, so we check if the event is still valid. */

            if (fe->mask & mask & AE_READABLE) {

                rfired = 1;

                fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                // 具体执行回调函数的地方。

            }

            if (fe->mask & mask & AE_WRITABLE) {

                if (!rfired || fe->wfileProc != fe->rfileProc)

                    fe->wfileProc(eventLoop,fd,fe->clientData,mask);
                     // 具体执行回调函数的地方。

            }

            processed++;

        }

    }

    /* Check time events */

    if (flags & AE_TIME_EVENTS)

        processed += processTimeEvents(eventLoop);

  

    return processed; /* return the number of processed file/time events */

}

最后的绝唱 aeApiPoll

static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {

    aeApiState *state = eventLoop->apidata;

    int retval, numevents = 0;
    
    retval = epoll_wait(state->epfd,state->events,AE_SETSIZE,

            tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
// 调用 epoll_wait获得准备好的事件,由上文注册的

    if (retval > 0) {

        int j;

  

        numevents = retval;

        for (j = 0; j < numevents; j++) {

            int mask = 0;

            struct epoll_event *e = state->events+j;

  

            if (e->events & EPOLLIN) mask |= AE_READABLE;

            if (e->events & EPOLLOUT) mask |= AE_WRITABLE;

            eventLoop->fired[j].fd = e->data.fd;

            eventLoop->fired[j].mask = mask;
            // 将结果转化为 redis格式的。

        }

    }
    
    return numevents;

}
posted on 2025-04-18 20:44  嗯嗯好傅  阅读(6)  评论(0)    收藏  举报