// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/replication.c
// Function: replicationCron
void replicationCron(void) {

    /* Non blocking connection timeout? */
    // 尝试连接到主服务器，但超时
    if (server.masterhost &&
        (server.repl_state == REDIS_REPL_CONNECTING ||
         server.repl_state == REDIS_REPL_RECEIVE_PONG) &&
        (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout)
    {
        redisLog(REDIS_WARNING,"Timeout connecting to the MASTER...");
        // 取消连接
        undoConnectWithMaster();
    }

    /* Bulk transfer I/O timeout? */
    // RDB 文件的传送已超时？
    if (server.masterhost && server.repl_state == REDIS_REPL_TRANSFER &&
        (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout)
    {
        redisLog(REDIS_WARNING,"Timeout receiving bulk data from MASTER... If the problem persists try to set the 'repl-timeout' parameter in redis.conf to a larger value.");
        // 停止传送，并删除临时文件
        replicationAbortSyncTransfer();
    }

    /* Timed out master when we are an already connected slave? */
    // 从服务器曾经连接上主服务器，但现在超时
    if (server.masterhost && server.repl_state == REDIS_REPL_CONNECTED &&
        (time(NULL)-server.master->lastinteraction) > server.repl_timeout)
    {
        redisLog(REDIS_WARNING,"MASTER timeout: no data nor PING received...");
        // 释放主服务器
        freeClient(server.master);
    }

    /* Check if we should connect to a MASTER */
    // 尝试连接主服务器
    if (server.repl_state == REDIS_REPL_CONNECT) {
        redisLog(REDIS_NOTICE,"Connecting to MASTER %s:%d",
            server.masterhost, server.masterport);
        if (connectWithMaster() == REDIS_OK) {
            redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync started");
        }
    }

    /* Send ACK to master from time to time.
     * Note that we do not send periodic acks to masters that don't
     * support PSYNC and replication offsets. */
    // 定期向主服务器发送 ACK 命令
    // 不过如果主服务器带有 REDIS_PRE_PSYNC 的话就不发送
    // 因为带有该标识的版本为 < 2.8 的版本，这些版本不支持 ACK 命令
    if (server.masterhost && server.master &&
        !(server.master->flags & REDIS_PRE_PSYNC))
        replicationSendAck();
    
    /* If we have attached slaves, PING them from time to time.
     *
     * 如果服务器有从服务器，定时向它们发送 PING 。
     *
     * So slaves can implement an explicit timeout to masters, and will
     * be able to detect a link disconnection even if the TCP connection
     * will not actually go down. 
     *
     * 这样从服务器就可以实现显式的 master 超时判断机制，
     * 即使 TCP 连接未断开也是如此。
     */
    if (!(server.cronloops % (server.repl_ping_slave_period * server.hz))) {
        listIter li;
        listNode *ln;
        robj *ping_argv[1];

        /* First, send PING */
        // 向所有已连接 slave （状态为 ONLINE）发送 PING
        ping_argv[0] = createStringObject("PING",4);
        replicationFeedSlaves(server.slaves, server.slaveseldb, ping_argv, 1);
        decrRefCount(ping_argv[0]);

        /* Second, send a newline to all the slaves in pre-synchronization
         * stage, that is, slaves waiting for the master to create the RDB file.
         *
         * 向那些正在等待 RDB 文件的从服务器（状态为 BGSAVE_START 或 BGSAVE_END）
         * 发送 "\n"
         *
         * The newline will be ignored by the slave but will refresh the
         * last-io timer preventing a timeout. 
         *
         * 这个 "\n" 会被从服务器忽略，
         * 它的作用就是用来防止主服务器因为长期不发送信息而被从服务器误判为超时
         */
        listRewind(server.slaves,&li);
        while((ln = listNext(&li))) {
            redisClient *slave = ln->value;

            if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START ||
                slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
                if (write(slave->fd, "\n", 1) == -1) {
                    /* Don't worry, it's just a ping. */
                }
            }
        }
    }

    /* Disconnect timedout slaves. */
    // 断开超时从服务器
    if (listLength(server.slaves)) {
        listIter li;
        listNode *ln;

        // 遍历所有从服务器
        listRewind(server.slaves,&li);
        while((ln = listNext(&li))) {
            redisClient *slave = ln->value;

            // 略过未 ONLINE 的从服务器
            if (slave->replstate != REDIS_REPL_ONLINE) continue;

            // 不检查旧版的从服务器
            if (slave->flags & REDIS_PRE_PSYNC) continue;

            // 释放超时从服务器
            if ((server.unixtime - slave->repl_ack_time) > server.repl_timeout)
            {
                char ip[REDIS_IP_STR_LEN];
                int port;

                if (anetPeerToString(slave->fd,ip,sizeof(ip),&port) != -1) {
                    redisLog(REDIS_WARNING,
                        "Disconnecting timedout slave: %s:%d",
                        ip, slave->slave_listening_port);
                }
                
                // 释放
                freeClient(slave);
            }
        }
    }

    /* If we have no attached slaves and there is a replication backlog
     * using memory, free it after some (configured) time. */
    // 在没有任何从服务器的 N 秒之后，释放 backlog
    if (listLength(server.slaves) == 0 && server.repl_backlog_time_limit &&
        server.repl_backlog)
    {
        time_t idle = server.unixtime - server.repl_no_slaves_since;

        if (idle > server.repl_backlog_time_limit) {
            // 释放
            freeReplicationBacklog();
            redisLog(REDIS_NOTICE,
                "Replication backlog freed after %d seconds "
                "without connected slaves.",
                (int) server.repl_backlog_time_limit);
        }
    }

    /* If AOF is disabled and we no longer have attached slaves, we can
     * free our Replication Script Cache as there is no need to propagate
     * EVALSHA at all. */
    // 在没有任何从服务器，AOF 关闭的情况下，清空 script 缓存
    // 因为已经没有传播 EVALSHA 的必要了
    if (listLength(server.slaves) == 0 &&
        server.aof_state == REDIS_AOF_OFF &&
        listLength(server.repl_scriptcache_fifo) != 0)
    {
        replicationScriptCacheFlush();
    }

    /* Refresh the number of slaves with lag <= min-slaves-max-lag. */
    // 更新符合给定延迟值的从服务器的数量
    refreshGoodSlavesCount();
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
leaq 0xd0ef6(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x650(%rax)
je 0x42a6e
leaq 0xd0ee5(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x674(%rax)
je 0x42a2c
leaq 0xd0ed5(%rip), %rax     # 0x1138f8
cmpl $0x3, 0x674(%rax)
jne 0x42a6e
xorl %eax, %eax
movl %eax, %edi
callq 0x1fc70
leaq 0xd0ebc(%rip), %rcx     # 0x1138f8
subq 0x6a0(%rcx), %rax
leaq 0xd0eae(%rip), %rcx     # 0x1138f8
movslq 0x65c(%rcx), %rcx
cmpq %rcx, %rax
jle 0x42a6e
movl $0x3, %edi
leaq 0x9fed2(%rip), %rsi     # 0xe2934
movb $0x0, %al
callq 0x24fb0
callq 0x41ee0
leaq 0xd0e83(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x650(%rax)
je 0x42ad1
leaq 0xd0e72(%rip), %rax     # 0x1138f8
cmpl $0x4, 0x674(%rax)
jne 0x42ad1
xorl %eax, %eax
movl %eax, %edi
callq 0x1fc70
leaq 0xd0e59(%rip), %rcx     # 0x1138f8
subq 0x6a0(%rcx), %rax
leaq 0xd0e4b(%rip), %rcx     # 0x1138f8
movslq 0x65c(%rcx), %rcx
cmpq %rcx, %rax
jle 0x42ad1
movl $0x3, %edi
leaq 0x9fe93(%rip), %rsi     # 0xe2958
movb $0x0, %al
callq 0x24fb0
callq 0x408c0
leaq 0xd0e20(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x650(%rax)
je 0x42b49
leaq 0xd0e0f(%rip), %rax     # 0x1138f8
cmpl $0x5, 0x674(%rax)
jne 0x42b49
xorl %eax, %eax
movl %eax, %edi
callq 0x1fc70
leaq 0xd0df6(%rip), %rcx     # 0x1138f8
movq 0x660(%rcx), %rcx
subq 0x80(%rcx), %rax
leaq 0xd0de1(%rip), %rcx     # 0x1138f8
movslq 0x65c(%rcx), %rcx
cmpq %rcx, %rax
jle 0x42b49
movl $0x3, %edi
leaq 0x9feb5(%rip), %rsi     # 0xe29e4
movb $0x0, %al
callq 0x24fb0
leaq 0xd0dbb(%rip), %rax     # 0x1138f8
movq 0x660(%rax), %rdi
callq 0x36a80
leaq 0xd0da8(%rip), %rax     # 0x1138f8
cmpl $0x1, 0x674(%rax)
jne 0x42ba6
leaq 0xd0d98(%rip), %rax     # 0x1138f8
movq 0x650(%rax), %rdx
leaq 0xd0d8a(%rip), %rax     # 0x1138f8
movl 0x658(%rax), %ecx
movl $0x2, %edi
leaq 0x9fe91(%rip), %rsi     # 0xe2a11
movb $0x0, %al
callq 0x24fb0
callq 0x41de0
cmpl $0x0, %eax
jne 0x42ba4
movl $0x2, %edi
leaq 0x9fe8f(%rip), %rsi     # 0xe2a2c
movb $0x0, %al
callq 0x24fb0
jmp 0x42ba6
leaq 0xd0d4b(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x650(%rax)
je 0x42beb
leaq 0xd0d3a(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x660(%rax)
je 0x42beb
leaq 0xd0d29(%rip), %rax     # 0x1138f8
movq 0x660(%rax), %rax
movl 0x90(%rax), %eax
andl $0x10000, %eax          # imm = 0x10000
cmpl $0x0, %eax
jne 0x42beb
callq 0x40280
leaq 0xd0d06(%rip), %rax     # 0x1138f8
movl 0x54(%rax), %eax
leaq 0xd0cfc(%rip), %rcx     # 0x1138f8
movl 0x5f8(%rcx), %ecx
leaq 0xd0cef(%rip), %rdx     # 0x1138f8
imull 0x8(%rdx), %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x42cd5
leaq 0x9fe2a(%rip), %rdi     # 0xe2a4a
movl $0x4, %esi
callq 0x3a2e0
movq %rax, -0x20(%rbp)
leaq 0xd0cc3(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rdi
leaq 0xd0cb5(%rip), %rax     # 0x1138f8
movl 0x5ec(%rax), %esi
leaq -0x20(%rbp), %rdx
movl $0x1, %ecx
callq 0x3f180
movq -0x20(%rbp), %rdi
callq 0x3aaa0
leaq 0xd0c91(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rdi
leaq -0x10(%rbp), %rsi
callq 0x202b0
leaq -0x10(%rbp), %rdi
callq 0x20310
movq %rax, -0x18(%rbp)
cmpq $0x0, %rax
je 0x42cd3
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
cmpl $0x6, 0x98(%rax)
je 0x42cb0
movq -0x28(%rbp), %rax
cmpl $0x7, 0x98(%rax)
jne 0x42cd1
movq -0x28(%rbp), %rax
movl (%rax), %edi
leaq 0x9dafc(%rip), %rsi     # 0xe07b9
movl $0x1, %edx
callq 0x1fb50
cmpq $-0x1, %rax
jne 0x42ccf
jmp 0x42ccf
jmp 0x42cd1
jmp 0x42c77
jmp 0x42cd5
leaq 0xd0c1c(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rax
cmpq $0x0, 0x28(%rax)
je 0x42dca
leaq 0xd0c03(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rdi
leaq -0x38(%rbp), %rsi
callq 0x202b0
leaq -0x38(%rbp), %rdi
callq 0x20310
movq %rax, -0x40(%rbp)
cmpq $0x0, %rax
je 0x42dc8
movq -0x40(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
cmpl $0x9, 0x98(%rax)
je 0x42d37
jmp 0x42d05
movq -0x48(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x10000, %eax          # imm = 0x10000
cmpl $0x0, %eax
je 0x42d4d
jmp 0x42d05
leaq 0xd0ba4(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
movq -0x48(%rbp), %rcx
subq 0xc8(%rcx), %rax
leaq 0xd0b8b(%rip), %rcx     # 0x1138f8
movslq 0x65c(%rcx), %rcx
cmpq %rcx, %rax
jle 0x42dc3
movq -0x48(%rbp), %rax
movl (%rax), %edi
leaq -0x80(%rbp), %rsi
movl $0x2e, %edx
leaq -0x84(%rbp), %rcx
callq 0x22be0
cmpl $-0x1, %eax
je 0x42dba
leaq -0x80(%rbp), %rdx
movq -0x48(%rbp), %rax
movl 0xfc(%rax), %ecx
movl $0x3, %edi
leaq 0x9fc9c(%rip), %rsi     # 0xe2a4f
movb $0x0, %al
callq 0x24fb0
movq -0x48(%rbp), %rdi
callq 0x36a80
jmp 0x42d05
jmp 0x42dca
leaq 0xd0b27(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rax
cmpq $0x0, 0x28(%rax)
jne 0x42e69
leaq 0xd0b0e(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x628(%rax)
je 0x42e69
leaq 0xd0afd(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x600(%rax)
je 0x42e69
leaq 0xd0aec(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
leaq 0xd0ade(%rip), %rcx     # 0x1138f8
subq 0x630(%rcx), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
leaq 0xd0ac2(%rip), %rcx     # 0x1138f8
cmpq 0x628(%rcx), %rax
jle 0x42e67
callq 0x3eef0
leaq 0xd0aad(%rip), %rax     # 0x1138f8
movq 0x628(%rax), %rax
movl %eax, %edx
movl $0x2, %edi
leaq 0x9fc13(%rip), %rsi     # 0xe2a73
movb $0x0, %al
callq 0x24fb0
jmp 0x42e69
leaq 0xd0a88(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rax
cmpq $0x0, 0x28(%rax)
jne 0x42ea8
leaq 0xd0a73(%rip), %rax     # 0x1138f8
cmpl $0x0, 0x4d0(%rax)
jne 0x42ea8
leaq 0xd0a63(%rip), %rax     # 0x1138f8
movq 0x700(%rax), %rax
cmpq $0x0, 0x28(%rax)
je 0x42ea8
callq 0x40020
callq 0x3fc30
addq $0x90, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)