// File: /workspace/github_c_makefile_star2_O2/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 %r12
pushq %rbx
subq $0x1000, %rsp           # imm = 0x1000
movl %esi, %edi
leaq 0x948ff(%rip), %r15     # 0xc6fa8
movq 0x678(%r15), %rdx
cmpq $-0x1, %rdx
je 0x327dc
subq 0x680(%r15), %rdx
movl $0x1000, %eax           # imm = 0x1000
cmpq %rax, %rdx
cmovgeq %rax, %rdx
movq %rsp, %rsi
callq 0x1f330
movq %rax, %r14
testq %rax, %rax
jle 0x3282c
movq 0x798(%r15), %rax
movq %rax, 0x6a0(%r15)
movl 0x694(%r15), %edi
movq %rsp, %rsi
movq %r14, %rdx
callq 0x1fb30
cmpq %r14, %rax
jne 0x3283b
movq 0x680(%r15), %rbx
addq %r14, %rbx
movq %rbx, 0x680(%r15)
movq 0x688(%r15), %rsi
leaq 0x800000(%rsi), %rax
cmpq %rax, %rbx
jl 0x32751
subq %rsi, %rbx
movl 0x694(%r15), %edi
pushq $0x3
popq %rcx
movq %rbx, %rdx
callq 0x1fc30
addq %rbx, 0x688(%r15)
movq 0x680(%r15), %rbx
cmpq 0x678(%r15), %rbx
jne 0x32875
movq 0x588(%r15), %rsi
movq 0x698(%r15), %rdi
callq 0x1fc20
cmpl $-0x1, %eax
je 0x32907
leaq 0x5b839(%rip), %rsi     # 0x8dfba
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
pushq $-0x1
popq %rdi
callq 0x2fe17
leaq -0x10e(%rip), %rdi      # 0x3268c
callq 0x2fd47
movq 0x28(%r15), %rdi
movl 0x690(%r15), %esi
pushq $0x1
popq %rdx
callq 0x203cd
movq 0x588(%r15), %rdi
callq 0x35a8b
testl %eax, %eax
je 0x32925
leaq 0x5b816(%rip), %rsi     # 0x8dfe3
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x22613
jmp 0x328a5
movslq 0x670(%r15), %rax
imulq $0x3e8, %rax, %rcx      # imm = 0x3E8
movq %rsp, %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x4b772
cmpq $-0x1, %rax
je 0x32850
movzbl (%rsp), %eax
testl %eax, %eax
je 0x328e5
cmpl $0x24, %eax
je 0x328b9
cmpl $0x2d, %eax
jne 0x328f5
leaq 0x1(%rsp), %rdx
leaq 0x5b5c2(%rip), %rsi     # 0x8dde9
pushq $0x3
popq %rdi
jmp 0x32869
cmpq $-0x1, %r14
je 0x32885
leaq 0x5b6b0(%rip), %rdx     # 0x8dee9
jmp 0x32894
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b6ab(%rip), %rsi     # 0x8def9
jmp 0x32863
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b559(%rip), %rsi     # 0x8ddbc
pushq $0x3
popq %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x22613
callq 0x325d1
addq $0x1000, %rsp           # imm = 0x1000
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
leaq 0x5b625(%rip), %rsi     # 0x8dec0
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x22613
addq $0x1000, %rsp           # imm = 0x1000
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
jmp 0x325d1
leaq 0x1(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x1f6d0
movq %rax, 0x678(%r15)
leaq 0x5b5b2(%rip), %rsi     # 0x8de88
pushq $0x2
popq %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x22613
jmp 0x32875
movq 0x798(%r15), %rax
movq %rax, 0x6a0(%r15)
jmp 0x32875
leaq 0x5b51a(%rip), %rsi     # 0x8de16
pushq $0x3
popq %rdi
movq %rsp, %rdx
jmp 0x32869
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b646(%rip), %rsi     # 0x8df60
pushq $0x3
popq %rdi
movq %rax, %rdx
jmp 0x3289e
movq 0x698(%r15), %rdi
callq 0x283cd
movl 0x694(%r15), %edi
callq 0x1f170
movl 0x690(%r15), %edi
callq 0x2b7d3
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 0x329bf
orb $0x1, 0x92(%rax)
leaq 0x5b65b(%rip), %rsi     # 0x8e021
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
cmpl $0x0, 0x4d0(%r15)
je 0x32875
callq 0x45bb6
pushq $0xa
popq %r12
leaq 0x5b660(%rip), %rbx     # 0x8e04e
pushq $0x3
popq %rbp
pushq $0x1
popq %r14
movl %r12d, %r15d
subl $0x1, %r15d
jb 0x32875
callq 0x45fa2
cmpl $-0x1, %eax
jne 0x32a25
movl %ebp, %edi
movq %rbx, %rsi
xorl %eax, %eax
callq 0x22613
movl %r14d, %edi
callq 0x1f5c0
movl %r15d, %r12d
jmp 0x329f8
cmpl $0x1, %r12d
jne 0x32875
leaq 0x5b678(%rip), %rsi     # 0x8e0ae
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x22613
pushq $0x1
popq %rdi
callq 0x1f2b0