// File: /workspace/github_c_makefile_star2_O2/gplessis[P]dotdeb-redis/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 0x2b8ae
movq %rax, %rbx
leaq 0x9b032(%rip), %r14     # 0xf98a8
movq 0x9b0(%r14), %rcx
movl 0x14(%rcx), %eax
pushq $0x2
popq %rsi
cltd
idivl %esi
movl %eax, %ebp
movq 0x60058(%rcx), %rax
testq %rax, %rax
je 0x5e8a0
cmpl $0x0, 0x60070(%rcx)
setne %dl
jmp 0x5e8a2
xorl %edx, %edx
subq 0x60030(%rcx), %rbx
andb $-0x2, 0x60080(%rcx)
movq 0x9a0(%r14), %rsi
leaq (%rsi,%rsi), %rdi
cmpq $0x7d1, %rdi            # imm = 0x7D1
movl $0x7d0, %r15d           # imm = 0x7D0
cmovgeq %rdi, %r15
movq 0xaf95d(%rip), %rdi     # 0x10e230
testb $0x1, 0x30(%rdi)
jne 0x5ea57
movq 0x850(%rdi), %rdi
testq %rdi, %rdi
je 0x5ea57
movb 0x30(%rdi), %r8b
shrb $0x3, %r8b
orb %dl, %r8b
testb $0x1, %r8b
je 0x5ea57
cmpl $0x0, 0x840(%rdi)
je 0x5ea57
movslq 0x9bc(%r14), %rdi
testq %rdi, %rdi
je 0x5e982
movq 0x978(%r14), %r8
movl $0x88, %r9d
addq 0x838(%r14), %r9
leaq 0x888(%r14), %r10
cmpl $0xf, 0x84c(%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 0x7c8(%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 0x5ead2
leaq (%r15,%r15), %rdx
cmpq %rdx, %rbx
jle 0x5ea69
callq 0x2b8ae
movq %rax, %rbx
callq 0x26a30
movl $0x1f4, %ecx            # imm = 0x1F4
cqto
idivq %rcx
addq %rcx, %rbx
addq %rdx, %rbx
movq 0x9b0(%r14), %rax
movq %rbx, 0x60030(%rax)
andq $0x0, 0x60038(%rax)
callq 0x5e4be
movq 0x9b0(%r14), %rcx
movl %eax, 0x60040(%rcx)
imull $0x3e8, %eax, %eax      # imm = 0x3E8
movslq %eax, %rbx
addq 0x60030(%rcx), %rbx
movq %rbx, 0x60030(%rcx)
cmpq $0x0, 0x60058(%rcx)
je 0x5ea12
callq 0x2b8ae
movq %rax, %rbx
movq 0x9b0(%r14), %rax
movq %rbx, 0x60030(%rax)
andl $0x0, 0x60040(%rax)
callq 0x2b8ae
subq %rax, %rbx
movq 0x9b0(%r14), %rax
movl 0x60040(%rax), %ebp
callq 0x3fee6
leaq 0x5a94b(%rip), %rsi     # 0xb937e
pushq $0x3
popq %rdi
movq %rbx, %rdx
movl %ebp, %ecx
movq %rax, %r8
xorl %eax, %eax
callq 0x2b699
pushq $0x1
popq %rdi
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x5e1f1
andl $0x0, 0x60050(%rcx)
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
testq %rax, %rax
jne 0x5eab6
cmpl $0x0, 0x6003c(%rcx)
jne 0x5eab6
callq 0x5e4be
movq 0x9b0(%r14), %rdx
movl %eax, %ecx
subl 0x60040(%rdx), %ecx
jle 0x5eab6
imull $0x3e8, %ecx, %ecx      # imm = 0x3E8
movslq %ecx, %rcx
addq %rcx, 0x60030(%rdx)
movl %eax, 0x60040(%rdx)
leaq 0x5a91d(%rip), %rsi     # 0xb93c7
pushq $0x3
popq %rdi
movl %eax, %edx
xorl %eax, %eax
callq 0x2b699
callq 0x2b8ae
movq 0x9b0(%r14), %rcx
cmpq 0x60030(%rcx), %rax
jge 0x5ead9
pushq $0x2
jmp 0x5eb91
pushq $0x1
jmp 0x5eb91
cmpq %r15, %rbx
jle 0x5eae5
pushq $0x3
jmp 0x5eb91
cmpl $0x0, 0x6003c(%rcx)
je 0x5eb4a
cmpl %ebp, 0x60038(%rcx)
jle 0x5eb8f
leaq 0x5a930(%rip), %rsi     # 0xb9431
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x2b699
movq 0xaf71e(%rip), %rax     # 0x10e230
movq 0x9b0(%r14), %rcx
movq 0x60048(%rcx), %rdx
cmpq %rdx, 0x38(%rax)
jae 0x5eb3b
movq %rdx, 0x38(%rax)
leaq 0x5a92b(%rip), %rsi     # 0xb945c
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x2b699
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x5e616
movq 0x8(%rcx), %rdx
incq %rdx
movq %rdx, 0x8(%rcx)
movq %rdx, 0x60048(%rcx)
leaq 0x5a8a1(%rip), %rsi     # 0xb9404
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x2b699
callq 0x5e3d8
movq 0x9b0(%r14), %rax
movl $0x1, 0x6003c(%rax)
orb $0xe, 0x60080(%rax)
jmp 0x5ea5e
pushq $0x4
popq %rdi
addq $0x8, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x5e544