// File: /workspace/github_c_makefile_star2_O1/nilyang[P]redis-tdd-annotation/src/replication.c
// Function: readSyncBulkPayload
void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
    char buf[4096];
    ssize_t nread, readlen;
    off_t left;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(privdata);
    REDIS_NOTUSED(mask);

    /* If repl_transfer_size == -1 we still have to read the bulk length
     * from the master reply. */
    // 读取 RDB 文件的大小
    if (server.repl_transfer_size == -1) {

        // 调用读函数
        if (syncReadLine(fd,buf,1024,server.repl_syncio_timeout*1000) == -1) {
            redisLog(REDIS_WARNING,
                "I/O error reading bulk count from MASTER: %s",
                strerror(errno));
            goto error;
        }

        // 出错？
        if (buf[0] == '-') {
            redisLog(REDIS_WARNING,
                "MASTER aborted replication with an error: %s",
                buf+1);
            goto error;
        } else if (buf[0] == '\0') {
            /* At this stage just a newline works as a PING in order to take
             * the connection live. So we refresh our last interaction
             * timestamp. */
            // 只接到了一个作用和 PING 一样的 '\0'
            // 更新最后互动时间
            server.repl_transfer_lastio = server.unixtime;
            return;
        } else if (buf[0] != '$') {
            // 读入的内容出错，和协议格式不符
            redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$' (we received '%s'), are you sure the host and port are right?", buf);
            goto error;
        }

        // 分析 RDB 文件大小
        server.repl_transfer_size = strtol(buf+1,NULL,10);

        redisLog(REDIS_NOTICE,
            "MASTER <-> SLAVE sync: receiving %lld bytes from master",
            (long long) server.repl_transfer_size);
        return;
    }

    /* Read bulk data */
    // 读数据

    // 还有多少字节要读？
    left = server.repl_transfer_size - server.repl_transfer_read;
    readlen = (left < (signed)sizeof(buf)) ? left : (signed)sizeof(buf);
    // 读取
    nread = read(fd,buf,readlen);
    if (nread <= 0) {
        redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
            (nread == -1) ? strerror(errno) : "connection lost");
        replicationAbortSyncTransfer();
        return;
    }
    // 更新最后 RDB 产生的 IO 时间
    server.repl_transfer_lastio = server.unixtime;
    if (write(server.repl_transfer_fd,buf,nread) != nread) {
        redisLog(REDIS_WARNING,"Write error or short write writing to the DB dump file needed for MASTER <-> SLAVE synchronization: %s", strerror(errno));
        goto error;
    }
    // 加上刚读取好的字节数
    server.repl_transfer_read += nread;

    /* Sync data on disk from time to time, otherwise at the end of the transfer
     * we may suffer a big delay as the memory buffers are copied into the
     * actual disk. */
    // 定期将读入的文件 fsync 到磁盘，以免 buffer 太多，一下子写入时撑爆 IO
    if (server.repl_transfer_read >=
        server.repl_transfer_last_fsync_off + REPL_MAX_WRITTEN_BEFORE_FSYNC)
    {
        off_t sync_size = server.repl_transfer_read -
                          server.repl_transfer_last_fsync_off;
        rdb_fsync_range(server.repl_transfer_fd,
            server.repl_transfer_last_fsync_off, sync_size);
        server.repl_transfer_last_fsync_off += sync_size;
    }

    /* Check if the transfer is now complete */
    // 检查 RDB 是否已经传送完毕
    if (server.repl_transfer_read == server.repl_transfer_size) {

        // 完毕，将临时文件改名为 dump.rdb
        if (rename(server.repl_transfer_tmpfile,server.rdb_filename) == -1) {
            redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
            replicationAbortSyncTransfer();
            return;
        }

        // 先清空旧数据库
        redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Flushing old data");
        signalFlushedDb(-1);
        emptyDb(replicationEmptyDbCallback);
        /* Before loading the DB into memory we need to delete the readable
         * handler, otherwise it will get called recursively since
         * rdbLoad() will call the event loop to process events from time to
         * time for non blocking loading. */
        // 先删除主服务器的读事件监听，因为 rdbLoad() 函数也会监听读事件
        aeDeleteFileEvent(server.el,server.repl_transfer_s,AE_READABLE);

        // 载入 RDB
        if (rdbLoad(server.rdb_filename) != REDIS_OK) {
            redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
            replicationAbortSyncTransfer();
            return;
        }

        /* Final setup of the connected slave <- master link */
        // 关闭临时文件
        zfree(server.repl_transfer_tmpfile);
        close(server.repl_transfer_fd);

        // 将主服务器设置成一个 redis client
        // 注意 createClient 会为主服务器绑定事件，为接下来接收命令做好准备
        server.master = createClient(server.repl_transfer_s);
        // 标记这个客户端为主服务器
        server.master->flags |= REDIS_MASTER;
        // 标记它为已验证身份
        server.master->authenticated = 1;
        // 更新复制状态
        server.repl_state = REDIS_REPL_CONNECTED;
        // 设置主服务器的复制偏移量
        server.master->reploff = server.repl_master_initial_offset;
        // 保存主服务器的 RUN ID
        memcpy(server.master->replrunid, server.repl_master_runid,
            sizeof(server.repl_master_runid));

        /* If master offset is set to -1, this master is old and is not
         * PSYNC capable, so we flag it accordingly. */
        // 如果 offset 被设置为 -1 ，那么表示主服务器的版本低于 2.8 
        // 无法使用 PSYNC ，所以需要设置相应的标识值
        if (server.master->reploff == -1)
            server.master->flags |= REDIS_PRE_PSYNC;
        redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Finished with success");

        /* Restart the AOF subsystem now that we finished the sync. This
         * will trigger an AOF rewrite, and when done will start appending
         * to the new file. */
        // 如果有开启 AOF 持久化，那么重启 AOF 功能，并强制生成新数据库的 AOF 文件
        if (server.aof_state != REDIS_AOF_OFF) {
            int retry = 10;

            // 关闭
            stopAppendOnly();
            // 再重启
            while (retry-- && startAppendOnly() == REDIS_ERR) {
                redisLog(REDIS_WARNING,"Failed enabling the AOF after successful master synchronization! Trying it again in one second.");
                sleep(1);
            }
            if (!retry) {
                redisLog(REDIS_WARNING,"FATAL: this slave instance finished the synchronization with its master, but the AOF can't be turned on. Exiting now.");
                exit(1);
            }
        }
    }

    return;

