// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/cluster.c
// Function: clusterSendPing
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 */
    // 从当前节点已知的节点中随机选出两个节点
    // 并通过这条消息捎带给目标节点，从而实现 gossip 协议

    // 每个节点有 freshnodes 次发送 gossip 信息的机会
    // 每次向目标节点发送 2 个被选中节点的 gossip 信息（gossipcount 计数）
    while(freshnodes > 0 && gossipcount < 3) {
        // 从 nodes 字典中随机选出一个节点（被选中节点）
        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 == 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);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1120, %rsp           # imm = 0x1120
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
leaq -0x10e0(%rbp), %rax
movq %rax, -0x10e8(%rbp)
movl $0x0, -0x10ec(%rbp)
leaq 0xa7477(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %rax
movq 0x28(%rax), %rax
leaq 0xa7461(%rip), %rcx     # 0x1138f8
movq 0x7d0(%rcx), %rcx
movq 0x18(%rcx), %rcx
addq 0x48(%rcx), %rax
subq $0x2, %rax
movl %eax, -0x10f4(%rbp)
movq -0x8(%rbp), %rax
cmpq $0x0, 0x20(%rax)
je 0x6c4d8
cmpl $0x0, -0xc(%rbp)
jne 0x6c4d8
callq 0x252e0
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq 0x20(%rax), %rax
movq %rcx, 0x858(%rax)
movq -0x10e8(%rbp), %rdi
movl -0xc(%rbp), %esi
callq 0x6cd20
xorl %eax, %eax
cmpl $0x0, -0x10f4(%rbp)
movb %al, -0x1115(%rbp)
jle 0x6c508
cmpl $0x3, -0x10ec(%rbp)
setl %al
movb %al, -0x1115(%rbp)
movb -0x1115(%rbp), %al
testb $0x1, %al
jne 0x6c517
jmp 0x6c71d
leaq 0xa73da(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %rdi
callq 0x24470
movq %rax, -0x1100(%rbp)
movq -0x1100(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x1108(%rbp)
movq -0x1108(%rbp), %rax
cmpq 0xbba23(%rip), %rax     # 0x127f78
je 0x6c58a
movq -0x1108(%rbp), %rax
movl 0x30(%rax), %eax
andl $0x60, %eax
cmpl $0x0, %eax
jne 0x6c58a
movq -0x1108(%rbp), %rax
cmpq $0x0, 0x8c0(%rax)
jne 0x6c59e
movq -0x1108(%rbp), %rax
cmpl $0x0, 0x840(%rax)
jne 0x6c59e
movl -0x10f4(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x10f4(%rbp)
jmp 0x6c4e7
movl $0x0, -0x1114(%rbp)
movl -0x1114(%rbp), %eax
cmpl -0x10ec(%rbp), %eax
jge 0x6c601
movq -0x10e8(%rbp), %rdi
addq $0x8a0, %rdi            # imm = 0x8A0
movslq -0x1114(%rbp), %rax
imulq $0x68, %rax, %rax
addq %rax, %rdi
movq -0x1108(%rbp), %rsi
addq $0x8, %rsi
movl $0x28, %edx
callq 0x1f950
cmpl $0x0, %eax
jne 0x6c5ee
jmp 0x6c601
jmp 0x6c5f0
movl -0x1114(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1114(%rbp)
jmp 0x6c5a8
movl -0x1114(%rbp), %eax
cmpl -0x10ec(%rbp), %eax
je 0x6c614
jmp 0x6c4e7
movl -0x10f4(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x10f4(%rbp)
movq -0x10e8(%rbp), %rax
addq $0x8a0, %rax            # imm = 0x8A0
movslq -0x10ec(%rbp), %rcx
imulq $0x68, %rcx, %rcx
addq %rcx, %rax
movq %rax, -0x1110(%rbp)
movq -0x1110(%rbp), %rdi
movq -0x1108(%rbp), %rsi
addq $0x8, %rsi
movl $0x28, %edx
callq 0x1fbf0
movq -0x1108(%rbp), %rax
movq 0x858(%rax), %rax
movl %eax, %edi
callq 0x1fab0
movl %eax, %ecx
movq -0x1110(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x1108(%rbp), %rax
movq 0x860(%rax), %rax
movl %eax, %edi
callq 0x1fab0
movl %eax, %ecx
movq -0x1110(%rbp), %rax
movl %ecx, 0x2c(%rax)
movq -0x1110(%rbp), %rdi
addq $0x30, %rdi
movq -0x1108(%rbp), %rsi
addq $0x888, %rsi            # imm = 0x888
movl $0x2e, %edx
callq 0x1fbf0
movq -0x1108(%rbp), %rax
movl 0x8b8(%rax), %eax
movzwl %ax, %edi
callq 0x1f270
movw %ax, %cx
movq -0x1110(%rbp), %rax
movw %cx, 0x5e(%rax)
movq -0x1108(%rbp), %rax
movl 0x30(%rax), %eax
movzwl %ax, %edi
callq 0x1f270
movw %ax, %cx
movq -0x1110(%rbp), %rax
movw %cx, 0x60(%rax)
movl -0x10ec(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10ec(%rbp)
jmp 0x6c4e7
movl $0x8a0, -0x10f0(%rbp)   # imm = 0x8A0
movslq -0x10ec(%rbp), %rax
imulq $0x68, %rax, %rcx
movslq -0x10f0(%rbp), %rax
addq %rcx, %rax
movl %eax, -0x10f0(%rbp)
movl -0x10ec(%rbp), %eax
movzwl %ax, %edi
callq 0x1f270
movw %ax, %cx
movq -0x10e8(%rbp), %rax
movw %cx, 0xe(%rax)
movl -0x10f0(%rbp), %edi
callq 0x1fab0
movl %eax, %ecx
movq -0x10e8(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x8(%rbp), %rdi
leaq -0x10e0(%rbp), %rsi
movslq -0x10f0(%rbp), %rdx
callq 0x6cbe0
addq $0x1120, %rsp           # imm = 0x1120
popq %rbp
retq
nopw %cs:(%rax,%rax)