// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/aof.c
// Function: backgroundRewriteDoneHandler
void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
    if (!bysignal && exitcode == 0) {
        int newfd, oldfd;
        char tmpfile[256];
        long long now = ustime();

        redisLog(REDIS_NOTICE,
            "Background AOF rewrite terminated with success");

        /* Flush the differences accumulated by the parent to the
         * rewritten AOF. */
        // 打开保存新 AOF 文件内容的临时文件
        snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof",
            (int)server.aof_child_pid);
        newfd = open(tmpfile,O_WRONLY|O_APPEND);
        if (newfd == -1) {
            redisLog(REDIS_WARNING,
                "Unable to open the temporary AOF produced by the child: %s", strerror(errno));
            goto cleanup;
        }

        // 将累积的重写缓存写入到临时文件中
        // 这个函数调用的 write 操作会阻塞主进程
        if (aofRewriteBufferWrite(newfd) == -1) {
            redisLog(REDIS_WARNING,
                "Error trying to flush the parent diff to the rewritten AOF: %s", strerror(errno));
            close(newfd);
            goto cleanup;
        }

        redisLog(REDIS_NOTICE,
            "Parent diff successfully flushed to the rewritten AOF (%lu bytes)", aofRewriteBufferSize());

        /* The only remaining thing to do is to rename the temporary file to
         * the configured file and switch the file descriptor used to do AOF
         * writes. We don't want close(2) or rename(2) calls to block the
         * server on old file deletion.
         *
         * 剩下的工作就是将临时文件改名为 AOF 程序指定的文件名，
         * 并将新文件的 fd 设为 AOF 程序的写目标。
         *
         * 不过这里有一个问题 ——
         * 我们不想 close(2) 或者 rename(2) 在删除旧文件时阻塞。
         *
         * There are two possible scenarios:
         *
         * 以下是两个可能的场景：
         *
         * 1) AOF is DISABLED and this was a one time rewrite. The temporary
         * file will be renamed to the configured file. When this file already
         * exists, it will be unlinked, which may block the server.
         *
         * AOF 被关闭，这个是一次单次的写操作。
         * 临时文件会被改名为 AOF 文件。
         * 本来已经存在的 AOF 文件会被 unlink ，这可能会阻塞服务器。
         *
         * 2) AOF is ENABLED and the rewritten AOF will immediately start
         * receiving writes. After the temporary file is renamed to the
         * configured file, the original AOF file descriptor will be closed.
         * Since this will be the last reference to that file, closing it
         * causes the underlying file to be unlinked, which may block the
         * server.
         *
         * AOF 被开启，并且重写后的 AOF 文件会立即被用于接收新的写入命令。
         * 当临时文件被改名为 AOF 文件时，原来的 AOF 文件描述符会被关闭。
         * 因为 Redis 会是最后一个引用这个文件的进程，
         * 所以关闭这个文件会引起 unlink ，这可能会阻塞服务器。
         *
         * To mitigate the blocking effect of the unlink operation (either
         * caused by rename(2) in scenario 1, or by close(2) in scenario 2), we
         * use a background thread to take care of this. First, we
         * make scenario 1 identical to scenario 2 by opening the target file
         * when it exists. The unlink operation after the rename(2) will then
         * be executed upon calling close(2) for its descriptor. Everything to
         * guarantee atomicity for this switch has already happened by then, so
         * we don't care what the outcome or duration of that close operation
         * is, as long as the file descriptor is released again. 
         *
         * 为了避免出现阻塞现象，程序会将 close(2) 放到后台线程执行，
         * 这样服务器就可以持续处理请求，不会被中断。
         */
        if (server.aof_fd == -1) {
            /* AOF disabled */

             /* Don't care if this fails: oldfd will be -1 and we handle that.
              * One notable case of -1 return is if the old file does
              * not exist. */
             oldfd = open(server.aof_filename,O_RDONLY|O_NONBLOCK);
        } else {
            /* AOF enabled */
            oldfd = -1; /* We'll set this to the current AOF filedes later. */
        }

        /* Rename the temporary file. This will not unlink the target file if
         * it exists, because we reference it with "oldfd". 
         *
         * 对临时文件进行改名，替换现有的 AOF 文件。
         *
         * 旧的 AOF 文件不会在这里被 unlink ，因为 oldfd 引用了它。
         */
        if (rename(tmpfile,server.aof_filename) == -1) {
            redisLog(REDIS_WARNING,
                "Error trying to rename the temporary AOF file: %s", strerror(errno));
            close(newfd);
            if (oldfd != -1) close(oldfd);
            goto cleanup;
        }

        if (server.aof_fd == -1) {
            /* AOF disabled, we don't need to set the AOF file descriptor
             * to this new file, so we can close it. 
             *
             * AOF 被关闭，直接关闭 AOF 文件，
             * 因为关闭 AOF 本来就会引起阻塞，所以这里就算 close 被阻塞也无所谓
             */
            close(newfd);
        } else {
            /* AOF enabled, replace the old fd with the new one. 
             *
             * 用新 AOF 文件的 fd 替换原来 AOF 文件的 fd
             */
            oldfd = server.aof_fd;
            server.aof_fd = newfd;

            // 因为前面进行了 AOF 重写缓存追加，所以这里立即 fsync 一次
            if (server.aof_fsync == AOF_FSYNC_ALWAYS)
                aof_fsync(newfd);
            else if (server.aof_fsync == AOF_FSYNC_EVERYSEC)
                aof_background_fsync(newfd);

            // 强制引发 SELECT
            server.aof_selected_db = -1; /* Make sure SELECT is re-issued */

            // 更新 AOF 文件的大小
            aofUpdateCurrentSize();

            // 记录前一次重写时的大小
            server.aof_rewrite_base_size = server.aof_current_size;

            /* Clear regular AOF buffer since its contents was just written to
             * the new AOF from the background rewrite buffer. 
             *
             * 清空 AOF 缓存，因为它的内容已经被写入过了，没用了
             */
            sdsfree(server.aof_buf);
            server.aof_buf = sdsempty();
        }

        server.aof_lastbgrewrite_status = REDIS_OK;

        redisLog(REDIS_NOTICE, "Background AOF rewrite finished successfully");

        /* Change state from WAIT_REWRITE to ON if needed 
         *
         * 如果是第一次创建 AOF 文件，那么更新 AOF 状态
         */
        if (server.aof_state == REDIS_AOF_WAIT_REWRITE)
            server.aof_state = REDIS_AOF_ON;

        /* Asynchronously close the overwritten AOF. 
         *
         * 异步关闭旧 AOF 文件
         */
        if (oldfd != -1) bioCreateBackgroundJob(REDIS_BIO_CLOSE_FILE,(void*)(long)oldfd,NULL,NULL);

        redisLog(REDIS_VERBOSE,
            "Background AOF rewrite signal handler took %lldus", ustime()-now);

    // BGREWRITEAOF 重写出错
    } else if (!bysignal && exitcode != 0) {
        server.aof_lastbgrewrite_status = REDIS_ERR;

        redisLog(REDIS_WARNING,
            "Background AOF rewrite terminated with error");

    // 未知错误
    } else {
        server.aof_lastbgrewrite_status = REDIS_ERR;

        redisLog(REDIS_WARNING,
            "Background AOF rewrite terminated by signal %d", bysignal);
    }

