Skip to content

clusterSendPing当中的疑问 #25

@lebron374

Description

@lebron374

这里的while循环当中gossipcount的范围是[0,3),不应该是发送3个节点信息么?
另外,gossip = &(hdr->data.ping.gossip[gossipcount]);这个操作会不会污染后面的内存呢?毕竟gossip的数组大小是1.


// 向指定节点发送一个 PING 或者 PONG 信息
void clusterSendPing(clusterLink link, int type) {
unsigned char buf[sizeof(clusterMsg)];
clusterMsg hdr = (clusterMsg) buf;
int gossipcount = 0, totlen;
/
freshnodes is the number of nodes we can still use to populate the
* gossip section of the ping packet. Basically we start with the nodes
* we have in memory minus two (ourself and the node we are sending the
* message to). Every time we add a node we decrement the counter, so when
* it will drop to <= zero we know there is no more gossip info we can
* send. */
// freshnodes 是用于发送 gossip 信息的计数器
// 每次发送一条信息时,程序将 freshnodes 的值减一
// 当 freshnodes 的数值小于等于 0 时,程序停止发送 gossip 信息
// freshnodes 的数量是节点目前的 nodes 表中的节点数量减去 2
// 这里的 2 指两个节点,一个是 myself 节点(也即是发送信息的这个节点)
// 另一个是接受 gossip 信息的节点
int freshnodes = dictSize(server.cluster->nodes)-2;

// 如果发送的信息是 PING ,那么更新最后一次发送 PING 命令的时间戳
if (link->node && type == CLUSTERMSG_TYPE_PING)
    link->node->ping_sent = mstime();

// 设置信息
clusterBuildMessageHdr(hdr,type);
    
/* Populate the gossip fields */
// 每个节点有 freshnodes 次发送 gossip 信息的机会
// 每次向目标节点发送 2 个被选中节点的 gossip 信息(gossipcount 计数)
while(freshnodes > 0 && gossipcount < 3) {

    // 从 nodes 字典中随机选出一个节点(被选中节点)
    struct dictEntry *de = dictGetRandomKey(server.cluster->nodes);
    clusterNode *this = dictGetVal(de);

    clusterMsgDataGossip *gossip;
    int j;

    /* In the gossip section don't include:
     * 以下节点不能作为被选中节点:
     * 1) Myself.
     *    节点本身。
     * 2) Nodes in HANDSHAKE state.
     *    处于 HANDSHAKE 状态的节点。
     * 3) Nodes with the NOADDR flag set.
     *    带有 NOADDR 标识的节点
     * 4) Disconnected nodes if they don't have configured slots.
     *    因为不处理任何槽而被断开连接的节点 
     */
    if (this == server.cluster->myself ||
        this->flags & (REDIS_NODE_HANDSHAKE|REDIS_NODE_NOADDR) ||
        (this->link == NULL && this->numslots == 0))
    {
            freshnodes--; /* otherwise we may loop forever. */
            continue;
    }

    /* Check if we already added this node */
    // 检查被选中节点是否已经在 hdr->data.ping.gossip 数组里面
    // 如果是的话说明这个节点之前已经被选中了
    // 不要再选中它(否则就会出现重复)
    for (j = 0; j < gossipcount; j++) {
        if (memcmp(hdr->data.ping.gossip[j].nodename,this->name,
                REDIS_CLUSTER_NAMELEN) == 0) break;
    }
    if (j != gossipcount) continue;

    /* Add it */

    // 这个被选中节点有效,计数器减一
    freshnodes--;

    // 指向 gossip 信息结构
    gossip = &(hdr->data.ping.gossip[gossipcount]);

    // 将被选中节点的名字记录到 gossip 信息
    memcpy(gossip->nodename,this->name,REDIS_CLUSTER_NAMELEN);
    // 将被选中节点的 PING 命令发送时间戳记录到 gossip 信息
    gossip->ping_sent = htonl(this->ping_sent);
    // 将被选中节点的 PING 命令回复的时间戳记录到 gossip 信息
    gossip->pong_received = htonl(this->pong_received);
    // 将被选中节点的 IP 记录到 gossip 信息
    memcpy(gossip->ip,this->ip,sizeof(this->ip));
    // 将被选中节点的端口号记录到 gossip 信息
    gossip->port = htons(this->port);
    // 将被选中节点的标识值记录到 gossip 信息
    gossip->flags = htons(this->flags);

    // 这个被选中节点有效,计数器增一
    gossipcount++;
}

// 计算信息长度
totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData);
totlen += (sizeof(clusterMsgDataGossip)*gossipcount);
// 将被选中节点的数量(gossip 信息中包含了多少个节点的信息)
// 记录在 count 属性里面
hdr->count = htons(gossipcount);
// 将信息的长度记录到信息里面
hdr->totlen = htonl(totlen);

// 发送信息
clusterSendMessage(link,buf,totlen);

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions