// File: /workspace/github_c_makefile_star2_O1/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
movl $0x0, 0x8(%rsp)
movl $0x4, 0xc(%rsp)
leaq 0x95203(%rip), %r12     # 0xc9fa8
cmpl $0x0, 0x674(%r12)
je 0x34e47
leaq 0x8(%rsp), %rcx
leaq 0xc(%rsp), %r8
movl %ebx, %edi
movl $0x1, %esi
movl $0x4, %edx
callq 0x1f6b0
cmpl $-0x1, %eax
jne 0x34ddf
callq 0x1f810
movl (%rax), %eax
movl %eax, 0x8(%rsp)
cmpl $0x0, 0x8(%rsp)
je 0x34e5f
movq 0x28(%r12), %rdi
movl %ebx, %esi
movl $0x3, %edx
callq 0x20a9d
movl 0x8(%rsp), %edi
callq 0x1f630
leaq 0x63492(%rip), %rsi     # 0x98299
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23064
movl %ebx, %edi
callq 0x1f170
movl $0xffffffff, 0x690(%r12) # imm = 0xFFFFFFFF
movl $0x1, 0x674(%r12)
addq $0x418, %rsp            # imm = 0x418
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl %ebx, %edi
addq $0x418, %rsp            # imm = 0x418
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1f170
movl 0x674(%r12), %eax
cmpl $0x3, %eax
je 0x34ec2
cmpl $0x2, %eax
jne 0x34f71
leaq 0x63444(%rip), %rsi     # 0x982c0
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
movq 0x28(%r12), %rdi
movl %ebx, %esi
movl $0x2, %edx
callq 0x20a9d
movl $0x3, 0x674(%r12)
leaq 0x63443(%rip), %rsi     # 0x982ef
movl $0x6, %edx
movl $0x64, %ecx
movl %ebx, %edi
callq 0x4fa20
jmp 0x34e35
movq 0x28(%r12), %rdi
movl %ebx, %esi
movl $0x1, %edx
callq 0x20a9d
leaq 0x10(%rsp), %rsi
movb $0x0, (%rsi)
movslq 0x670(%r12), %rax
imulq $0x3e8, %rax, %rcx      # imm = 0x3E8
movl $0x400, %edx            # imm = 0x400
movl %ebx, %edi
callq 0x4fbd5
cmpq $-0x1, %rax
je 0x35047
cmpb $0x2b, 0x10(%rsp)
je 0x34f5e
movl $0x414f4e2d, %eax       # imm = 0x414F4E2D
xorl 0x10(%rsp), %eax
movl $0x48545541, %ecx       # imm = 0x48545541
xorl 0x13(%rsp), %ecx
orl %eax, %ecx
je 0x34f5e
movdqa 0x10(%rsp), %xmm0
movdqu 0x1c(%rsp), %xmm1
pcmpeqb 0x627af(%rip), %xmm1    # 0x976e0
pcmpeqb 0x627b7(%rip), %xmm0    # 0x976f0
pand %xmm1, %xmm0
pmovmskb %xmm0, %eax
cmpl $0xffff, %eax           # imm = 0xFFFF
je 0x34f5e
leaq 0x633f9(%rip), %rsi     # 0x98348
leaq 0x10(%rsp), %rdx
movl $0x3, %edi
jmp 0x34e0f
leaq 0x63409(%rip), %rsi     # 0x9836e
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
movq 0x648(%r12), %rdx
testq %rdx, %rdx
je 0x34fc3
leaq 0x633a1(%rip), %rsi     # 0x98326
movl %ebx, %edi
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x347fc
movq %rax, %r14
cmpb $0x2d, (%rax)
jne 0x34fbb
leaq 0x63403(%rip), %rsi     # 0x983a2
movl $0x3, %edi
movq %r14, %rdx
xorl %eax, %eax
callq 0x23064
movq %r14, %rdi
callq 0x28204
jmp 0x34e16
movq %r14, %rdi
callq 0x28204
movslq 0x88(%r12), %rdi
callq 0x2861d
movq %rax, %r15
leaq 0x5f84a(%rip), %rsi     # 0x94824
leaq 0x62be1(%rip), %rdx     # 0x97bc2
movl %ebx, %edi
movq %rax, %rcx
xorl %r8d, %r8d
xorl %eax, %eax
callq 0x347fc
movq %rax, %r14
movq %r15, %rdi
callq 0x28204
cmpb $0x2d, (%r14)
jne 0x35017
leaq 0x633b7(%rip), %rsi     # 0x983bf
movl $0x2, %edi
movq %r14, %rdx
xorl %eax, %eax
callq 0x23064
movq %r14, %rdi
callq 0x28204
movl %ebx, %edi
callq 0x349b6
cmpl $0x2, %eax
je 0x3505f
testl %eax, %eax
jne 0x3509e
leaq 0x633cf(%rip), %rsi     # 0x98405
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
jmp 0x34e35
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x6329c(%rip), %rsi     # 0x982f6
jmp 0x34e07
leaq 0x633e3(%rip), %rsi     # 0x98449
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
movslq 0x670(%r12), %rax
imulq $0x3e8, %rax, %rcx      # imm = 0x3E8
leaq 0x633d7(%rip), %rsi     # 0x9845f
movl $0x6, %edx
movl %ebx, %edi
callq 0x4fa20
cmpq $-0x1, %rax
je 0x351c0
movl $0xfffffffb, %r13d      # imm = 0xFFFFFFFB
leaq 0x633db(%rip), %r14     # 0x98486
leaq 0x10(%rsp), %r15
movl 0x798(%r12), %ebp
callq 0x1f410
movslq %eax, %r8
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rdx
movl %ebp, %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 0x35103
movl $0x1, %edi
callq 0x1f5c0
incl %r13d
jne 0x350b0
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
jmp 0x35105
movl %eax, %ebp
cmpl $-0x1, %ebp
je 0x3517f
movq 0x28(%r12), %rdi
leaq -0xcdc(%rip), %rcx      # 0x3443a
movl %ebx, %esi
movl $0x1, %edx
xorl %r8d, %r8d
callq 0x209d7
cmpl $-0x1, %eax
je 0x35197
movl $0x4, 0x674(%r12)
movq $-0x1, 0x678(%r12)
pxor %xmm0, %xmm0
movdqu %xmm0, 0x680(%r12)
movl %ebp, 0x694(%r12)
movq 0x798(%r12), %rax
movq %rax, 0x6a0(%r12)
leaq 0x10(%rsp), %rdi
callq 0x29885
movq %rax, 0x698(%r12)
jmp 0x34e35
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x63304(%rip), %rsi     # 0x98496
jmp 0x34e07
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x63332(%rip), %rsi     # 0x984dc
movl $0x3, %edi
movq %rax, %rdx
movl %ebx, %ecx
xorl %eax, %eax
callq 0x23064
jmp 0x34e16
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x63293(%rip), %rsi     # 0x98466
jmp 0x34e07