cleanup:

    // 清空 AOF 缓冲区
    aofRewriteBufferReset();

    // 移除临时文件
    aofRemoveTempFile(server.aof_child_pid);

    // 重置默认属性
    server.aof_child_pid = -1;
    server.aof_rewrite_time_last = time(NULL)-server.aof_rewrite_time_start;
    server.aof_rewrite_time_start = -1;

    /* Schedule a new rewrite if we are waiting for it to switch the AOF ON. */
    if (server.aof_state == REDIS_AOF_WAIT_REWRITE)
        server.aof_rewrite_scheduled = 1;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movl %edi, -0x4(%rbp)
movl %esi, -0x8(%rbp)
cmpl $0x0, -0x8(%rbp)
jne 0x61775
cmpl $0x0, -0x4(%rbp)
jne 0x61775
callq 0x252a0
movq %rax, -0x118(%rbp)
movl $0x2, %edi
leaq 0x839f7(%rip), %rsi     # 0xe4ec4
movb $0x0, %al
callq 0x24fb0
leaq -0x110(%rbp), %rdi
leaq 0xb2416(%rip), %rax     # 0x1138f8
movl 0x504(%rax), %ecx
movl $0x100, %esi            # imm = 0x100
leaq 0x8384c(%rip), %rdx     # 0xe4d40
movb $0x0, %al
callq 0x1f120
leaq -0x110(%rbp), %rdi
movl $0x401, %esi            # imm = 0x401
movb $0x0, %al
callq 0x1f640
movl %eax, -0xc(%rbp)
cmpl $-0x1, -0xc(%rbp)
jne 0x6153e
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0x839c1(%rip), %rsi     # 0xe4ef3
movb $0x0, %al
callq 0x24fb0
jmp 0x617d2
movl -0xc(%rbp), %edi
callq 0x5ea00
cmpq $-0x1, %rax
jne 0x6157b
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0x839c7(%rip), %rsi     # 0xe4f2e
movb $0x0, %al
callq 0x24fb0
movl -0xc(%rbp), %edi
callq 0x1f170
jmp 0x617d2
callq 0x5e7c0
movq %rax, %rdx
movl $0x2, %edi
leaq 0x839de(%rip), %rsi     # 0xe4f6d
movb $0x0, %al
callq 0x24fb0
leaq 0xb235b(%rip), %rax     # 0x1138f8
cmpl $-0x1, 0x518(%rax)
jne 0x615c5
leaq 0xb234b(%rip), %rax     # 0x1138f8
movq 0x4d8(%rax), %rdi
movl $0x800, %esi            # imm = 0x800
movb $0x0, %al
callq 0x1f640
movl %eax, -0x10(%rbp)
jmp 0x615cc
movl $0xffffffff, -0x10(%rbp) # imm = 0xFFFFFFFF
leaq -0x110(%rbp), %rdi
leaq 0xb231e(%rip), %rax     # 0x1138f8
movq 0x4d8(%rax), %rsi
callq 0x1fc40
cmpl $-0x1, %eax
jne 0x61628
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0x839a9(%rip), %rsi     # 0xe4faf
movb $0x0, %al
callq 0x24fb0
movl -0xc(%rbp), %edi
callq 0x1f170
cmpl $-0x1, -0x10(%rbp)
je 0x61623
movl -0x10(%rbp), %edi
callq 0x1f170
jmp 0x617d2
leaq 0xb22c9(%rip), %rax     # 0x1138f8
cmpl $-0x1, 0x518(%rax)
jne 0x61645
movl -0xc(%rbp), %edi
callq 0x1f170
jmp 0x616f4
leaq 0xb22ac(%rip), %rax     # 0x1138f8
movl 0x518(%rax), %eax
movl %eax, -0x10(%rbp)
movl -0xc(%rbp), %ecx
leaq 0xb2299(%rip), %rax     # 0x1138f8
movl %ecx, 0x518(%rax)
leaq 0xb228c(%rip), %rax     # 0x1138f8
cmpl $0x1, 0x4d4(%rax)
jne 0x6167f
movl -0xc(%rbp), %edi
callq 0x1f540
jmp 0x61699
leaq 0xb2272(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x4d4(%rax)
jne 0x61697
movl -0xc(%rbp), %edi
callq 0x5eac0
jmp 0x61699
leaq 0xb2258(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x51c(%rax) # imm = 0xFFFFFFFF
callq 0x5ffa0
leaq 0xb2242(%rip), %rax     # 0x1138f8
movq 0x4f8(%rax), %rcx
leaq 0xb2234(%rip), %rax     # 0x1138f8
movq %rcx, 0x4f0(%rax)
leaq 0xb2226(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x2c160
callq 0x2c0c0
movq %rax, %rcx
leaq 0xb220b(%rip), %rax     # 0x1138f8
movq %rcx, 0x510(%rax)
leaq 0xb21fd(%rip), %rax     # 0x1138f8
movl $0x0, 0x540(%rax)
movl $0x2, %edi
leaq 0x838d0(%rip), %rsi     # 0xe4fe1
movb $0x0, %al
callq 0x24fb0
leaq 0xb21d9(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x4d0(%rax)
jne 0x61739
leaq 0xb21c9(%rip), %rax     # 0x1138f8
movl $0x1, 0x4d0(%rax)
cmpl $-0x1, -0x10(%rbp)
je 0x61751
movslq -0x10(%rbp), %rsi
xorl %edi, %edi
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rdx
callq 0x75b40
callq 0x252a0
movq %rax, %rdx
subq -0x118(%rbp), %rdx
movl $0x1, %edi
leaq 0x838a2(%rip), %rsi     # 0xe500e
movb $0x0, %al
callq 0x24fb0
jmp 0x617d0
cmpl $0x0, -0x8(%rbp)
jne 0x617a7
cmpl $0x0, -0x4(%rbp)
je 0x617a7
leaq 0xb2170(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x540(%rax) # imm = 0xFFFFFFFF
movl $0x3, %edi
leaq 0x838a2(%rip), %rsi     # 0xe5040
movb $0x0, %al
callq 0x24fb0
jmp 0x617ce
leaq 0xb214a(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x540(%rax) # imm = 0xFFFFFFFF
movl -0x8(%rbp), %edx
movl $0x3, %edi
leaq 0x838a6(%rip), %rsi     # 0xe506d
movb $0x0, %al
callq 0x24fb0
jmp 0x617d0
jmp 0x617d2
callq 0x5e760
leaq 0xb211a(%rip), %rax     # 0x1138f8
movl 0x504(%rax), %edi
callq 0x5f130
leaq 0xb2108(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x504(%rax) # imm = 0xFFFFFFFF
xorl %eax, %eax
movl %eax, %edi
callq 0x1fc70
movq %rax, %rcx
leaq 0xb20eb(%rip), %rax     # 0x1138f8
subq 0x538(%rax), %rcx
leaq 0xb20dd(%rip), %rax     # 0x1138f8
movq %rcx, 0x530(%rax)
leaq 0xb20cf(%rip), %rax     # 0x1138f8
movq $-0x1, 0x538(%rax)
leaq 0xb20bd(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x4d0(%rax)
jne 0x61855
leaq 0xb20ad(%rip), %rax     # 0x1138f8
movl $0x1, 0x500(%rax)
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
nop