// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/aof.c
// Function: flushAppendOnlyFile
void flushAppendOnlyFile(int force) {
    ssize_t nwritten;
    int sync_in_progress = 0;

    // 缓冲区中没有任何内容，直接返回
    if (sdslen(server.aof_buf) == 0) return;

    // 策略为每秒 FSYNC 
    if (server.aof_fsync == AOF_FSYNC_EVERYSEC)
        // 是否有 SYNC 正在后台进行？
        sync_in_progress = bioPendingJobsOfType(REDIS_BIO_AOF_FSYNC) != 0;

    // 每秒 fsync ，并且强制写入为假
    if (server.aof_fsync == AOF_FSYNC_EVERYSEC && !force) {

        /* With this append fsync policy we do background fsyncing.
         *
         * 当 fsync 策略为每秒钟一次时， fsync 在后台执行。
         *
         * If the fsync is still in progress we can try to delay
         * the write for a couple of seconds. 
         *
         * 如果后台仍在执行 FSYNC ，那么我们可以延迟写操作一两秒
         * （如果强制执行 write 的话，服务器主线程将阻塞在 write 上面）
         */
        if (sync_in_progress) {

            // 有 fsync 正在后台进行 。。。

            if (server.aof_flush_postponed_start == 0) {
                /* No previous write postponinig, remember that we are
                 * postponing the flush and return. 
                 *
                 * 前面没有推迟过 write 操作，这里将推迟写操作的时间记录下来
                 * 然后就返回，不执行 write 或者 fsync
                 */
                server.aof_flush_postponed_start = server.unixtime;
                return;

            } else if (server.unixtime - server.aof_flush_postponed_start < 2) {
                /* We were already waiting for fsync to finish, but for less
                 * than two seconds this is still ok. Postpone again. 
                 *
                 * 如果之前已经因为 fsync 而推迟了 write 操作
                 * 但是推迟的时间不超过 2 秒，那么直接返回
                 * 不执行 write 或者 fsync
                 */
                return;

            }

            /* Otherwise fall trough, and go write since we can't wait
             * over two seconds. 
             *
             * 如果后台还有 fsync 在执行，并且 write 已经推迟 >= 2 秒
             * 那么执行写操作（write 将被阻塞）
             */
            server.aof_delayed_fsync++;
            redisLog(REDIS_NOTICE,"Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.");
        }
    }

    /* If you are following this code path, then we are going to write so
     * set reset the postponed flush sentinel to zero. 
     *
     * 执行到这里，程序会对 AOF 文件进行写入。
     *
     * 清零延迟 write 的时间记录
     */
    server.aof_flush_postponed_start = 0;

    /* We want to perform a single write. This should be guaranteed atomic
     * at least if the filesystem we are writing is a real physical one.
     *
     * 执行单个 write 操作，如果写入设备是物理的话，那么这个操作应该是原子的
     *
     * While this will save us against the server being killed I don't think
     * there is much to do about the whole server stopping for power problems
     * or alike 
     *
     * 当然，如果出现像电源中断这样的不可抗现象，那么 AOF 文件也是可能会出现问题的
     * 这时就要用 redis-check-aof 程序来进行修复。
     */
    nwritten = write(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));
    if (nwritten != (signed)sdslen(server.aof_buf)) {

        static time_t last_write_error_log = 0;
        int can_log = 0;

        /* Limit logging rate to 1 line per AOF_WRITE_LOG_ERROR_RATE seconds. */
        // 将日志的记录频率限制在每行 AOF_WRITE_LOG_ERROR_RATE 秒
        if ((server.unixtime - last_write_error_log) > AOF_WRITE_LOG_ERROR_RATE) {
            can_log = 1;
            last_write_error_log = server.unixtime;
        }

        /* Lof the AOF write error and record the error code. */
        // 如果写入出错，那么尝试将该情况写入到日志里面
        if (nwritten == -1) {
            if (can_log) {
                redisLog(REDIS_WARNING,"Error writing to the AOF file: %s",
                    strerror(errno));
                server.aof_last_write_errno = errno;
            }
        } else {
            if (can_log) {
                redisLog(REDIS_WARNING,"Short write while writing to "
                                       "the AOF file: (nwritten=%lld, "
                                       "expected=%lld)",
                                       (long long)nwritten,
                                       (long long)sdslen(server.aof_buf));
            }

            // 尝试移除新追加的不完整内容
            if (ftruncate(server.aof_fd, server.aof_current_size) == -1) {
                if (can_log) {
                    redisLog(REDIS_WARNING, "Could not remove short write "
                             "from the append-only file.  Redis may refuse "
                             "to load the AOF the next time it starts.  "
                             "ftruncate: %s", strerror(errno));
                }
            } else {
                /* If the ftrunacate() succeeded we can set nwritten to
                 * -1 since there is no longer partial data into the AOF. */
                nwritten = -1;
            }
            server.aof_last_write_errno = ENOSPC;
        }

        /* Handle the AOF write error. */
        // 处理写入 AOF 文件时出现的错误
        if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
            /* We can't recover when the fsync policy is ALWAYS since the
             * reply for the client is already in the output buffers, and we
             * have the contract with the user that on acknowledged write data
             * is synched on disk. */
            redisLog(REDIS_WARNING,"Can't recover from AOF write error when the AOF fsync policy is 'always'. Exiting...");
            exit(1);
        } else {
            /* Recover from failed write leaving data into the buffer. However
             * set an error to stop accepting writes as long as the error
             * condition is not cleared. */
            server.aof_last_write_status = REDIS_ERR;

            /* Trim the sds buffer if there was a partial write, and there
             * was no way to undo it with ftruncate(2). */
            if (nwritten > 0) {
                server.aof_current_size += nwritten;
                sdsrange(server.aof_buf,nwritten,-1);
            }
            return; /* We'll try again on the next call... */
        }
    } else {
        /* Successful write(2). If AOF was in error state, restore the
         * OK state and log the event. */
        // 写入成功，更新最后写入状态
        if (server.aof_last_write_status == REDIS_ERR) {
            redisLog(REDIS_WARNING,
                "AOF write error looks solved, Redis can write again.");
            server.aof_last_write_status = REDIS_OK;
        }
    }

    // 更新写入后的 AOF 文件大小
    server.aof_current_size += nwritten;

    /* Re-use AOF buffer when it is small enough. The maximum comes from the
     * arena size of 4k minus some overhead (but is otherwise arbitrary). 
     *
     * 如果 AOF 缓存的大小足够小的话，那么重用这个缓存，
     * 否则的话，释放 AOF 缓存。
     */
    if ((sdslen(server.aof_buf)+sdsavail(server.aof_buf)) < 4000) {
        // 清空缓存中的内容，等待重用
        sdsclear(server.aof_buf);
    } else {
        // 释放缓存
        sdsfree(server.aof_buf);
        server.aof_buf = sdsempty();
    }

    /* Don't fsync if no-appendfsync-on-rewrite is set to yes and there are
     * children doing I/O in the background. 
     *
     * 如果 no-appendfsync-on-rewrite 选项为开启状态，
     * 并且有 BGSAVE 或者 BGREWRITEAOF 正在进行的话，
     * 那么不执行 fsync 
     */
    if (server.aof_no_fsync_on_rewrite &&
        (server.aof_child_pid != -1 || server.rdb_child_pid != -1))
            return;

    /* Perform the fsync if needed. */

    // 总是执行 fsnyc
    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
        /* aof_fsync is defined as fdatasync() for Linux in order to avoid
         * flushing metadata. */
        aof_fsync(server.aof_fd); /* Let's try to get this data on the disk */

        // 更新最后一次执行 fsnyc 的时间
        server.aof_last_fsync = server.unixtime;

    // 策略为每秒 fsnyc ，并且距离上次 fsync 已经超过 1 秒
    } else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&
                server.unixtime > server.aof_last_fsync)) {
        // 放到后台执行
        if (!sync_in_progress) aof_background_fsync(server.aof_fd);
        // 更新最后一次执行 fsync 的时间
        server.aof_last_fsync = server.unixtime;
    }

    // 其实上面无论执行 if 部分还是 else 部分都要更新 fsync 的时间
    // 可以将代码挪到下面来
    // server.aof_last_fsync = server.unixtime;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movl %edi, -0x4(%rbp)
