// File: /workspace/github_c_makefile_star2_O1/nilyang[P]redis-tdd-annotation/src/cluster.c
// Function: clusterSendFailoverAuthIfNeeded
void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {

    // 请求节点的主节点
    clusterNode *master = node->slaveof;

    // 请求节点的当前配置纪元
    uint64_t requestCurrentEpoch = ntohu64(request->currentEpoch);

    // 请求节点想要获得投票的纪元
    uint64_t requestConfigEpoch = ntohu64(request->configEpoch);

    // 请求节点的槽布局
    unsigned char *claimed_slots = request->myslots;
    int force_ack = request->mflags[0] & CLUSTERMSG_FLAG0_FORCEACK;
    int j;

    /* IF we are not a master serving at least 1 slot, we don't have the
     * right to vote, as the cluster size in Redis Cluster is the number
     * of masters serving at least one slot, and quorum is the cluster
     * size + 1 */

    // 如果节点为从节点，或者是一个没有处理任何槽的主节点，
    // 那么它没有投票权
    if (nodeIsSlave(myself) || myself->numslots == 0) return;

    /* Request epoch must be >= our currentEpoch. */
    // 请求的配置纪元必须大于等于当前节点的配置纪元
    if (requestCurrentEpoch < server.cluster->currentEpoch) return;

    /* I already voted for this epoch? Return ASAP. */
    // 已经投过票了
    if (server.cluster->lastVoteEpoch == server.cluster->currentEpoch) return;

    /* Node must be a slave and its master down.
     * The master can be non failing if the request is flagged
     * with CLUSTERMSG_FLAG0_FORCEACK (manual failover). */
    if (nodeIsMaster(node) || master == NULL ||
        (!nodeFailed(master) && !force_ack)) return;

    /* We did not voted for a slave about this master for two
     * times the node timeout. This is not strictly needed for correctness
     * of the algorithm but makes the base case more linear. */
    // 如果之前一段时间已经对请求节点进行过投票，那么不进行投票
    if (mstime() - node->slaveof->voted_time < server.cluster_node_timeout * 2)
        return;

    /* The slave requesting the vote must have a configEpoch for the claimed
     * slots that is >= the one of the masters currently serving the same
     * slots in the current configuration. */
    for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) {

        // 跳过未指派节点
        if (bitmapTestBit(claimed_slots, j) == 0) continue;

        // 查找是否有某个槽的配置纪元大于节点请求的纪元
        if (server.cluster->slots[j] == NULL ||
            server.cluster->slots[j]->configEpoch <= requestConfigEpoch)
        {
            continue;
        }

        // 如果有的话，说明节点请求的纪元已经过期，没有必要进行投票
        /* If we reached this point we found a slot that in our current slots
         * is served by a master with a greater configEpoch than the one claimed
         * by the slave requesting our vote. Refuse to vote for this slave. */
        return;
    }

    /* We can vote for this slave. */
    // 为节点投票
    clusterSendFailoverAuth(node);
    // 更新时间值
    server.cluster->lastVoteEpoch = server.cluster->currentEpoch;
    node->slaveof->voted_time = mstime();
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rsi, %r14
movq %rdi, %rbx
movq 0x850(%rdi), %rbp
movq 0x10(%rsi), %rdi
callq 0x566c1
movq %rax, %r12
movq 0x18(%r14), %rdi
callq 0x566c1
movq %rax, %r15
movq 0x8b76f(%rip), %rax     # 0xde628
testb $0x2, 0x30(%rax)
jne 0x52faa
cmpl $0x0, 0x840(%rax)
je 0x52faa
leaq 0x770d1(%rip), %r13     # 0xc9fa8
movq 0x7d0(%r13), %rax
movq 0x8(%rax), %rcx
cmpq %rcx, %r12
jb 0x52faa
cmpq %rcx, 0x60070(%rax)
je 0x52faa
testq %rbp, %rbp
sete %al
orb 0x30(%rbx), %al
testb $0x1, %al
jne 0x52faa
testb $0x8, 0x30(%rbp)
jne 0x52f1e
movb 0x89d(%r14), %al
andb $0x2, %al
je 0x52faa
callq 0x232a3
movq 0x850(%rbx), %rcx
subq 0x870(%rcx), %rax
movq 0x7c0(%r13), %rcx
addq %rcx, %rcx
cmpq %rcx, %rax
jl 0x52faa
movq 0x7d0(%r13), %rax
xorl %ecx, %ecx
movl %ecx, %edx
shrl $0x3, %edx
movzbl 0x50(%r14,%rdx), %edx
movl %ecx, %esi
andl $0x7, %esi
btl %esi, %edx
jae 0x52f71
movq 0x40028(%rax,%rcx,8), %rdx
testq %rdx, %rdx
je 0x52f71
cmpq %r15, 0x38(%rdx)
ja 0x52faa
incq %rcx
cmpq $0x4000, %rcx           # imm = 0x4000
jne 0x52f49
movq %rbx, %rdi
callq 0x534a8
movq 0x7d0(%r13), %rax
movq 0x8(%rax), %rcx
movq %rcx, 0x60070(%rax)
callq 0x232a3
movq 0x850(%rbx), %rcx
movq %rax, 0x870(%rcx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq