// File: /workspace/github_c_makefile_star2_O1/zhou-yuxin[P]redis-aof-no-cow/src/cluster.c
// Function: clusterHandleSlaveFailover
void clusterHandleSlaveFailover(void) {
    mstime_t data_age;
    mstime_t auth_age = mstime() - server.cluster->failover_auth_time;
    int needed_quorum = (server.cluster->size / 2) + 1;
    int manual_failover = server.cluster->mf_end != 0 &&
                          server.cluster->mf_can_start;
    mstime_t auth_timeout, auth_retry_time;

    server.cluster->todo_before_sleep &= ~CLUSTER_TODO_HANDLE_FAILOVER;

    /* Compute the failover timeout (the max time we have to send votes
     * and wait for replies), and the failover retry time (the time to wait
     * before trying to get voted again).
     *
     * Timeout is MIN(NODE_TIMEOUT*2,2000) milliseconds.
     * Retry is two times the Timeout.
     */
    auth_timeout = server.cluster_node_timeout*2;
    if (auth_timeout < 2000) auth_timeout = 2000;
    auth_retry_time = auth_timeout*2;

    /* Pre conditions to run the function, that must be met both in case
     * of an automatic or manual failover:
     * 1) We are a slave.
     * 2) Our master is flagged as FAIL, or this is a manual failover.
     * 3) It is serving slots. */
    if (nodeIsMaster(myself) ||
        myself->slaveof == NULL ||
        (!nodeFailed(myself->slaveof) && !manual_failover) ||
        myself->slaveof->numslots == 0)
    {
        /* There are no reasons to failover, so we set the reason why we
         * are returning without failing over to NONE. */
        server.cluster->cant_failover_reason = CLUSTER_CANT_FAILOVER_NONE;
        return;
    }

    /* Set data_age to the number of seconds we are disconnected from
     * the master. */
    if (server.repl_state == REPL_STATE_CONNECTED) {
        data_age = (mstime_t)(server.unixtime - server.master->lastinteraction)
                   * 1000;
    } else {
        data_age = (mstime_t)(server.unixtime - server.repl_down_since) * 1000;
    }

    /* Remove the node timeout from the data age as it is fine that we are
     * disconnected from our master at least for the time it was down to be
     * flagged as FAIL, that's the baseline. */
    if (data_age > server.cluster_node_timeout)
        data_age -= server.cluster_node_timeout;

    /* Check if our data is recent enough according to the slave validity
     * factor configured by the user.
     *
     * Check bypassed for manual failovers. */
    if (server.cluster_slave_validity_factor &&
        data_age >
        (((mstime_t)server.repl_ping_slave_period * 1000) +
         (server.cluster_node_timeout * server.cluster_slave_validity_factor)))
    {
        if (!manual_failover) {
            clusterLogCantFailover(CLUSTER_CANT_FAILOVER_DATA_AGE);
            return;
        }
    }

    /* If the previous failover attempt timedout and the retry time has
     * elapsed, we can setup a new one. */
    if (auth_age > auth_retry_time) {
        server.cluster->failover_auth_time = mstime() +
            500 + /* Fixed delay of 500 milliseconds, let FAIL msg propagate. */
            random() % 500; /* Random delay between 0 and 500 milliseconds. */
        server.cluster->failover_auth_count = 0;
        server.cluster->failover_auth_sent = 0;
        server.cluster->failover_auth_rank = clusterGetSlaveRank();
        /* We add another delay that is proportional to the slave rank.
         * Specifically 1 second * rank. This way slaves that have a probably
         * less updated replication offset, are penalized. */
        server.cluster->failover_auth_time +=
            server.cluster->failover_auth_rank * 1000;
        /* However if this is a manual failover, no delay is needed. */
        if (server.cluster->mf_end) {
            server.cluster->failover_auth_time = mstime();
            server.cluster->failover_auth_rank = 0;
        }
        serverLog(LL_WARNING,
            "Start of election delayed for %lld milliseconds "
            "(rank #%d, offset %lld).",
            server.cluster->failover_auth_time - mstime(),
            server.cluster->failover_auth_rank,
            replicationGetSlaveOffset());
        /* Now that we have a scheduled election, broadcast our offset
         * to all the other slaves so that they'll updated their offsets
         * if our offset is better. */
        clusterBroadcastPong(CLUSTER_BROADCAST_LOCAL_SLAVES);
        return;
    }

    /* It is possible that we received more updated offsets from other
     * slaves for the same master since we computed our election delay.
     * Update the delay if our rank changed.
     *
     * Not performed if this is a manual failover. */
    if (server.cluster->failover_auth_sent == 0 &&
        server.cluster->mf_end == 0)
    {
        int newrank = clusterGetSlaveRank();
        if (newrank > server.cluster->failover_auth_rank) {
            long long added_delay =
                (newrank - server.cluster->failover_auth_rank) * 1000;
            server.cluster->failover_auth_time += added_delay;
            server.cluster->failover_auth_rank = newrank;
            serverLog(LL_WARNING,
                "Slave rank updated to #%d, added %lld milliseconds of delay.",
                newrank, added_delay);
        }
    }

    /* Return ASAP if we can't still start the election. */
    if (mstime() < server.cluster->failover_auth_time) {
        clusterLogCantFailover(CLUSTER_CANT_FAILOVER_WAITING_DELAY);
        return;
    }

    /* Return ASAP if the election is too old to be valid. */
    if (auth_age > auth_timeout) {
        clusterLogCantFailover(CLUSTER_CANT_FAILOVER_EXPIRED);
        return;
    }

    /* Ask for votes if needed. */
    if (server.cluster->failover_auth_sent == 0) {
        server.cluster->currentEpoch++;
        server.cluster->failover_auth_epoch = server.cluster->currentEpoch;
        serverLog(LL_WARNING,"Starting a failover election for epoch %llu.",
            (unsigned long long) server.cluster->currentEpoch);
        clusterRequestFailoverAuth();
        server.cluster->failover_auth_sent = 1;
        clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|
                             CLUSTER_TODO_UPDATE_STATE|
                             CLUSTER_TODO_FSYNC_CONFIG);
        return; /* Wait for replies. */
    }

    /* Check if we reached the quorum. */
    if (server.cluster->failover_auth_count >= needed_quorum) {
        /* We have the quorum, we can finally failover the master. */

        serverLog(LL_WARNING,
            "Failover election won: I'm the new master.");

        /* Update my configEpoch to the epoch of the election. */
        if (myself->configEpoch < server.cluster->failover_auth_epoch) {
            myself->configEpoch = server.cluster->failover_auth_epoch;
            serverLog(LL_WARNING,
                "configEpoch set to %llu after successful failover",
                (unsigned long long) myself->configEpoch);
        }

        /* Take responsability for the cluster slots. */
        clusterFailoverReplaceYourMaster();
    } else {
        clusterLogCantFailover(CLUSTER_CANT_FAILOVER_WAITING_VOTES);
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
pushq %rax
callq 0x330c8
movq %rax, %rbx
leaq 0x9984f(%rip), %r14     # 0x106858
movq 0x9a0(%r14), %rax
movq 0x60058(%rax), %rcx
testq %rcx, %rcx
je 0x6d028
cmpl $0x0, 0x60070(%rax)
setne %dl
jmp 0x6d02a
xorl %edx, %edx
movl 0x14(%rax), %ebp
subq 0x60030(%rax), %rbx
andb $-0x2, 0x60080(%rax)
movq 0x990(%r14), %rsi
leaq (%rsi,%rsi), %rdi
cmpq $0x7d1, %rdi            # imm = 0x7D1
movl $0x7d0, %r15d           # imm = 0x7D0
cmovgeq %rdi, %r15
movq 0xae172(%rip), %rdi     # 0x11b1d0
testb $0x1, 0x30(%rdi)
jne 0x6d211
movq 0x850(%rdi), %rdi
testq %rdi, %rdi
je 0x6d211
movb 0x30(%rdi), %r8b
shrb $0x3, %r8b
orb %dl, %r8b
testb $0x1, %r8b
je 0x6d211
cmpl $0x0, 0x840(%rdi)
je 0x6d211
movslq 0x9ac(%r14), %rdi
testq %rdi, %rdi
je 0x6d10d
movq 0x968(%r14), %r8
movl $0x88, %r9d
addq 0x828(%r14), %r9
leaq 0x878(%r14), %r10
cmpl $0xf, 0x83c(%r14)
cmoveq %r9, %r10
subq (%r10), %r8
imulq $0x3e8, %r8, %r8        # imm = 0x3E8
xorl %r9d, %r9d
cmpq %rsi, %r8
cmovgq %rsi, %r9
subq %r9, %r8
movslq 0x7b8(%r14), %r9
imulq $0x3e8, %r9, %r9        # imm = 0x3E8
imulq %rsi, %rdi
addq %r9, %rdi
cmpq %rdi, %r8
setle %sil
orb %dl, %sil
testb $0x1, %sil
je 0x6d294
leaq (%r15,%r15), %rdx
cmpq %rdx, %rbx
jle 0x6d226
callq 0x330c8
movq %rax, %rbx
callq 0x26a40
movq %rax, %rcx
movabsq $0x20c49ba5e353f7cf, %rdx # imm = 0x20C49BA5E353F7CF
imulq %rdx
movq %rdx, %rax
shrq $0x3f, %rax
sarq $0x6, %rdx
addq %rax, %rdx
imulq $0x1f4, %rdx, %rax      # imm = 0x1F4
subq %rax, %rcx
addq $0x1f4, %rbx            # imm = 0x1F4
addq %rcx, %rbx
movq 0x9a0(%r14), %rax
movq %rbx, 0x60030(%rax)
movq $0x0, 0x60038(%rax)
callq 0x6cbeb
movq 0x9a0(%r14), %rcx
movl %eax, 0x60040(%rcx)
imull $0x3e8, %eax, %eax      # imm = 0x3E8
cltq
addq %rax, 0x60030(%rcx)
cmpq $0x0, 0x60058(%rcx)
je 0x6d1ba
callq 0x330c8
movq 0x9a0(%r14), %rcx
movq %rax, 0x60030(%rcx)
movl $0x0, 0x60040(%rcx)
movq 0x9a0(%r14), %rax
movq 0x60030(%rax), %rbx
callq 0x330c8
subq %rax, %rbx
movq 0x9a0(%r14), %rax
movl 0x60040(%rax), %ebp
callq 0x4a7d1
leaq 0x5e125(%rip), %rsi     # 0xcb30e
movl $0x3, %edi
movq %rbx, %rdx
movl %ebp, %ecx
movq %rax, %r8
xorl %eax, %eax
callq 0x32ea6
movl $0x1, %edi
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x6c7fa
movl $0x0, 0x60050(%rax)
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
testq %rcx, %rcx
jne 0x6d275
cmpl $0x0, 0x6003c(%rax)
jne 0x6d275
callq 0x6cbeb
movq 0x9a0(%r14), %rdx
movl %eax, %ecx
subl 0x60040(%rdx), %ecx
jle 0x6d275
imull $0x3e8, %ecx, %ecx      # imm = 0x3E8
movslq %ecx, %rcx
addq %rcx, 0x60030(%rdx)
movl %eax, 0x60040(%rdx)
leaq 0x5e0f0(%rip), %rsi     # 0xcb357
movl $0x3, %edi
movl %eax, %edx
xorl %eax, %eax
callq 0x32ea6
callq 0x330c8
movq 0x9a0(%r14), %rcx
cmpq 0x60030(%rcx), %rax
jge 0x6d29e
movl $0x2, %edi
jmp 0x6d36b
movl $0x1, %edi
jmp 0x6d36b
cmpq %r15, %rbx
jle 0x6d2ad
movl $0x3, %edi
jmp 0x6d36b
cmpl $0x0, 0x6003c(%rcx)
je 0x6d31f
movl %ebp, %eax
shrl $0x1f, %eax
addl %ebp, %eax
sarl %eax
cmpl %eax, 0x60038(%rcx)
jle 0x6d366
leaq 0x5e0ef(%rip), %rsi     # 0xcb3c1
movl $0x3, %edi
xorl %eax, %eax
callq 0x32ea6
movq 0xadeeb(%rip), %rax     # 0x11b1d0
movq 0x9a0(%r14), %rcx
movq 0x60048(%rcx), %rdx
cmpq %rdx, 0x38(%rax)
jae 0x6d310
movq %rdx, 0x38(%rax)
leaq 0x5e0e8(%rip), %rsi     # 0xcb3ec
movl $0x3, %edi
xorl %eax, %eax
callq 0x32ea6
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x6cd4f
movq 0x8(%rcx), %rdx
incq %rdx
movq %rdx, 0x8(%rcx)
movq %rdx, 0x60048(%rcx)
leaq 0x5e05c(%rip), %rsi     # 0xcb394
movl $0x3, %edi
xorl %eax, %eax
callq 0x32ea6
callq 0x6caff
movq 0x9a0(%r14), %rax
movl $0x1, 0x6003c(%rax)
orb $0xe, 0x60080(%rax)
jmp 0x6d21b
movl $0x4, %edi
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x6cc7b