movl $0x0, -0x14(%rbp)
leaq 0xb4caf(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x5e720
cmpq $0x0, %rax
jne 0x5ec60
jmp 0x5f123
leaq 0xb4c91(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x4d4(%rax)
jne 0x5ec89
movl $0x1, %edi
callq 0x75c20
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x14(%rbp)
leaq 0xb4c68(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x4d4(%rax)
jne 0x5ed41
cmpl $0x0, -0x4(%rbp)
jne 0x5ed41
cmpl $0x0, -0x14(%rbp)
je 0x5ed3f
leaq 0xb4c40(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x520(%rax)
jne 0x5ece3
leaq 0xb4c2f(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rcx
leaq 0xb4c21(%rip), %rax     # 0x1138f8
movq %rcx, 0x520(%rax)
jmp 0x5f123
leaq 0xb4c0e(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
leaq 0xb4c00(%rip), %rcx     # 0x1138f8
subq 0x520(%rcx), %rax
cmpq $0x2, %rax
jge 0x5ed0a
jmp 0x5f123
jmp 0x5ed0c
leaq 0xb4be5(%rip), %rax     # 0x1138f8
movq 0x548(%rax), %rcx
addq $0x1, %rcx
leaq 0xb4bd3(%rip), %rax     # 0x1138f8
movq %rcx, 0x548(%rax)
movl $0x2, %edi
leaq 0x85aba(%rip), %rsi     # 0xe47f2
movb $0x0, %al
callq 0x24fb0
jmp 0x5ed41
leaq 0xb4bb0(%rip), %rax     # 0x1138f8
movq $0x0, 0x520(%rax)
leaq 0xb4b9e(%rip), %rax     # 0x1138f8
movl 0x518(%rax), %eax
movl %eax, -0x2c(%rbp)
leaq 0xb4b8e(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rax
movq %rax, -0x28(%rbp)
leaq 0xb4b7c(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x5e720
movl -0x2c(%rbp), %edi
movq -0x28(%rbp), %rsi
movq %rax, %rdx
callq 0x1fb50
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x20(%rbp)
leaq 0xb4b4e(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x5e720
movq %rax, %rcx
movq -0x20(%rbp), %rax
movslq %ecx, %rcx
cmpq %rcx, %rax
je 0x5ef7a
movl $0x0, -0x18(%rbp)
leaq 0xb4b21(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
subq 0xc918b(%rip), %rax     # 0x127f70
cmpq $0x1e, %rax
jle 0x5ee07
movl $0x1, -0x18(%rbp)
leaq 0xb4aff(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
movq %rax, 0xc9169(%rip)     # 0x127f70
cmpq $-0x1, -0x10(%rbp)
jne 0x5ee4f
cmpl $0x0, -0x18(%rbp)
je 0x5ee4a
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0x85a56(%rip), %rsi     # 0xe4885
movb $0x0, %al
callq 0x24fb0
callq 0x1f820
movl (%rax), %ecx
leaq 0xb4ab4(%rip), %rax     # 0x1138f8
movl %ecx, 0x558(%rax)
jmp 0x5eef2
cmpl $0x0, -0x18(%rbp)
je 0x5ee8a
movq -0x10(%rbp), %rax
movq %rax, -0x38(%rbp)
leaq 0xb4a94(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x5e720
movq -0x38(%rbp), %rdx
movq %rax, %rcx
movl $0x3, %edi
leaq 0x85a24(%rip), %rsi     # 0xe48a7
movb $0x0, %al
callq 0x24fb0
leaq 0xb4a67(%rip), %rax     # 0x1138f8
movl 0x518(%rax), %edi
leaq 0xb4a5a(%rip), %rax     # 0x1138f8
movq 0x4f8(%rax), %rsi
callq 0x1f6d0
cmpl $-0x1, %eax
jne 0x5eed9
cmpl $0x0, -0x18(%rbp)
je 0x5eed7
callq 0x1f820
movl (%rax), %edi
callq 0x1f630
movq %rax, %rdx
movl $0x3, %edi
leaq 0x85a21(%rip), %rsi     # 0xe48f1
movb $0x0, %al
callq 0x24fb0
jmp 0x5eee1
movq $-0x1, -0x10(%rbp)
leaq 0xb4a10(%rip), %rax     # 0x1138f8
movl $0x1c, 0x558(%rax)
leaq 0xb49ff(%rip), %rax     # 0x1138f8
cmpl $0x1, 0x4d4(%rax)
jne 0x5ef1f
movl $0x3, %edi
leaq 0x85a65(%rip), %rsi     # 0xe4973
movb $0x0, %al
callq 0x24fb0
movl $0x1, %edi
callq 0x1f2c0
leaq 0xb49d2(%rip), %rax     # 0x1138f8
movl $0xffffffff, 0x554(%rax) # imm = 0xFFFFFFFF
cmpq $0x0, -0x10(%rbp)
jle 0x5ef75
movq -0x10(%rbp), %rcx
leaq 0xb49b6(%rip), %rax     # 0x1138f8
addq 0x4f8(%rax), %rcx
leaq 0xb49a8(%rip), %rax     # 0x1138f8
movq %rcx, 0x4f8(%rax)
leaq 0xb499a(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
movq -0x10(%rbp), %rax
movl %eax, %esi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x2d2e0
jmp 0x5f123
leaq 0xb4977(%rip), %rax     # 0x1138f8
cmpl $-0x1, 0x554(%rax)
jne 0x5efae
movl $0x3, %edi
leaq 0x85a32(%rip), %rsi     # 0xe49c8
movb $0x0, %al
callq 0x24fb0
leaq 0xb4954(%rip), %rax     # 0x1138f8
movl $0x0, 0x554(%rax)
jmp 0x5efb0
movq -0x10(%rbp), %rcx
leaq 0xb493d(%rip), %rax     # 0x1138f8
addq 0x4f8(%rax), %rcx
leaq 0xb492f(%rip), %rax     # 0x1138f8
movq %rcx, 0x4f8(%rax)
leaq 0xb4921(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x5e720
movq %rax, -0x40(%rbp)
leaq 0xb490a(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x5e740
movq %rax, %rcx
movq -0x40(%rbp), %rax
addq %rcx, %rax
cmpq $0xfa0, %rax            # imm = 0xFA0
jae 0x5f021
leaq 0xb48e5(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x2c1e0
jmp 0x5f04a
leaq 0xb48d0(%rip), %rax     # 0x1138f8
movq 0x510(%rax), %rdi
callq 0x2c160
callq 0x2c0c0
movq %rax, %rcx
leaq 0xb48b5(%rip), %rax     # 0x1138f8
movq %rcx, 0x510(%rax)
leaq 0xb48a7(%rip), %rax     # 0x1138f8
cmpl $0x0, 0x4e0(%rax)
je 0x5f07f
leaq 0xb4897(%rip), %rax     # 0x1138f8
cmpl $-0x1, 0x504(%rax)
jne 0x5f07a
leaq 0xb4887(%rip), %rax     # 0x1138f8
cmpl $-0x1, 0x570(%rax)
je 0x5f07f
jmp 0x5f123
leaq 0xb4872(%rip), %rax     # 0x1138f8
cmpl $0x1, 0x4d4(%rax)
jne 0x5f0bf
leaq 0xb4862(%rip), %rax     # 0x1138f8
movl 0x518(%rax), %edi
callq 0x1f540
leaq 0xb4850(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rcx
leaq 0xb4842(%rip), %rax     # 0x1138f8
movq %rcx, 0x528(%rax)
jmp 0x5f123
leaq 0xb4832(%rip), %rax     # 0x1138f8
cmpl $0x2, 0x4d4(%rax)
jne 0x5f121
leaq 0xb4822(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rax
leaq 0xb4814(%rip), %rcx     # 0x1138f8
cmpq 0x528(%rcx), %rax
jle 0x5f121
cmpl $0x0, -0x14(%rbp)
jne 0x5f105
leaq 0xb47fe(%rip), %rax     # 0x1138f8
movl 0x518(%rax), %edi
callq 0x5eac0
leaq 0xb47ec(%rip), %rax     # 0x1138f8
movq 0x798(%rax), %rcx
leaq 0xb47de(%rip), %rax     # 0x1138f8
movq %rcx, 0x528(%rax)
jmp 0x5f123
addq $0x40, %rsp
popq %rbp
retq
nopl (%rax)