首页 > 代码库 > Redis Cluster 的实现 - 初始化(2)

Redis Cluster 的实现 - 初始化(2)

 

  2) 在监听套接口上通过调用 aeCreateFileEvent() 设置事件处理器,从签名的调用可以看到设置的 ACCEPT 事件处理器为 clusterAcceptHandler(),
    

aeCreateFileEvent(server.el, server.cfd[j], AE_READABLE, clusterAcceptHandler, NULL);

 

// 设置事件处理器    
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
      aeFileProc *proc, void *clientData)
{
    if (fd >= eventLoop->setsize) {
        errno = ERANGE;
        return AE_ERR;
    }
    aeFileEvent *fe = &eventLoop->events[fd];
    
    // 在文件描述符 fd 上设置添加事件
    // 会根据不同系统平台选择相应的 I/O 模型
    // 如: Linux 下的 epoll
    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
        return AE_ERR;
        
    fe->mask |= mask;
    
    // 分别针对 read/write 事件设置 事件处理器
    // 这里设置针对 READ 事件处理的为 clusterAcceptHandler()
    if (mask & AE_READABLE) fe->rfileProc = proc;
    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    fe->clientData = clientData;
    if (fd > eventLoop->maxfd)
        eventLoop->maxfd = fd;
    return AE_OK;
}

    
    如上设置添加 ACCEPT 事件处理器后,当有新的连接过来后,会回调 clusterAcceptHandler() 来处理新的连接。
    

// 设置每次回调时最多处理 1000 个连接
#define MAX_CLUSTER_ACCEPTS_PER_CALL 1000
// fd 为 监听套接字
// privdata 为在调用 aeCreateFileEvent() 时设置的 clientdata 参数,这里为 NULL
void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    int cport, cfd;
    int max = MAX_CLUSTER_ACCEPTS_PER_CALL;
    char cip[REDIS_IP_STR_LEN];
    clusterLink *link;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(mask);
    REDIS_NOTUSED(privdata);
    /* If the server is starting up, don‘t accept cluster connections:
     * UPDATE messages may interact with the database content. */
    if (server.masterhost == NULL && server.loading) return;
    
    // 循环 MAX_CLUSTER_ACCEPTS_PER_CALL 次来接受新的连接
    while(max--) {
        
        // 客户端连接的描述符为 cfg
        // cip 为客户端地址
        // cport 为已连接 socket 的本地端口
        cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
        if (cfd == ANET_ERR) {
            if (errno != EWOULDBLOCK)
                redisLog(REDIS_VERBOSE,
                    "Accepting cluster node: %s", server.neterr);
            return;
        }
        
        // 这里同样设置 连接 socket 为 非阻塞
        anetNonBlock(NULL,cfd);
        
        // 并且打开 socket 选项 TCP_NODELAY(禁止 TCP 的 Nagle 算法)
        anetEnableTcpNoDelay(NULL,cfd);
        /* Use non-blocking I/O for cluster messages. */
        redisLog(REDIS_VERBOSE,"Accepted cluster node %s:%d", cip, cport);
        
        /* Create a link object we use to handle the connection.
         * It gets passed to the readable handler when data is available.
         * Initiallly the link->node pointer is set to NULL as we don‘t know
         * which node is, but the right node is references once we know the
         * node identity. */
        link = createClusterLink(NULL);
        link->fd = cfd;
        aeCreateFileEvent(server.el,cfd,AE_READABLE,clusterReadHandler,link);
    }
}

 

    在成功接受客户端连接(这里其实表示其他 节点 的连接)后,创建 cluster 链路,并进行初始化,设置 read 事件处理器 clusterReadHandler。
    
  关于 redis cluster 的各个节点的初始化部分基本结束,下面就是等着接受连接,处理接收的数据,组件 cluster。
    
    [下一篇准备分析一下 clusterReadHandler 的实现。]

本文出自 “安静的疯子” 博客,请务必保留此出处http://quietmadman.blog.51cto.com/3269500/1558685

Redis Cluster 的实现 - 初始化(2)