// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x560, %rsp            # imm = 0x560
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
movl $0x5, -0x130(%rbp)
movl $0x0, -0x134(%rbp)
movl $0x4, -0x13c(%rbp)
leaq 0xd20aa(%rip), %rax     # 0x1138f8
cmpl $0x0, 0x674(%rax)
jne 0x41864
movl -0xc(%rbp), %edi
callq 0x1f170
jmp 0x41dd2
movl -0xc(%rbp), %edi
movl $0x1, %esi
movl $0x4, %edx
leaq -0x134(%rbp), %rcx
leaq -0x13c(%rbp), %r8
callq 0x1f6a0
cmpl $-0x1, %eax
jne 0x41896
callq 0x1f820
movl (%rax), %eax
movl %eax, -0x134(%rbp)
cmpl $0x0, -0x134(%rbp)
je 0x418dd
leaq 0xd2052(%rip), %rax     # 0x1138f8
movq 0x28(%rax), %rdi
movl -0xc(%rbp), %esi
movl $0x3, %edx
callq 0x20c60
movl -0x134(%rbp), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0xa0b04(%rip), %rsi     # 0xe23d5
movb $0x0, %al
callq 0x24fb0
jmp 0x41da8
leaq 0xd2014(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x674(%rax)
jne 0x41947
movl $0x2, %edi
leaq 0xa0b03(%rip), %rsi     # 0xe23fc
movb $0x0, %al
callq 0x24fb0
leaq 0xd1ff1(%rip), %rax     # 0x1138f8
movq 0x28(%rax), %rdi
movl -0xc(%rbp), %esi
movl $0x2, %edx
callq 0x20c60
leaq 0xd1fd9(%rip), %rax     # 0x1138f8
movl $0x3, 0x674(%rax)
movl -0xc(%rbp), %edi
leaq 0xa0af8(%rip), %rsi     # 0xe242b
movl $0x6, %edx
movl $0x64, %ecx
callq 0x67bb0
jmp 0x41dd2
leaq 0xd1faa(%rip), %rax     # 0x1138f8
cmpl $0x3, 0x674(%rax)
jne 0x41a49
leaq 0xd1f96(%rip), %rax     # 0x1138f8
movq 0x28(%rax), %rdi
movl -0xc(%rbp), %esi
movl $0x1, %edx
callq 0x20c60
movb $0x0, -0x540(%rbp)
movl -0xc(%rbp), %edi
leaq -0x540(%rbp), %rsi
leaq 0xd1f6d(%rip), %rax     # 0x1138f8
imull $0x3e8, 0x670(%rax), %eax # imm = 0x3E8
movslq %eax, %rcx
movl $0x400, %edx            # imm = 0x400
callq 0x67e10
cmpq $-0x1, %rax
jne 0x419cf
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0xa0a6f(%rip), %rsi     # 0xe2432
movb $0x0, %al
callq 0x24fb0
jmp 0x41da8
movsbl -0x540(%rbp), %eax
cmpl $0x2b, %eax
je 0x41a34
leaq -0x540(%rbp), %rdi
leaq 0xa0a76(%rip), %rsi     # 0xe245f
movl $0x7, %edx
callq 0x1f340
cmpl $0x0, %eax
je 0x41a34
leaq -0x540(%rbp), %rdi
leaq 0xa0a61(%rip), %rsi     # 0xe2467
movl $0x1c, %edx
callq 0x1f340
cmpl $0x0, %eax
je 0x41a34
leaq -0x540(%rbp), %rdx
movl $0x3, %edi
leaq 0xa0a5c(%rip), %rsi     # 0xe2484
movb $0x0, %al
callq 0x24fb0
jmp 0x41da8
movl $0x2, %edi
leaq 0xa0a6a(%rip), %rsi     # 0xe24aa
movb $0x0, %al
callq 0x24fb0
jmp 0x41a49
leaq 0xd1ea8(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x648(%rax)
je 0x41aca
movl -0xc(%rbp), %edi
leaq 0xd1e94(%rip), %rax     # 0x1138f8
movq 0x648(%rax), %rdx
leaq 0xa09f0(%rip), %rsi     # 0xe2462
xorl %eax, %eax
movl %eax, %ecx
movb $0x0, %al
callq 0x41030
movq %rax, -0x128(%rbp)
movq -0x128(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x2d, %eax
jne 0x41abe
movq -0x128(%rbp), %rdx
movl $0x3, %edi
leaq 0xa0a38(%rip), %rsi     # 0xe24de
movb $0x0, %al
callq 0x24fb0
movq -0x128(%rbp), %rdi
callq 0x2c160
jmp 0x41da8
movq -0x128(%rbp), %rdi
callq 0x2c160
leaq 0xd1e27(%rip), %rax     # 0x1138f8
movslq 0x88(%rax), %rdi
callq 0x2c910
movq %rax, -0x548(%rbp)
movl -0xc(%rbp), %edi
movq -0x548(%rbp), %rcx
leaq 0x9cda7(%rip), %rsi     # 0xde89c
leaq 0xa0202(%rip), %rdx     # 0xe1cfe
xorl %eax, %eax
movl %eax, %r8d
movb $0x0, %al
callq 0x41030
movq %rax, -0x128(%rbp)
movq -0x548(%rbp), %rdi
callq 0x2c160
movq -0x128(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x2d, %eax
jne 0x41b44
movq -0x128(%rbp), %rdx
movl $0x2, %edi
leaq 0xa09be(%rip), %rsi     # 0xe24fb
movb $0x0, %al
callq 0x24fb0
movq -0x128(%rbp), %rdi
callq 0x2c160
movl -0xc(%rbp), %edi
callq 0x412b0
movl %eax, -0x138(%rbp)
cmpl $0x0, -0x138(%rbp)
jne 0x41b7f
movl $0x2, %edi
leaq 0xa09ce(%rip), %rsi     # 0xe2541
movb $0x0, %al
callq 0x24fb0
jmp 0x41dd2
cmpl $0x2, -0x138(%rbp)
jne 0x41bf2
movl $0x2, %edi
leaq 0xa09f1(%rip), %rsi     # 0xe2585
movb $0x0, %al
callq 0x24fb0
movl -0xc(%rbp), %edi
leaq 0xd1d53(%rip), %rax     # 0x1138f8
imull $0x3e8, 0x670(%rax), %eax # imm = 0x3E8
movslq %eax, %rcx
leaq 0xa09e2(%rip), %rsi     # 0xe259b
movl $0x6, %edx
callq 0x67bb0
cmpq $-0x1, %rax
jne 0x41bf0
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0xa09be(%rip), %rsi     # 0xe25a2
movb $0x0, %al
callq 0x24fb0
jmp 0x41da8
jmp 0x41bf2
jmp 0x41bf4
movl -0x130(%rbp), %eax
movl %eax, %ecx
addl $-0x1, %ecx
movl %ecx, -0x130(%rbp)
cmpl $0x0, %eax
je 0x41c90
leaq -0x120(%rbp), %rax
movq %rax, -0x558(%rbp)
leaq 0xd1cd5(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
movl %eax, -0x54c(%rbp)
callq 0x1f410
movq -0x558(%rbp), %rdi
movl -0x54c(%rbp), %ecx
movslq %eax, %r8
movl $0x100, %esi            # imm = 0x100
leaq 0xa0971(%rip), %rdx     # 0xe25c2
movb $0x0, %al
callq 0x1f120
leaq -0x120(%rbp), %rdi
movl $0xc1, %esi
movl $0x1a4, %edx            # imm = 0x1A4
movb $0x0, %al
callq 0x1f640
movl %eax, -0x12c(%rbp)
cmpl $-0x1, -0x12c(%rbp)
je 0x41c81
jmp 0x41c90
movl $0x1, %edi
callq 0x1f5c0
jmp 0x41bf4
cmpl $-0x1, -0x12c(%rbp)
jne 0x41cc0
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0xa091e(%rip), %rsi     # 0xe25d2
movb $0x0, %al
callq 0x24fb0
jmp 0x41da8
leaq 0xd1c31(%rip), %rax     # 0x1138f8
movq 0x28(%rax), %rdi
movl -0xc(%rbp), %esi
movl $0x1, %edx
leaq -0x12ea(%rip), %rcx     # 0x409f0
xorl %eax, %eax
movl %eax, %r8d
callq 0x20a80
cmpl $-0x1, %eax
jne 0x41d13
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl -0xc(%rbp), %ecx
movl $0x3, %edi
leaq 0xa0911(%rip), %rsi     # 0xe2618
movb $0x0, %al
callq 0x24fb0
jmp 0x41da8
leaq 0xd1bde(%rip), %rax     # 0x1138f8
movl $0x4, 0x674(%rax)
leaq 0xd1bcd(%rip), %rax     # 0x1138f8
movq $-0x1, 0x678(%rax)
leaq 0xd1bbb(%rip), %rax     # 0x1138f8
movq $0x0, 0x680(%rax)
leaq 0xd1ba9(%rip), %rax     # 0x1138f8
movq $0x0, 0x688(%rax)
movl -0x12c(%rbp), %ecx
leaq 0xd1b91(%rip), %rax     # 0x1138f8
movl %ecx, 0x694(%rax)
leaq 0xd1b84(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rcx
leaq 0xd1b76(%rip), %rax     # 0x1138f8
movq %rcx, 0x6a0(%rax)
leaq -0x120(%rbp), %rdi
callq 0x2e430
movq %rax, %rcx
leaq 0xd1b59(%rip), %rax     # 0x1138f8
movq %rcx, 0x698(%rax)
jmp 0x41dd2
movl -0xc(%rbp), %edi
callq 0x1f170
leaq 0xd1b41(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x690(%rax) # imm = 0xFFFFFFFF
leaq 0xd1b30(%rip), %rax     # 0x1138f8
movl $0x1, 0x674(%rax)
addq $0x560, %rsp            # imm = 0x560
popq %rbp
retq
nopl (%rax,%rax)