error:
    replicationAbortSyncTransfer();
    return;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x1008, %rsp           # imm = 0x1008
movl %esi, %edi
leaq 0x95b58(%rip), %r15     # 0xc9fa8
movq 0x678(%r15), %rdx
cmpq $-0x1, %rdx
je 0x3458d
subq 0x680(%r15), %rdx
movl $0x1000, %eax           # imm = 0x1000
cmpq %rax, %rdx
cmovgeq %rax, %rdx
movq %rsp, %rsi
callq 0x1f330
movq %rax, %rbx
testq %rax, %rax
jle 0x345dd
movq 0x798(%r15), %rax
movq %rax, 0x6a0(%r15)
movl 0x694(%r15), %edi
movq %rsp, %rsi
movq %rbx, %rdx
callq 0x1fb30
cmpq %rbx, %rax
jne 0x345ec
movq 0x680(%r15), %r14
addq %rbx, %r14
movq %r14, 0x680(%r15)
movq 0x688(%r15), %rsi
leaq 0x800000(%rsi), %rax
cmpq %rax, %r14
jl 0x344f3
subq %rsi, %r14
movl 0x694(%r15), %edi
movq %r14, %rdx
movl $0x3, %ecx
callq 0x1fc30
addq %r14, 0x688(%r15)
movq 0x680(%r15), %rax
cmpq 0x678(%r15), %rax
jne 0x346b0
movq 0x588(%r15), %rsi
movq 0x698(%r15), %rdi
callq 0x1fc20
cmpl $-0x1, %eax
je 0x346be
leaq 0x63a5c(%rip), %rsi     # 0x97f86
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x31956
leaq -0x112(%rip), %rdi      # 0x34435
callq 0x3185b
movq 0x28(%r15), %rdi
movl 0x690(%r15), %esi
movl $0x1, %edx
callq 0x20a9d
movq 0x588(%r15), %rdi
callq 0x3811a
testl %eax, %eax
je 0x346de
leaq 0x63a33(%rip), %rsi     # 0x97faf
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
jmp 0x34643
movslq 0x670(%r15), %rax
imulq $0x3e8, %rax, %rcx      # imm = 0x3E8
movq %rsp, %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x4fbd5
cmpq $-0x1, %rax
je 0x34601
movzbl (%rsp), %eax
testl %eax, %eax
je 0x34685
cmpl $0x24, %eax
je 0x34655
cmpl $0x2d, %eax
jne 0x34695
leaq 0x1(%rsp), %rdx
leaq 0x637dd(%rip), %rsi     # 0x97db5
jmp 0x3469f
cmpq $-0x1, %rbx
je 0x34621
leaq 0x638cb(%rip), %rdx     # 0x97eb5
jmp 0x34630
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x638c6(%rip), %rsi     # 0x97ec5
jmp 0x34614
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x63774(%rip), %rsi     # 0x97d88
movl $0x3, %edi
movq %rax, %rdx
jmp 0x346a4
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
leaq 0x63855(%rip), %rsi     # 0x97e8c
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
addq $0x1008, %rsp           # imm = 0x1008
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x34374
leaq 0x1(%rsp), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x1f6d0
movq %rax, 0x678(%r15)
leaq 0x637e0(%rip), %rsi     # 0x97e54
movl $0x2, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23064
jmp 0x346b0
movq 0x798(%r15), %rax
movq %rax, 0x6a0(%r15)
jmp 0x346b0
leaq 0x63746(%rip), %rsi     # 0x97de2
movq %rsp, %rdx
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
callq 0x34374
addq $0x1008, %rsp           # imm = 0x1008
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x6385b(%rip), %rsi     # 0x97f2c
movl $0x3, %edi
movq %rax, %rdx
jmp 0x3463c
movq 0x698(%r15), %rdi
callq 0x2984b
movl 0x694(%r15), %edi
callq 0x1f170
movl 0x690(%r15), %edi
callq 0x2cd47
movq %rax, 0x660(%r15)
orb $0x2, 0x90(%rax)
movl $0x1, 0x94(%rax)
movl $0x5, 0x674(%r15)
movq 0x6f0(%r15), %rcx
movq %rcx, 0xb8(%rax)
movups 0x6c0(%r15), %xmm0
movups 0x6d0(%r15), %xmm1
movups 0x6d9(%r15), %xmm2
movups %xmm2, 0xe9(%rax)
movups %xmm1, 0xe0(%rax)
movups %xmm0, 0xd0(%rax)
movq 0x660(%r15), %rax
cmpq $-0x1, 0xb8(%rax)
jne 0x34778
orb $0x1, 0x92(%rax)
leaq 0x6386e(%rip), %rsi     # 0x97fed
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
cmpl $0x0, 0x4d0(%r15)
je 0x346b0
callq 0x495b7
movl $0x9, %ebp
leaq 0x63870(%rip), %rbx     # 0x9801a
callq 0x49a1c
cmpl $-0x1, %eax
jne 0x347d7
movl $0x3, %edi
movq %rbx, %rsi
xorl %eax, %eax
callq 0x23064
movl $0x1, %edi
callq 0x1f5c0
addl $-0x1, %ebp
jb 0x347aa
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
testl %ebp, %ebp
jne 0x346b0
leaq 0x63894(%rip), %rsi     # 0x9807a
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
movl $0x1, %edi
callq 0x1f2b0