// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/cluster.c
// Function: clusterUpdateState
void clusterUpdateState(void) {
    int j, new_state;
    int unreachable_masters = 0;
    static mstime_t among_minority_time;
    static mstime_t first_call_time = 0;

    server.cluster->todo_before_sleep &= ~CLUSTER_TODO_UPDATE_STATE;

    /* If this is a master node, wait some time before turning the state
     * into OK, since it is not a good idea to rejoin the cluster as a writable
     * master, after a reboot, without giving the cluster a chance to
     * reconfigure this node. Note that the delay is calculated starting from
     * the first call to this function and not since the server start, in order
     * to don't count the DB loading time. */
    if (first_call_time == 0) first_call_time = mstime();
    if (nodeIsMaster(myself) &&
        mstime() - first_call_time < REDIS_CLUSTER_WRITABLE_DELAY) return;

    /* Start assuming the state is OK. We'll turn it into FAIL if there
     * are the right conditions. */

    // 先假设节点状态为 OK ，后面再检测节点是否真的下线
    new_state = REDIS_CLUSTER_OK;

    /* Check if all the slots are covered. */
    // 检查是否所有槽都已经有某个节点在处理
    for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) {
        if (server.cluster->slots[j] == NULL ||
            server.cluster->slots[j]->flags & (REDIS_NODE_FAIL))
        {
            new_state = REDIS_CLUSTER_FAIL;
            break;
        }
    }

    /* Compute the cluster size, that is the number of master nodes
     * serving at least a single slot.
     *
     * At the same time count the number of unreachable masters with
     * at least one node. */
    // 统计在线并且正在处理至少一个槽的 master 的数量，
    // 以及下线 master 的数量
    {
        dictIterator *di;
        dictEntry *de;

        server.cluster->size = 0;
        di = dictGetSafeIterator(server.cluster->nodes);
        while((de = dictNext(di)) != NULL) {
            clusterNode *node = dictGetVal(de);

            if (nodeIsMaster(node) && node->numslots) {
                server.cluster->size++;
                if (node->flags & (REDIS_NODE_FAIL|REDIS_NODE_PFAIL))
                    unreachable_masters++;
            }
        }
        dictReleaseIterator(di);
    }

    /* If we can't reach at least half the masters, change the cluster state
     * to FAIL, as we are not even able to mark nodes as FAIL in this side
     * of the netsplit because of lack of majority.
     *
     * 如果不能连接到半数以上节点，那么将我们自己的状态设置为 FAIL
     * 因为在少于半数节点的情况下，节点是无法将一个节点判断为 FAIL 的。
     */
    {
        int needed_quorum = (server.cluster->size / 2) + 1;

        if (unreachable_masters >= needed_quorum) {
            new_state = REDIS_CLUSTER_FAIL;
            among_minority_time = mstime();
        }
    }

    /* Log a state change */
    // 记录状态变更
    if (new_state != server.cluster->state) {
        mstime_t rejoin_delay = server.cluster_node_timeout;

        /* If the instance is a master and was partitioned away with the
         * minority, don't let it accept queries for some time after the
         * partition heals, to make sure there is enough time to receive
         * a configuration update. */
        if (rejoin_delay > REDIS_CLUSTER_MAX_REJOIN_DELAY)
            rejoin_delay = REDIS_CLUSTER_MAX_REJOIN_DELAY;
        if (rejoin_delay < REDIS_CLUSTER_MIN_REJOIN_DELAY)
            rejoin_delay = REDIS_CLUSTER_MIN_REJOIN_DELAY;

        if (new_state == REDIS_CLUSTER_OK &&
            nodeIsMaster(myself) &&
            mstime() - among_minority_time < rejoin_delay)
        {
            return;
        }

        /* Change the state and log the event. */
        redisLog(REDIS_WARNING,"Cluster state changed: %s",
            new_state == REDIS_CLUSTER_OK ? "ok" : "fail");

        // 设置新状态
        server.cluster->state = new_state;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movl $0x0, -0xc(%rbp)
leaq 0xa5c52(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movl 0x60078(%rax), %ecx
andl $-0x3, %ecx
movl %ecx, 0x60078(%rax)
cmpq $0x0, 0xba2cc(%rip)     # 0x127f90
jne 0x6dcd2
callq 0x252e0
movq %rax, 0xba2be(%rip)     # 0x127f90
movq 0xba29f(%rip), %rax     # 0x127f78
movl 0x30(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x6dcfd
callq 0x252e0
subq 0xba2a0(%rip), %rax     # 0x127f90
cmpq $0x7d0, %rax            # imm = 0x7D0
jge 0x6dcfd
jmp 0x6df08
movl $0x0, -0x8(%rbp)
movl $0x0, -0x4(%rbp)
cmpl $0x4000, -0x4(%rbp)     # imm = 0x4000
jge 0x6dd6c
leaq 0xa5bdd(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movslq -0x4(%rbp), %rcx
cmpq $0x0, 0x40028(%rax,%rcx,8)
je 0x6dd56
leaq 0xa5bc0(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movslq -0x4(%rbp), %rcx
movq 0x40028(%rax,%rcx,8), %rax
movl 0x30(%rax), %eax
andl $0x8, %eax
cmpl $0x0, %eax
je 0x6dd5f
movl $0x1, -0x8(%rbp)
jmp 0x6dd6c
jmp 0x6dd61
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x6dd0b
leaq 0xa5b85(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movl $0x0, 0x14(%rax)
leaq 0xa5b70(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %rdi
callq 0x24240
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rdi
callq 0x24270
movq %rax, -0x20(%rbp)
cmpq $0x0, %rax
je 0x6de0a
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movl 0x30(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x6de08
movq -0x28(%rbp), %rax
cmpl $0x0, 0x840(%rax)
je 0x6de08
leaq 0xa5b1a(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movl 0x14(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x14(%rax)
movq -0x28(%rbp), %rax
movl 0x30(%rax), %eax
andl $0xc, %eax
cmpl $0x0, %eax
je 0x6de06
movl -0xc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc(%rbp)
jmp 0x6de08
jmp 0x6dd9c
movq -0x18(%rbp), %rdi
callq 0x243d0
leaq 0xa5ade(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movl 0x14(%rax), %eax
movl $0x2, %ecx
cltd
idivl %ecx
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movl -0xc(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jl 0x6de4d
movl $0x1, -0x8(%rbp)
callq 0x252e0
movq %rax, 0xba13b(%rip)     # 0x127f88
movl -0x8(%rbp), %eax
leaq 0xa5aa1(%rip), %rcx     # 0x1138f8
movq 0x7d0(%rcx), %rcx
cmpl 0x10(%rcx), %eax
je 0x6df08
leaq 0xa5a8a(%rip), %rax     # 0x1138f8
movq 0x7c0(%rax), %rax
movq %rax, -0x38(%rbp)
cmpq $0x1388, -0x38(%rbp)    # imm = 0x1388
jle 0x6de8b
movq $0x1388, -0x38(%rbp)    # imm = 0x1388
cmpq $0x1f4, -0x38(%rbp)     # imm = 0x1F4
jge 0x6de9d
movq $0x1f4, -0x38(%rbp)     # imm = 0x1F4
cmpl $0x0, -0x8(%rbp)
jne 0x6dec9
movq 0xba0ce(%rip), %rax     # 0x127f78
movl 0x30(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x6dec9
callq 0x252e0
subq 0xba0c7(%rip), %rax     # 0x127f88
cmpq -0x38(%rbp), %rax
jge 0x6dec9
jmp 0x6df08
movl -0x8(%rbp), %ecx
leaq 0x77de2(%rip), %rdx     # 0xe5cb5
leaq 0x7def1(%rip), %rax     # 0xebdcb
cmpl $0x0, %ecx
cmoveq %rax, %rdx
movl $0x3, %edi
leaq 0x788e4(%rip), %rsi     # 0xe67d1
movb $0x0, %al
callq 0x24fb0
movl -0x8(%rbp), %ecx
leaq 0xa59fa(%rip), %rax     # 0x1138f8
movq 0x7d0(%rax), %rax
movl %ecx, 0x10(%rax)
addq $0x40, %rsp
popq %rbp
retq
nop