// File: /workspace/github_c_makefile_star2_O1/nilyang[P]redis-tdd-annotation/src/sentinel.c
// Function: sentinelSelectSlave
sentinelRedisInstance *sentinelSelectSlave(sentinelRedisInstance *master) {

    sentinelRedisInstance **instance =
        zmalloc(sizeof(instance[0])*dictSize(master->slaves));
    sentinelRedisInstance *selected = NULL;
    int instances = 0;
    dictIterator *di;
    dictEntry *de;
    mstime_t max_master_down_time = 0;

    // 计算可以接收的，从服务器与主服务器之间的最大下线时间
    // 这个值可以保证被选中的从服务器的数据库不会太旧
    if (master->flags & SRI_S_DOWN)
        max_master_down_time += mstime() - master->s_down_since_time;
    max_master_down_time += master->down_after_period * 10;

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

        // 从服务器实例
        sentinelRedisInstance *slave = dictGetVal(de);
        mstime_t info_validity_time;

        // 忽略所有 SDOWN 、ODOWN 或者已断线的从服务器
        if (slave->flags & (SRI_S_DOWN|SRI_O_DOWN|SRI_DISCONNECTED)) continue;
        if (mstime() - slave->last_avail_time > SENTINEL_PING_PERIOD*5) continue;
        if (slave->slave_priority == 0) continue;

        /* If the master is in SDOWN state we get INFO for slaves every second.
         * Otherwise we get it with the usual period so we need to account for
         * a larger delay. */
        // 如果主服务器处于 SDOWN 状态，那么 Sentinel 以每秒一次的频率向从服务器发送 INFO 命令
        // 否则以平常频率向从服务器发送 INFO 命令
        // 这里要检查 INFO 命令的返回值是否合法，检查的时间会乘以一个倍数，以计算延迟
        if (master->flags & SRI_S_DOWN)
            info_validity_time = SENTINEL_PING_PERIOD*5;
        else
            info_validity_time = SENTINEL_INFO_PERIOD*3;

        // INFO 回复已过期，不考虑
        if (mstime() - slave->info_refresh > info_validity_time) continue;

        // 从服务器下线的时间过长，不考虑
        if (slave->master_link_down_time > max_master_down_time) continue;

        // 将被选中的 slave 保存到数组中
        instance[instances++] = slave;
    }
    dictReleaseIterator(di);

    if (instances) {

        // 对被选中的从服务器进行排序
        qsort(instance,instances,sizeof(sentinelRedisInstance*),
            compareSlavesForPromotion);
        
        // 分值最低的从服务器为被选中服务器
        selected = instance[0];
    }
    zfree(instance);

    // 返回被选中的从服务区
    return selected;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rdi, %r14
movq 0xc8(%rdi), %rax
movq 0x48(%rax), %rdi
addq 0x28(%rax), %rdi
shlq $0x3, %rdi
callq 0x29709
movq %rax, %rbx
xorl %r13d, %r13d
testb $0x10, (%r14)
jne 0x5f09c
xorl %r12d, %r12d
jmp 0x5f0ab
callq 0x232a3
movq %rax, %r12
subq 0x88(%r14), %r12
movq 0x98(%r14), %rbp
movq 0xc8(%r14), %rdi
callq 0x228b5
movq %rax, %r15
movq %rax, %rdi
callq 0x22913
testq %rax, %rax
je 0x5f154
leaq (,%rbp,4), %rcx
addq %rbp, %rcx
leaq (%r12,%rcx,2), %rcx
movq %rcx, (%rsp)
xorl %r13d, %r13d
movq 0x8(%rax), %rbp
testb $0x38, (%rbp)
jne 0x5f147
callq 0x232a3
subq 0x58(%rbp), %rax
cmpq $0x1388, %rax           # imm = 0x1388
jg 0x5f147
cmpl $0x0, 0xe8(%rbp)
je 0x5f147
testb $0x10, (%r14)
movl $0x1388, %r12d          # imm = 0x1388
movl $0x7530, %eax           # imm = 0x7530
cmoveq %rax, %r12
callq 0x232a3
subq 0xa0(%rbp), %rax
cmpq %r12, %rax
jg 0x5f147
movq (%rsp), %rax
cmpq %rax, 0xe0(%rbp)
jg 0x5f147
movslq %r13d, %rax
incl %r13d
movq %rbp, (%rbx,%rax,8)
movq %r15, %rdi
callq 0x22913
testq %rax, %rax
jne 0x5f0e8
movq %r15, %rdi
callq 0x229b9
testl %r13d, %r13d
je 0x5f17d
movslq %r13d, %rsi
leaq 0xbb4(%rip), %rcx       # 0x5fd1f
movl $0x8, %edx
movq %rbx, %rdi
callq 0x1f820
movq (%rbx), %r14
jmp 0x5f180
xorl %r14d, %r14d
movq %rbx, %rdi
callq 0x2984b
movq %r14, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq