// File: /workspace/github_c_makefile_star2_O3/gplessis[P]dotdeb-redis/src/cluster.c
// Function: clusterCron
void clusterCron(void) {
    dictIterator *di;
    dictEntry *de;
    int update_state = 0;
    int orphaned_masters; /* How many masters there are without ok slaves. */
    int max_slaves; /* Max number of ok slaves for a single master. */
    int this_slaves; /* Number of ok slaves for our master (if we are slave). */
    mstime_t min_pong = 0, now = mstime();
    clusterNode *min_pong_node = NULL;
    static unsigned long long iteration = 0;
    mstime_t handshake_timeout;

    iteration++; /* Number of times this function was called so far. */

    /* The handshake timeout is the time after which a handshake node that was
     * not turned into a normal node is removed from the nodes. Usually it is
     * just the NODE_TIMEOUT value, but when NODE_TIMEOUT is too small we use
     * the value of 1 second. */
    handshake_timeout = server.cluster_node_timeout;
    if (handshake_timeout < 1000) handshake_timeout = 1000;

    /* Check if we have disconnected nodes and re-establish the connection. */
    di = dictGetSafeIterator(server.cluster->nodes);
    while((de = dictNext(di)) != NULL) {
        clusterNode *node = dictGetVal(de);

        if (node->flags & (CLUSTER_NODE_MYSELF|CLUSTER_NODE_NOADDR)) continue;

        /* A Node in HANDSHAKE state has a limited lifespan equal to the
         * configured node timeout. */
        if (nodeInHandshake(node) && now - node->ctime > handshake_timeout) {
            clusterDelNode(node);
            continue;
        }

        if (node->link == NULL) {
            int fd;
            mstime_t old_ping_sent;
            clusterLink *link;

            fd = anetTcpNonBlockBindConnect(server.neterr, node->ip,
                node->port+CLUSTER_PORT_INCR, NET_FIRST_BIND_ADDR);
            if (fd == -1) {
                /* We got a synchronous error from connect before
                 * clusterSendPing() had a chance to be called.
                 * If node->ping_sent is zero, failure detection can't work,
                 * so we claim we actually sent a ping now (that will
                 * be really sent as soon as the link is obtained). */
                if (node->ping_sent == 0) node->ping_sent = mstime();
                serverLog(LL_DEBUG, "Unable to connect to "
                    "Cluster Node [%s]:%d -> %s", node->ip,
                    node->port+CLUSTER_PORT_INCR,
                    server.neterr);
                continue;
            }
            link = createClusterLink(node);
            link->fd = fd;
            node->link = link;
            aeCreateFileEvent(server.el,link->fd,AE_READABLE,
                    clusterReadHandler,link);
            /* Queue a PING in the new connection ASAP: this is crucial
             * to avoid false positives in failure detection.
             *
             * If the node is flagged as MEET, we send a MEET message instead
             * of a PING one, to force the receiver to add us in its node
             * table. */
            old_ping_sent = node->ping_sent;
            clusterSendPing(link, node->flags & CLUSTER_NODE_MEET ?
                    CLUSTERMSG_TYPE_MEET : CLUSTERMSG_TYPE_PING);
            if (old_ping_sent) {
                /* If there was an active ping before the link was
                 * disconnected, we want to restore the ping time, otherwise
                 * replaced by the clusterSendPing() call. */
                node->ping_sent = old_ping_sent;
            }
            /* We can clear the flag after the first packet is sent.
             * If we'll never receive a PONG, we'll never send new packets
             * to this node. Instead after the PONG is received and we
             * are no longer in meet/handshake status, we want to send
             * normal PING packets. */
            node->flags &= ~CLUSTER_NODE_MEET;

            serverLog(LL_DEBUG,"Connecting with Node %.40s at %s:%d",
                    node->name, node->ip, node->port+CLUSTER_PORT_INCR);
        }
    }
    dictReleaseIterator(di);

    /* Ping some random node 1 time every 10 iterations, so that we usually ping
     * one random node every second. */
    if (!(iteration % 10)) {
        int j;

        /* Check a few random nodes and ping the one with the oldest
         * pong_received time. */
        for (j = 0; j < 5; j++) {
            de = dictGetRandomKey(server.cluster->nodes);
            clusterNode *this = dictGetVal(de);

            /* Don't ping nodes disconnected or with a ping currently active. */
            if (this->link == NULL || this->ping_sent != 0) continue;
            if (this->flags & (CLUSTER_NODE_MYSELF|CLUSTER_NODE_HANDSHAKE))
                continue;
            if (min_pong_node == NULL || min_pong > this->pong_received) {
                min_pong_node = this;
                min_pong = this->pong_received;
            }
        }
        if (min_pong_node) {
            serverLog(LL_DEBUG,"Pinging node %.40s", min_pong_node->name);
            clusterSendPing(min_pong_node->link, CLUSTERMSG_TYPE_PING);
        }
    }

    /* Iterate nodes to check if we need to flag something as failing.
     * This loop is also responsible to:
     * 1) Check if there are orphaned masters (masters without non failing
     *    slaves).
     * 2) Count the max number of non failing slaves for a single master.
     * 3) Count the number of slaves for our master, if we are a slave. */
    orphaned_masters = 0;
    max_slaves = 0;
    this_slaves = 0;
    di = dictGetSafeIterator(server.cluster->nodes);
    while((de = dictNext(di)) != NULL) {
        clusterNode *node = dictGetVal(de);
        now = mstime(); /* Use an updated time at every iteration. */
        mstime_t delay;

        if (node->flags &
            (CLUSTER_NODE_MYSELF|CLUSTER_NODE_NOADDR|CLUSTER_NODE_HANDSHAKE))
                continue;

        /* Orphaned master check, useful only if the current instance
         * is a slave that may migrate to another master. */
        if (nodeIsSlave(myself) && nodeIsMaster(node) && !nodeFailed(node)) {
            int okslaves = clusterCountNonFailingSlaves(node);

            /* A master is orphaned if it is serving a non-zero number of
             * slots, have no working slaves, but used to have at least one
             * slave, or failed over a master that used to have slaves. */
            if (okslaves == 0 && node->numslots > 0 &&
                node->flags & CLUSTER_NODE_MIGRATE_TO)
            {
                orphaned_masters++;
            }
            if (okslaves > max_slaves) max_slaves = okslaves;
            if (nodeIsSlave(myself) && myself->slaveof == node)
                this_slaves = okslaves;
        }

        /* If we are waiting for the PONG more than half the cluster
         * timeout, reconnect the link: maybe there is a connection
         * issue even if the node is alive. */
        if (node->link && /* is connected */
            now - node->link->ctime >
            server.cluster_node_timeout && /* was not already reconnected */
            node->ping_sent && /* we already sent a ping */
            node->pong_received < node->ping_sent && /* still waiting pong */
            /* and we are waiting for the pong more than timeout/2 */
            now - node->ping_sent > server.cluster_node_timeout/2)
        {
            /* Disconnect the link, it will be reconnected automatically. */
            freeClusterLink(node->link);
        }

        /* If we have currently no active ping in this instance, and the
         * received PONG is older than half the cluster timeout, send
         * a new ping now, to ensure all the nodes are pinged without
         * a too big delay. */
        if (node->link &&
            node->ping_sent == 0 &&
            (now - node->pong_received) > server.cluster_node_timeout/2)
        {
            clusterSendPing(node->link, CLUSTERMSG_TYPE_PING);
            continue;
        }

        /* If we are a master and one of the slaves requested a manual
         * failover, ping it continuously. */
        if (server.cluster->mf_end &&
            nodeIsMaster(myself) &&
            server.cluster->mf_slave == node &&
            node->link)
        {
            clusterSendPing(node->link, CLUSTERMSG_TYPE_PING);
            continue;
        }

        /* Check only if we have an active ping for this instance. */
        if (node->ping_sent == 0) continue;

        /* Compute the delay of the PONG. Note that if we already received
         * the PONG, then node->ping_sent is zero, so can't reach this
         * code at all. */
        delay = now - node->ping_sent;

        if (delay > server.cluster_node_timeout) {
            /* Timeout reached. Set the node as possibly failing if it is
             * not already in this state. */
            if (!(node->flags & (CLUSTER_NODE_PFAIL|CLUSTER_NODE_FAIL))) {
                serverLog(LL_DEBUG,"*** NODE %.40s possibly failing",
                    node->name);
                node->flags |= CLUSTER_NODE_PFAIL;
                update_state = 1;
            }
        }
    }
    dictReleaseIterator(di);

    /* If we are a slave node but the replication is still turned off,
     * enable it if we know the address of our master and it appears to
     * be up. */
    if (nodeIsSlave(myself) &&
        server.masterhost == NULL &&
        myself->slaveof &&
        nodeHasAddr(myself->slaveof))
    {
        replicationSetMaster(myself->slaveof->ip, myself->slaveof->port);
    }

    /* Abourt a manual failover if the timeout is reached. */
    manualFailoverCheckTimeout();

    if (nodeIsSlave(myself)) {
        clusterHandleManualFailover();
        clusterHandleSlaveFailover();
        /* If there are orphaned slaves, and we are a slave among the masters
         * with the max number of non-failing slaves, consider migrating to
         * the orphaned masters. Note that it does not make sense to try
         * a migration if there is no master with at least *two* working
         * slaves. */
        if (orphaned_masters && max_slaves >= 2 && this_slaves == max_slaves)
            clusterHandleSlaveMigration(max_slaves);
    }

    if (update_state || server.cluster->state == CLUSTER_FAIL)
        clusterUpdateState();
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
callq 0x2ffce
movq %rax, %r12
incq 0xac72f(%rip)           # 0x116240
leaq 0x97d90(%rip), %r15     # 0x1018a8
movq 0x9a0(%r15), %rax
movq 0x9b0(%r15), %rcx
cmpq $0x3e9, %rax            # imm = 0x3E9
movl $0x3e8, %ebx            # imm = 0x3E8
cmovgeq %rax, %rbx
movq 0x18(%rcx), %rdi
callq 0x2efe5
movq %rax, %r14
movq %rax, %rdi
callq 0x2f015
testq %rax, %rax
je 0x69cde
movl $0x208, %ecx            # imm = 0x208
addq 0x9345a(%rip), %rcx     # 0xfcfb8
movq %rcx, 0x10(%rsp)
leaq 0x208(%r15), %rcx
movq %rcx, 0x8(%rsp)
movq %rbx, (%rsp)
movq 0x8(%rax), %rbp
movl 0x30(%rbp), %eax
testb $0x50, %al
jne 0x69ccd
testb $0x20, %al
je 0x69b9f
movq %r12, %rax
subq (%rbp), %rax
cmpq %rbx, %rax
jle 0x69b9f
movq %rbp, %rdi
callq 0x6640c
jmp 0x69ccd
cmpq $0x0, 0x8c8(%rbp)
jne 0x69ccd
cmpl $0x0, 0x128(%r15)
je 0x69bc0
movq 0xa8(%r15), %rcx
jmp 0x69bc2
xorl %ecx, %ecx
leaq 0x890(%rbp), %r13
movl 0x8c0(%rbp), %edx
movl $0x2710, %eax           # imm = 0x2710
addl %eax, %edx
movq 0x8(%rsp), %rdi
movq %r13, %rsi
callq 0x2dce0
cmpl $-0x1, %eax
je 0x69c8b
movl %eax, %r15d
movq %r12, %rbx
movq %rbp, %rdi
callq 0x664d7
movq %rax, %r12
movl %r15d, 0x8(%rax)
movq %rax, 0x8c8(%rbp)
leaq 0x97c99(%rip), %rax     # 0x1018a8
movq 0x40(%rax), %rdi
movl %r15d, %esi
movl $0x1, %edx
leaq -0x3694(%rip), %rcx     # 0x6658e
movq %r12, %r8
callq 0x2ce46
movq 0x858(%rbp), %r15
movl 0x30(%rbp), %esi
shrl $0x6, %esi
andl $0x2, %esi
movq %r12, %rdi
callq 0x6834f
testq %r15, %r15
je 0x69c4e
movq %r15, 0x858(%rbp)
andb $0x7f, 0x30(%rbp)
movl 0x8c0(%rbp), %r8d
movl $0x2710, %eax           # imm = 0x2710
addl %eax, %r8d
addq $0x8, %rbp
xorl %edi, %edi
leaq 0x5e8ea(%rip), %rsi     # 0xc8558
movq %rbp, %rdx
movq %r13, %rcx
xorl %eax, %eax
callq 0x2fdad
leaq 0x97c26(%rip), %r15     # 0x1018a8
movq %rbx, %r12
movq (%rsp), %rbx
jmp 0x69ccd
cmpq $0x0, 0x858(%rbp)
jne 0x69ca1
callq 0x2ffce
movq %rax, 0x858(%rbp)
movl 0x8c0(%rbp), %ecx
movl $0x2710, %eax           # imm = 0x2710
addl %eax, %ecx
xorl %edi, %edi
leaq 0x5e871(%rip), %rsi     # 0xc8528
movq %r13, %rdx
movq 0x10(%rsp), %r8
xorl %eax, %eax
callq 0x2fdad
leaq 0x97bdb(%rip), %r15     # 0x1018a8
movq %r14, %rdi
callq 0x2f015
testq %rax, %rax
jne 0x69b73
movq %r14, %rdi
callq 0x2f0dd
movabsq $-0x3333333333333333, %rax # imm = 0xCCCCCCCCCCCCCCCD
imulq 0xac548(%rip), %rax     # 0x116240
rorq %rax
movabsq $0x1999999999999999, %rcx # imm = 0x1999999999999999
cmpq %rcx, %rax
ja 0x69d90
movl $0x5, %ebp
xorl %r14d, %r14d
xorl %ebx, %ebx
movq 0x9b0(%r15), %rax
movq 0x18(%rax), %rdi
callq 0x2f141
movq 0x8(%rax), %rax
cmpq $0x0, 0x8c8(%rax)
je 0x69d65
cmpq $0x0, 0x858(%rax)
jne 0x69d65
testb $0x30, 0x30(%rax)
jne 0x69d65
movq 0x860(%rax), %rcx
testq %rbx, %rbx
je 0x69d5f
cmpq %rcx, %r14
cmovgq %rax, %rbx
cmovgeq %rcx, %r14
jmp 0x69d65
movq %rax, %rbx
movq %rcx, %r14
decl %ebp
jne 0x69d18
testq %rbx, %rbx
je 0x69d90
leaq 0x8(%rbx), %rdx
leaq 0x5e803(%rip), %rsi     # 0xc857c
xorl %edi, %edi
xorl %eax, %eax
callq 0x2fdad
movq 0x8c8(%rbx), %rdi
xorl %esi, %esi
callq 0x6834f
movq 0x9b0(%r15), %rax
movq 0x18(%rax), %rdi
callq 0x2efe5
movq %rax, %r14
movq %rax, %rdi
callq 0x2f015
testq %rax, %rax
je 0x69fb7
movl $0x0, (%rsp)
movl $0x0, 0x8(%rsp)
xorl %r13d, %r13d
xorl %ebp, %ebp
movq 0x8(%rax), %r15
callq 0x2ffce
movl 0x30(%r15), %ecx
testb $0x70, %cl
je 0x69dec
movq %r14, %rdi
callq 0x2f015
testq %rax, %rax
jne 0x69dc8
jmp 0x69fa5
movq %rax, %r12
movl %ecx, %eax
andl $0x9, %eax
cmpl $0x1, %eax
jne 0x69e65
movq 0xac430(%rip), %rax     # 0x116230
movl 0x30(%rax), %edx
andl $0x2, %edx
je 0x69e65
movslq 0x844(%r15), %rsi
testq %rsi, %rsi
jle 0x69e3f
movq 0x848(%r15), %rdi
xorl %r8d, %r8d
xorl %edx, %edx
movq (%rdi,%r8,8), %r9
movb 0x30(%r9), %r9b
andb $0x8, %r9b
cmpb $0x1, %r9b
adcl $0x0, %edx
incq %r8
cmpq %r8, %rsi
jne 0x69e20
testl %edx, %edx
jne 0x69e54
xorl %edx, %edx
cmpl $0x0, 0x840(%r15)
jle 0x69e54
btl $0x8, %ecx
adcl $0x0, 0x8(%rsp)
cmpl %r13d, %edx
cmovgl %edx, %r13d
cmpq %r15, 0x850(%rax)
cmovel %edx, %ebp
movq 0x8c8(%r15), %rdi
movb $0x1, %bl
testq %rdi, %rdi
je 0x69f0d
movq %r12, %rcx
subq (%rdi), %rcx
leaq 0x97a24(%rip), %rax     # 0x1018a8
movq 0x9a0(%rax), %rax
cmpq %rax, %rcx
jle 0x69ece
movq 0x858(%r15), %rcx
testq %rcx, %rcx
je 0x69ece
cmpq %rcx, 0x860(%r15)
jge 0x69ece
movq %r12, %rdx
subq %rcx, %rdx
movq %rax, %rcx
shrq $0x3f, %rcx
addq %rax, %rcx
sarq %rcx
cmpq %rcx, %rdx
jle 0x69ece
callq 0x6651c
movq 0x8c8(%r15), %rdi
testq %rdi, %rdi
je 0x69f0d
cmpq $0x0, 0x858(%r15)
jne 0x69f09
movq 0x860(%r15), %rax
movq %r12, %rcx
subq %rax, %rcx
leaq 0x979bc(%rip), %rax     # 0x1018a8
movq 0x9a0(%rax), %rax
movq %rax, %rdx
shrq $0x3f, %rdx
addq %rax, %rdx
sarq %rdx
cmpq %rdx, %rcx
jg 0x69f99
xorl %ebx, %ebx
jmp 0x69f0f
xorl %edi, %edi
leaq 0x97992(%rip), %rax     # 0x1018a8
movq 0x9b0(%rax), %rax
cmpq $0x0, 0x60058(%rax)
je 0x69f42
movq 0xac302(%rip), %rcx     # 0x116230
testb $0x1, 0x30(%rcx)
je 0x69f42
cmpq %r15, 0x60060(%rax)
setne %al
orb %al, %bl
je 0x69f99
movq 0x858(%r15), %rax
testq %rax, %rax
je 0x69dda
subq %rax, %r12
leaq 0x9794c(%rip), %rax     # 0x1018a8
cmpq 0x9a0(%rax), %r12
jle 0x69dda
testb $0xc, 0x30(%r15)
jne 0x69dda
leaq 0x8(%r15), %rdx
xorl %edi, %edi
leaq 0x5e60e(%rip), %rsi     # 0xc858f
xorl %eax, %eax
callq 0x2fdad
orb $0x4, 0x30(%r15)
movl $0x1, (%rsp)
jmp 0x69dda
xorl %esi, %esi
callq 0x6834f
jmp 0x69dda
cmpl $0x0, 0x8(%rsp)
setne %r15b
cmpl $0x0, (%rsp)
sete %bl
jmp 0x69fc1
movb $0x1, %bl
xorl %ebp, %ebp
xorl %r13d, %r13d
xorl %r15d, %r15d
movq %r14, %rdi
callq 0x2f0dd
movq 0xac260(%rip), %rax     # 0x116230
testb $0x2, 0x30(%rax)
je 0x6a00b
leaq 0x978cb(%rip), %rcx     # 0x1018a8
cmpq $0x0, 0x828(%rcx)
jne 0x6a00b
movq 0x850(%rax), %rdi
testq %rdi, %rdi
je 0x6a00b
testb $0x40, 0x30(%rdi)
jne 0x6a00b
movl 0x8c0(%rdi), %esi
addq $0x890, %rdi            # imm = 0x890
callq 0x46c10
callq 0x69a46
movq 0xac219(%rip), %rax     # 0x116230
testb $0x2, 0x30(%rax)
je 0x6a043
callq 0x69a86
callq 0x694a5
cmpl $0x2, %r13d
setge %al
andb %al, %r15b
cmpb $0x1, %r15b
jne 0x6a043
cmpl %r13d, %ebp
jne 0x6a043
movl %ebp, %edi
callq 0x69829
testb %bl, %bl
je 0x6a05b
leaq 0x9785a(%rip), %rax     # 0x1018a8
movq 0x9b0(%rax), %rax
cmpl $0x1, 0x10(%rax)
jne 0x6a06e
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x692ea
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq