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

    /* ignore SYNC if already slave or in monitor mode */
    // 已经是 SLAVE ，或者处于 MONITOR 模式，返回
    if (c->flags & REDIS_SLAVE) return;

    /* Refuse SYNC requests if we are a slave but the link with our master
     * is not ok... */
    // 如果这是一个从服务器，但与主服务器的连接仍未就绪，那么拒绝 SYNC
    if (server.masterhost && server.repl_state != REDIS_REPL_CONNECTED) {
        addReplyError(c,"Can't SYNC while not connected with my master");
        return;
    }

    /* SYNC can't be issued when the server has pending data to send to
     * the client about already issued commands. We need a fresh reply
     * buffer registering the differences between the BGSAVE and the current
     * dataset, so that we can copy to other slaves if needed. */
    // 在客户端仍有输出数据等待输出，不能 SYNC
    if (listLength(c->reply) != 0 || c->bufpos != 0) {
        addReplyError(c,"SYNC and PSYNC are invalid with pending output");
        return;
    }

    redisLog(REDIS_NOTICE,"Slave asks for synchronization");

    /* Try a partial resynchronization if this is a PSYNC command.
     * 如果这是一个 PSYNC 命令，那么尝试 partial resynchronization 。
     *
     * If it fails, we continue with usual full resynchronization, however
     * when this happens masterTryPartialResynchronization() already
     * replied with:
     *
     * 如果失败，那么使用 full resynchronization ，
     * 在这种情况下， masterTryPartialResynchronization() 返回以下内容：
     *
     * +FULLRESYNC <runid> <offset>
     *
     * So the slave knows the new runid and offset to try a PSYNC later
     * if the connection with the master is lost. 
     *
     * 这样的话，之后如果主服务器断开，那么从服务器就可以尝试 PSYNC 了。
     */
    if (!strcasecmp(c->argv[0]->ptr,"psync")) {
        // 尝试进行 PSYNC
        if (masterTryPartialResynchronization(c) == REDIS_OK) {
            // 可执行 PSYNC
            server.stat_sync_partial_ok++;
            return; /* No full resync needed, return. */
        } else {
            // 不可执行 PSYNC
            char *master_runid = c->argv[1]->ptr;
            
            /* Increment stats for failed PSYNCs, but only if the
             * runid is not "?", as this is used by slaves to force a full
             * resync on purpose when they are not albe to partially
             * resync. */
            if (master_runid[0] != '?') server.stat_sync_partial_err++;
        }
    } else {
        /* If a slave uses SYNC, we are dealing with an old implementation
         * of the replication protocol (like redis-cli --slave). Flag the client
         * so that we don't expect to receive REPLCONF ACK feedbacks. */
        // 旧版实现，设置标识，避免接收 REPLCONF ACK 
        c->flags |= REDIS_PRE_PSYNC;
    }

    // 以下是完整重同步的情况。。。

    /* Full resynchronization. */
    // 执行 full resynchronization ，增加计数
    server.stat_sync_full++;

    /* Here we need to check if there is a background saving operation
     * in progress, or if it is required to start one */
    // 检查是否有 BGSAVE 在执行
    if (server.rdb_child_pid != -1) {
        /* Ok a background save is in progress. Let's check if it is a good
         * one for replication, i.e. if there is another slave that is
         * registering differences since the server forked to save */
        redisClient *slave;
        listNode *ln;
        listIter li;

        // 如果有至少一个 slave 在等待这个 BGSAVE 完成
        // 那么说明正在进行的 BGSAVE 所产生的 RDB 也可以为其他 slave 所用
        listRewind(server.slaves,&li);
        while((ln = listNext(&li))) {
            slave = ln->value;
            if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
        }

        if (ln) {
            /* Perfect, the server is already registering differences for
             * another slave. Set the right state, and copy the buffer. */
            // 幸运的情况，可以使用目前 BGSAVE 所生成的 RDB
            copyClientOutputBuffer(c,slave);
            c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
            redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
        } else {
            /* No way, we need to wait for the next BGSAVE in order to
             * register differences */
            // 不好运的情况，必须等待下个 BGSAVE
            c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
            redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
        }
    } else {
        /* Ok we don't have a BGSAVE in progress, let's start one */
        // 没有 BGSAVE 在进行，开始一个新的 BGSAVE
        redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
        if (rdbSaveBackground(server.rdb_filename) != REDIS_OK) {
            redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
            addReplyError(c,"Unable to perform background save");
            return;
        }
        // 设置状态
        c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
        /* Flush the script cache for the new slave. */
        // 因为新 slave 进入，刷新复制脚本缓存
        replicationScriptCacheFlush();
    }

    if (server.repl_disable_tcp_nodelay)
        anetDisableTcpNoDelay(NULL, c->fd); /* Non critical if it fails. */

    c->repldbfd = -1;

    c->flags |= REDIS_SLAVE;

    server.slaveseldb = -1; /* Force to re-emit the SELECT command. */

    // 添加到 slave 列表中
    listAddNodeTail(server.slaves,c);
    // 如果是第一个 slave ，那么初始化 backlog
    if (listLength(server.slaves) == 1 && server.repl_backlog == NULL)
        createReplicationBacklog();
    return;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x3fd23
jmp 0x4001a
leaq 0xd3bce(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x650(%rax)
je 0x3fd59
leaq 0xd3bbd(%rip), %rax     # 0x1138f8
cmpl $0x5, 0x674(%rax)
je 0x3fd59
movq -0x8(%rbp), %rdi
leaq 0xa1e93(%rip), %rsi     # 0xe1be2
callq 0x35d40
jmp 0x4001a
movq -0x8(%rbp), %rax
movq 0x60(%rax), %rax
cmpq $0x0, 0x28(%rax)
jne 0x3fd75
movq -0x8(%rbp), %rax
cmpl $0x0, 0x170(%rax)
je 0x3fd8a
movq -0x8(%rbp), %rdi
leaq 0xa1e90(%rip), %rsi     # 0xe1c10
callq 0x35d40
jmp 0x4001a
movl $0x2, %edi
leaq 0xa1ea9(%rip), %rsi     # 0xe1c3f
movb $0x0, %al
callq 0x24fb0
movq -0x8(%rbp), %rax
movq 0x38(%rax), %rax
movq (%rax), %rax
movq 0x8(%rax), %rdi
leaq 0x9e818(%rip), %rsi     # 0xde5cb
callq 0x1f2f0
cmpl $0x0, %eax
jne 0x3fe34
movq -0x8(%rbp), %rdi
callq 0x3f960
cmpl $0x0, %eax
jne 0x3fdf0
leaq 0xd3b26(%rip), %rax     # 0x1138f8
movq 0x398(%rax), %rcx
addq $0x1, %rcx
leaq 0xd3b14(%rip), %rax     # 0x1138f8
movq %rcx, 0x398(%rax)
jmp 0x4001a
movq -0x8(%rbp), %rax
movq 0x38(%rax), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x3f, %eax
je 0x3fe30
leaq 0xd3ae1(%rip), %rax     # 0x1138f8
movq 0x3a0(%rax), %rcx
addq $0x1, %rcx
leaq 0xd3acf(%rip), %rax     # 0x1138f8
movq %rcx, 0x3a0(%rax)
jmp 0x3fe32
jmp 0x3fe4a
movq -0x8(%rbp), %rax
movl 0x90(%rax), %ecx
orl $0x10000, %ecx          # imm = 0x10000
movl %ecx, 0x90(%rax)
leaq 0xd3aa7(%rip), %rax     # 0x1138f8
movq 0x390(%rax), %rcx
addq $0x1, %rcx
leaq 0xd3a95(%rip), %rax     # 0x1138f8
movq %rcx, 0x390(%rax)
leaq 0xd3a87(%rip), %rax     # 0x1138f8
cmpl $-0x1, 0x570(%rax)
je 0x3ff1f
leaq 0xd3a73(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rdi
leaq -0x30(%rbp), %rsi
callq 0x202b0
leaq -0x30(%rbp), %rdi
callq 0x20310
movq %rax, -0x20(%rbp)
cmpq $0x0, %rax
je 0x3fec5
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x7, 0x98(%rax)
jne 0x3fec3
jmp 0x3fec5
jmp 0x3fe95
cmpq $0x0, -0x20(%rbp)
je 0x3fefc
movq -0x8(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x36700
movq -0x8(%rbp), %rax
movl $0x7, 0x98(%rax)
movl $0x2, %edi
leaq 0xa1d6b(%rip), %rsi     # 0xe1c5e
movb $0x0, %al
callq 0x24fb0
jmp 0x3ff1d
movq -0x8(%rbp), %rax
movl $0x6, 0x98(%rax)
movl $0x2, %edi
leaq 0xa1d6b(%rip), %rsi     # 0xe1c81
movb $0x0, %al
callq 0x24fb0
jmp 0x3ff85
movl $0x2, %edi
leaq 0xa1d77(%rip), %rsi     # 0xe1ca2
movb $0x0, %al
callq 0x24fb0
leaq 0xd39bf(%rip), %rax     # 0x1138f8
movq 0x588(%rax), %rdi
callq 0x44ef0
cmpl $0x0, %eax
je 0x3ff72
movl $0x2, %edi
leaq 0xa1d65(%rip), %rsi     # 0xe1cbb
movb $0x0, %al
callq 0x24fb0
movq -0x8(%rbp), %rdi
leaq 0xa1d74(%rip), %rsi     # 0xe1cdc
callq 0x35d40
jmp 0x4001a
movq -0x8(%rbp), %rax
movl $0x7, 0x98(%rax)
callq 0x40020
leaq 0xd396c(%rip), %rax     # 0x1138f8
cmpl $0x0, 0x6b8(%rax)
je 0x3ffa4
movq -0x8(%rbp), %rax
movl (%rax), %esi
xorl %eax, %eax
movl %eax, %edi
callq 0x21c50
movq -0x8(%rbp), %rax
movl $0xffffffff, 0x9c(%rax) # imm = 0xFFFFFFFF
movq -0x8(%rbp), %rax
movl 0x90(%rax), %ecx
orl $0x1, %ecx
movl %ecx, 0x90(%rax)
leaq 0xd392c(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x5ec(%rax) # imm = 0xFFFFFFFF
leaq 0xd391b(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rdi
movq -0x8(%rbp), %rsi
callq 0x1ff90
leaq 0xd3904(%rip), %rax     # 0x1138f8
movq 0x1c0(%rax), %rax
cmpq $0x1, 0x28(%rax)
jne 0x40018
leaq 0xd38ef(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x600(%rax)
jne 0x40018
callq 0x3ed40
jmp 0x4001a
addq $0x30, %rsp
popq %rbp
retq