// File: /workspace/github_c_makefile_star2_O2/nilyang[P]redis-tdd-annotation/src/replication.c
// Function: syncWithMaster
void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
    char tmpfile[256], *err;
    int dfd, maxtries = 5;
    int sockerr = 0, psync_result;
    socklen_t errlen = sizeof(sockerr);
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(privdata);
    REDIS_NOTUSED(mask);

    /* If this event fired after the user turned the instance into a master
     * with SLAVEOF NO ONE we must just return ASAP. */
    // 如果处于 SLAVEOF NO ONE 模式，那么关闭 fd
    if (server.repl_state == REDIS_REPL_NONE) {
        close(fd);
        return;
    }

    /* Check for errors in the socket. */
    // 检查套接字错误
    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) == -1)
        sockerr = errno;
    if (sockerr) {
        aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
        redisLog(REDIS_WARNING,"Error condition on socket for SYNC: %s",
            strerror(sockerr));
        goto error;
    }

    /* If we were connecting, it's time to send a non blocking PING, we want to
     * make sure the master is able to reply before going into the actual
     * replication process where we have long timeouts in the order of
     * seconds (in the meantime the slave would block). */
    // 如果状态为 CONNECTING ，那么在进行初次同步之前，
    // 向主服务器发送一个非阻塞的 PONG 
    // 因为接下来的 RDB 文件发送非常耗时，所以我们想确认主服务器真的能访问
    if (server.repl_state == REDIS_REPL_CONNECTING) {
        redisLog(REDIS_NOTICE,"Non blocking connect for SYNC fired the event.");
        /* Delete the writable event so that the readable event remains
         * registered and we can wait for the PONG reply. */
        // 手动发送同步 PING ，暂时取消监听写事件
        aeDeleteFileEvent(server.el,fd,AE_WRITABLE);
        // 更新状态
        server.repl_state = REDIS_REPL_RECEIVE_PONG;
        /* Send the PING, don't check for errors at all, we have the timeout
         * that will take care about this. */
        // 同步发送 PING
        syncWrite(fd,"PING\r\n",6,100);

        // 返回，等待 PONG 到达
        return;
    }

    /* Receive the PONG command. */
    // 接收 PONG 命令
    if (server.repl_state == REDIS_REPL_RECEIVE_PONG) {
        char buf[1024];

        /* Delete the readable event, we no longer need it now that there is
         * the PING reply to read. */
        // 手动同步接收 PONG ，暂时取消监听读事件
        aeDeleteFileEvent(server.el,fd,AE_READABLE);

        /* Read the reply with explicit timeout. */
        // 尝试在指定时间限制内读取 PONG
        buf[0] = '\0';
        // 同步接收 PONG
        if (syncReadLine(fd,buf,sizeof(buf),
            server.repl_syncio_timeout*1000) == -1)
        {
            redisLog(REDIS_WARNING,
                "I/O error reading PING reply from master: %s",
                strerror(errno));
            goto error;
        }

        /* We accept only two replies as valid, a positive +PONG reply
         * (we just check for "+") or an authentication error.
         * Note that older versions of Redis replied with "operation not
         * permitted" instead of using a proper error code, so we test
         * both. */
        // 接收到的数据只有两种可能：
        // 第一种是 +PONG ，第二种是因为未验证而出现的 -NOAUTH 错误
        if (buf[0] != '+' &&
            strncmp(buf,"-NOAUTH",7) != 0 &&
            strncmp(buf,"-ERR operation not permitted",28) != 0)
        {
            // 接收到未验证错误
            redisLog(REDIS_WARNING,"Error reply to PING from master: '%s'",buf);
            goto error;
        } else {
            // 接收到 PONG
            redisLog(REDIS_NOTICE,
                "Master replied to PING, replication can continue...");
        }
    }

    /* AUTH with the master if required. */
    // 进行身份验证
    if(server.masterauth) {
        err = sendSynchronousCommand(fd,"AUTH",server.masterauth,NULL);
        if (err[0] == '-') {
            redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",err);
            sdsfree(err);
            goto error;
        }
        sdsfree(err);
    }

    /* Set the slave port, so that Master's INFO command can list the
     * slave listening port correctly. */
    // 将从服务器的端口发送给主服务器，
    // 使得主服务器的 INFO 命令可以显示从服务器正在监听的端口
    {
        sds port = sdsfromlonglong(server.port);
        err = sendSynchronousCommand(fd,"REPLCONF","listening-port",port,
                                         NULL);
        sdsfree(port);
        /* Ignore the error if any, not all the Redis versions support
         * REPLCONF listening-port. */
        if (err[0] == '-') {
            redisLog(REDIS_NOTICE,"(Non critical) Master does not understand REPLCONF listening-port: %s", err);
        }
        sdsfree(err);
    }

    /* Try a partial resynchonization. If we don't have a cached master
     * slaveTryPartialResynchronization() will at least try to use PSYNC
     * to start a full resynchronization so that we get the master run id
     * and the global offset, to try a partial resync at the next
     * reconnection attempt. */
    // 根据返回的结果决定是执行部分 resync ，还是 full-resync
    psync_result = slaveTryPartialResynchronization(fd);

    // 可以执行部分 resync
    if (psync_result == PSYNC_CONTINUE) {
        redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Master accepted a Partial Resynchronization.");
        // 返回
        return;
    }

    /* Fall back to SYNC if needed. Otherwise psync_result == PSYNC_FULLRESYNC
     * and the server.repl_master_runid and repl_master_initial_offset are
     * already populated. */
    // 主服务器不支持 PSYNC ，发送 SYNC
    if (psync_result == PSYNC_NOT_SUPPORTED) {
        redisLog(REDIS_NOTICE,"Retrying with SYNC...");
        // 向主服务器发送 SYNC 命令
        if (syncWrite(fd,"SYNC\r\n",6,server.repl_syncio_timeout*1000) == -1) {
            redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
                strerror(errno));
            goto error;
        }
    }

    // 如果执行到这里，
    // 那么 psync_result == PSYNC_FULLRESYNC 或 PSYNC_NOT_SUPPORTED

    /* Prepare a suitable temp file for bulk transfer */
    // 打开一个临时文件，用于写入和保存接下来从主服务器传来的 RDB 文件数据
    while(maxtries--) {
        snprintf(tmpfile,256,
            "temp-%d.%ld.rdb",(int)server.unixtime,(long int)getpid());
        dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
        if (dfd != -1) break;
        sleep(1);
    }
    if (dfd == -1) {
        redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
        goto error;
    }

    /* Setup the non blocking download of the bulk file. */
    // 设置一个读事件处理器，来读取主服务器的 RDB 文件
    if (aeCreateFileEvent(server.el,fd, AE_READABLE,readSyncBulkPayload,NULL)
            == AE_ERR)
    {
        redisLog(REDIS_WARNING,
            "Can't create readable event for SYNC: %s (fd=%d)",
            strerror(errno),fd);
        goto error;
    }

    // 设置状态
    server.repl_state = REDIS_REPL_TRANSFER;

    // 更新统计信息
    server.repl_transfer_size = -1;
    server.repl_transfer_read = 0;
    server.repl_transfer_last_fsync_off = 0;
    server.repl_transfer_fd = dfd;
    server.repl_transfer_lastio = server.unixtime;
    server.repl_transfer_tmpfile = zstrdup(tmpfile);

    return;

error:
    close(fd);
    server.repl_transfer_s = -1;
    server.repl_state = REDIS_REPL_CONNECT;
    return;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x418, %rsp            # imm = 0x418
movl %esi, %ebx
andl $0x0, 0x8(%rsp)
movl $0x4, 0xc(%rsp)
leaq 0x93fee(%rip), %r13     # 0xc6fa8
cmpl $0x0, 0x674(%r13)
je 0x32fe6
pushq $0x1
popq %rsi
pushq $0x4
popq %rdx
leaq 0x8(%rsp), %rcx
leaq 0xc(%rsp), %r8
movl %ebx, %edi
callq 0x1f6b0
cmpl $-0x1, %eax
je 0x32ffe
movl 0x8(%rsp), %eax
jmp 0x33009
movl %ebx, %edi
addq $0x418, %rsp            # imm = 0x418
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1f170
callq 0x1f810
movl (%rax), %eax
movl %eax, 0x8(%rsp)
testl %eax, %eax
je 0x33065
movq 0x28(%r13), %rdi
pushq $0x3
popq %rbp
movl %ebx, %esi
movl %ebp, %edx
callq 0x203cd
movl 0x8(%rsp), %edi
callq 0x1f630
leaq 0x5b2a0(%rip), %rsi     # 0x8e2cd
movl %ebp, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x22613
movl %ebx, %edi
callq 0x1f170
orl $-0x1, 0x690(%r13)
movl $0x1, 0x674(%r13)
addq $0x418, %rsp            # imm = 0x418
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0x674(%r13), %eax
cmpl $0x3, %eax
je 0x330bb
cmpl $0x2, %eax
jne 0x33151
leaq 0x5b273(%rip), %rsi     # 0x8e2f4
pushq $0x2
popq %rbp
movl %ebp, %edi
xorl %eax, %eax
callq 0x22613
movq 0x28(%r13), %rdi
movl %ebx, %esi
movl %ebp, %edx
callq 0x203cd
movl $0x3, 0x674(%r13)
leaq 0x5b277(%rip), %rsi     # 0x8e323
pushq $0x6
popq %rdx
pushq $0x64
popq %rcx
movl %ebx, %edi
callq 0x4b630
jmp 0x33053
movq 0x28(%r13), %rdi
pushq $0x1
popq %rdx
movl %ebx, %esi
callq 0x203cd
leaq 0x10(%rsp), %rsi
movb $0x0, (%rsi)
movslq 0x670(%r13), %rax
imulq $0x3e8, %rax, %rcx      # imm = 0x3E8
movl $0x400, %edx            # imm = 0x400
movl %ebx, %edi
callq 0x4b772
cmpq $-0x1, %rax
je 0x3321f
cmpb $0x2b, 0x10(%rsp)
je 0x33140
leaq 0x5b254(%rip), %rsi     # 0x8e357
leaq 0x10(%rsp), %rdi
pushq $0x7
popq %rdx
callq 0x1f6a0
testl %eax, %eax
je 0x33140
leaq 0x5b244(%rip), %rsi     # 0x8e35f
leaq 0x10(%rsp), %rdi
pushq $0x1c
popq %rdx
callq 0x1f6a0
testl %eax, %eax
je 0x33140
leaq 0x5b249(%rip), %rsi     # 0x8e37c
pushq $0x3
popq %rdi
leaq 0x10(%rsp), %rdx
jmp 0x33032
leaq 0x5b25b(%rip), %rsi     # 0x8e3a2
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
movq 0x648(%r13), %rdx
testq %rdx, %rdx
je 0x331a0
leaq 0x5b1f6(%rip), %rsi     # 0x8e35a
movl %ebx, %edi
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x32a48
movq %rax, %r14
cmpb $0x2d, (%rax)
jne 0x33198
leaq 0x5b258(%rip), %rsi     # 0x8e3d6
pushq $0x3
popq %rdi
movq %r14, %rdx
xorl %eax, %eax
callq 0x22613
movq %r14, %rdi
callq 0x271f7
jmp 0x33039
movq %r14, %rdi
callq 0x271f7
movslq 0x88(%r13), %rdi
callq 0x27535
movq %rax, %r15
leaq 0x5767e(%rip), %rsi     # 0x8a834
leaq 0x5aa39(%rip), %rdx     # 0x8dbf6
movl %ebx, %edi
movq %rax, %rcx
xorl %r8d, %r8d
xorl %eax, %eax
callq 0x32a48
movq %rax, %r14
movq %r15, %rdi
callq 0x271f7
cmpb $0x2d, (%r14)
jne 0x331f1
leaq 0x5b20f(%rip), %rsi     # 0x8e3f3
pushq $0x2
popq %rdi
movq %r14, %rdx
xorl %eax, %eax
callq 0x22613
movq %r14, %rdi
callq 0x271f7
movl %ebx, %edi
callq 0x32c02
cmpl $0x2, %eax
je 0x33237
testl %eax, %eax
jne 0x33271
leaq 0x5b229(%rip), %rsi     # 0x8e439
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
jmp 0x33053
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b0f8(%rip), %rsi     # 0x8e32a
jmp 0x33360
leaq 0x5b23f(%rip), %rsi     # 0x8e47d
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
movslq 0x670(%r13), %rax
imulq $0x3e8, %rax, %rcx      # imm = 0x3E8
leaq 0x5b236(%rip), %rsi     # 0x8e493
pushq $0x6
popq %rdx
movl %ebx, %edi
callq 0x4b630
cmpq $-0x1, %rax
je 0x3334d
pushq $-0x5
popq %r14
leaq 0x10(%rsp), %r15
pushq $0x1
popq %rbp
testl %r14d, %r14d
je 0x332cf
movl 0x798(%r13), %r12d
callq 0x1f410
movslq %eax, %r8
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
leaq 0x5b21a(%rip), %rdx     # 0x8e4ba
movl %r12d, %ecx
xorl %eax, %eax
callq 0x1f120
movq %r15, %rdi
movl $0xc1, %esi
movl $0x1a4, %edx            # imm = 0x1A4
xorl %eax, %eax
callq 0x1f640
cmpl $-0x1, %eax
jne 0x332e4
movl %ebp, %edi
callq 0x1f5c0
incl %r14d
jmp 0x3327d
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b1e8(%rip), %rsi     # 0x8e4ca
jmp 0x33360
movl %eax, %r12d
movq 0x28(%r13), %rdi
leaq -0xc61(%rip), %rcx      # 0x32691
pushq $0x1
popq %rdx
movl %ebx, %esi
xorl %r8d, %r8d
callq 0x2030c
cmpl $-0x1, %eax
je 0x33368
movl $0x4, 0x674(%r13)
orq $-0x1, 0x678(%r13)
xorps %xmm0, %xmm0
movups %xmm0, 0x680(%r13)
movl %r12d, 0x694(%r13)
movq 0x798(%r13), %rax
movq %rax, 0x6a0(%r13)
leaq 0x10(%rsp), %rdi
callq 0x28407
movq %rax, 0x698(%r13)
jmp 0x33053
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b13a(%rip), %rsi     # 0x8e49a
pushq $0x3
popq %rdi
jmp 0x3302f
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x5b195(%rip), %rsi     # 0x8e510
pushq $0x3
popq %rdi
movq %rax, %rdx
movl %ebx, %ecx
xorl %eax, %eax
callq 0x22613
jmp 0x33039