// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/sentinel.c
// Function: sentinelFailoverDetectEnd
void sentinelFailoverDetectEnd(sentinelRedisInstance *master) {
    int not_reconfigured = 0, timeout = 0;
    dictIterator *di;
    dictEntry *de;

    // 上次 failover 状态更新以来，经过的时间
    mstime_t elapsed = mstime() - master->failover_state_change_time;

    /* We can't consider failover finished if the promoted slave is
     * not reachable. */
    // 如果新主服务器已经下线，那么故障转移操作不成功
    if (master->promoted_slave == NULL ||
        master->promoted_slave->flags & SRI_S_DOWN) return;

    /* The failover terminates once all the reachable slaves are properly
     * configured. */
    // 计算未完成同步的从服务器的数量
    di = dictGetIterator(master->slaves);
    while((de = dictNext(di)) != NULL) {
        sentinelRedisInstance *slave = dictGetVal(de);

        // 新主服务器和已完成同步的从服务器不计算在内
        if (slave->flags & (SRI_PROMOTED|SRI_RECONF_DONE)) continue;

        // 已下线的从服务器不计算在内
        if (slave->flags & SRI_S_DOWN) continue;

        // 增一
        not_reconfigured++;
    }
    dictReleaseIterator(di);

    /* Force end of failover on timeout. */
    // 故障操作因为超时而结束
    if (elapsed > master->failover_timeout) {
        // 忽略未完成的从服务器
        not_reconfigured = 0;
        // 打开超时标志
        timeout = 1;
        // 发送超时事件
        sentinelEvent(REDIS_WARNING,"+failover-end-for-timeout",master,"%@");
    }

    // 所有从服务器都已完成同步，故障转移结束
    if (not_reconfigured == 0) {
        sentinelEvent(REDIS_WARNING,"+failover-end",master,"%@");
        // 更新故障转移状态
        // 这一状态将告知 Sentinel ，所有从服务器都已经同步到新主服务器
        master->failover_state = SENTINEL_FAILOVER_STATE_UPDATE_CONFIG;
        // 更新状态改变的时间
        master->failover_state_change_time = mstime();
    }

    /* If I'm the leader it is a good idea to send a best effort SLAVEOF
     * command to all the slaves still not reconfigured to replicate with
     * the new master. */
    if (timeout) {
        dictIterator *di;
        dictEntry *de;

        // 遍历所有从服务器
        di = dictGetIterator(master->slaves);
        while((de = dictNext(di)) != NULL) {
            sentinelRedisInstance *slave = dictGetVal(de);
            int retval;

            // 跳过已发送 SLAVEOF 命令，以及已经完成同步的所有从服务器
            if (slave->flags &
                (SRI_RECONF_DONE|SRI_RECONF_SENT|SRI_DISCONNECTED)) continue;

            // 发送命令
            retval = sentinelSendSlaveOf(slave,
                    master->promoted_slave->addr->ip,
                    master->promoted_slave->addr->port);
            if (retval == REDIS_OK) {
                sentinelEvent(REDIS_NOTICE,"+slave-reconf-sent-be",slave,"%@");
                // 打开从服务器的 SLAVEOF 命令已发送标记
                slave->flags |= SRI_RECONF_SENT;
            }
        }
        dictReleaseIterator(di);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movq %rdi, -0x8(%rbp)
movl $0x0, -0xc(%rbp)
movl $0x0, -0x10(%rbp)
callq 0x252e0
movq -0x8(%rbp), %rcx
subq 0x138(%rcx), %rax
movq %rax, -0x28(%rbp)
movq -0x8(%rbp), %rax
cmpq $0x0, 0x158(%rax)
je 0x80831
movq -0x8(%rbp), %rax
movq 0x158(%rax), %rax
movl (%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x80836
jmp 0x809e4
movq -0x8(%rbp), %rax
movq 0xc8(%rax), %rdi
callq 0x241d0
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rdi
callq 0x24270
movq %rax, -0x20(%rbp)
cmpq $0x0, %rax
je 0x80896
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movl (%rax), %eax
andl $0x900, %eax            # imm = 0x900
cmpl $0x0, %eax
je 0x8087b
jmp 0x8084a
movq -0x30(%rbp), %rax
movl (%rax), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x8088b
jmp 0x8084a
movl -0xc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc(%rbp)
jmp 0x8084a
movq -0x18(%rbp), %rdi
callq 0x243d0
movq -0x28(%rbp), %rax
movq -0x8(%rbp), %rcx
cmpq 0x148(%rcx), %rax
jle 0x808dc
movl $0x0, -0xc(%rbp)
movl $0x1, -0x10(%rbp)
movq -0x8(%rbp), %rdx
movl $0x3, %edi
leaq 0x695cf(%rip), %rsi     # 0xe9e9d
leaq 0x6875d(%rip), %rcx     # 0xe9032
movb $0x0, %al
callq 0x79b10
cmpl $0x0, -0xc(%rbp)
jne 0x80921
movq -0x8(%rbp), %rdx
movl $0x3, %edi
leaq 0x695c5(%rip), %rsi     # 0xe9eb7
leaq 0x68739(%rip), %rcx     # 0xe9032
movb $0x0, %al
callq 0x79b10
movq -0x8(%rbp), %rax
movl $0x6, 0x130(%rax)
callq 0x252e0
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x138(%rax)
cmpl $0x0, -0x10(%rbp)
je 0x809e4
movq -0x8(%rbp), %rax
movq 0xc8(%rax), %rdi
callq 0x241d0
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rdi
callq 0x24270
movq %rax, -0x40(%rbp)
cmpq $0x0, %rax
je 0x809db
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movl (%rax), %eax
andl $0xa08, %eax            # imm = 0xA08
cmpl $0x0, %eax
je 0x80974
jmp 0x8093f
movq -0x48(%rbp), %rdi
movq -0x8(%rbp), %rax
movq 0x158(%rax), %rax
movq 0x20(%rax), %rax
movq (%rax), %rsi
movq -0x8(%rbp), %rax
movq 0x158(%rax), %rax
movq 0x20(%rax), %rax
movl 0x8(%rax), %edx
callq 0x7da60
movl %eax, -0x4c(%rbp)
cmpl $0x0, -0x4c(%rbp)
jne 0x809d6
movq -0x48(%rbp), %rdx
movl $0x2, %edi
leaq 0x6950b(%rip), %rsi     # 0xe9ec5
leaq 0x68671(%rip), %rcx     # 0xe9032
movb $0x0, %al
callq 0x79b10
movq -0x48(%rbp), %rax
movl (%rax), %ecx
orl $0x200, %ecx            # imm = 0x200
movl %ecx, (%rax)
jmp 0x8093f
movq -0x38(%rbp), %rdi
callq 0x243d0
addq $0x50, %rsp
popq %rbp
retq
nopw (%rax,%rax)