// File: /workspace/github_c_makefile_star2_O1/nilyang[P]redis-tdd-annotation/src/aof.c
// Function: rewriteAppendOnlyFile
int rewriteAppendOnlyFile(char *filename) {
    dictIterator *di = NULL;
    dictEntry *de;
    rio aof;
    FILE *fp;
    char tmpfile[256];
    int j;
    long long now = mstime();

    /* Note that we have to use a different temp name here compared to the
     * one used by rewriteAppendOnlyFileBackground() function. 
     *
     * 创建临时文件
     *
     * 注意这里创建的文件名和 rewriteAppendOnlyFileBackground() 创建的文件名稍有不同
     */
    snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
    fp = fopen(tmpfile,"w");
    if (!fp) {
        redisLog(REDIS_WARNING, "Opening the temp file for AOF rewrite in rewriteAppendOnlyFile(): %s", strerror(errno));
        return REDIS_ERR;
    }

    // 初始化文件 io
    rioInitWithFile(&aof,fp);

    // 设置每写入 REDIS_AOF_AUTOSYNC_BYTES 字节
    // 就执行一次 FSYNC 
    // 防止缓存中积累太多命令内容，造成 I/O 阻塞时间过长
    if (server.aof_rewrite_incremental_fsync)
        rioSetAutoSync(&aof,REDIS_AOF_AUTOSYNC_BYTES);

    // 遍历所有数据库
    for (j = 0; j < server.dbnum; j++) {

        char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";

        redisDb *db = server.db+j;

        // 指向键空间
        dict *d = db->dict;
        if (dictSize(d) == 0) continue;

        // 创建键空间迭代器
        di = dictGetSafeIterator(d);
        if (!di) {
            fclose(fp);
            return REDIS_ERR;
        }

        /* SELECT the new DB 
         *
         * 首先写入 SELECT 命令，确保之后的数据会被插入到正确的数据库上
         */
        if (rioWrite(&aof,selectcmd,sizeof(selectcmd)-1) == 0) goto werr;
        if (rioWriteBulkLongLong(&aof,j) == 0) goto werr;

        /* Iterate this DB writing every entry 
         *
         * 遍历数据库所有键，并通过命令将它们的当前状态（值）记录到新 AOF 文件中
         */
        while((de = dictNext(di)) != NULL) {
            sds keystr;
            robj key, *o;
            long long expiretime;

            // 取出键
            keystr = dictGetKey(de);

            // 取出值
            o = dictGetVal(de);
            initStaticStringObject(key,keystr);

            // 取出过期时间
            expiretime = getExpire(db,&key);

            /* If this key is already expired skip it 
             *
             * 如果键已经过期，那么跳过它，不保存
             */
            if (expiretime != -1 && expiretime < now) continue;

            /* Save the key and associated value 
             *
             * 根据值的类型，选择适当的命令来保存值
             */
            if (o->type == REDIS_STRING) {
                /* Emit a SET command */
                char cmd[]="*3\r\n$3\r\nSET\r\n";
                if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr;
                /* Key and value */
                if (rioWriteBulkObject(&aof,&key) == 0) goto werr;
                if (rioWriteBulkObject(&aof,o) == 0) goto werr;
            } else if (o->type == REDIS_LIST) {
                if (rewriteListObject(&aof,&key,o) == 0) goto werr;
            } else if (o->type == REDIS_SET) {
                if (rewriteSetObject(&aof,&key,o) == 0) goto werr;
            } else if (o->type == REDIS_ZSET) {
                if (rewriteSortedSetObject(&aof,&key,o) == 0) goto werr;
            } else if (o->type == REDIS_HASH) {
                if (rewriteHashObject(&aof,&key,o) == 0) goto werr;
            } else {
                redisPanic("Unknown object type");
            }

            /* Save the expire time 
             *
             * 保存键的过期时间
             */
            if (expiretime != -1) {
                char cmd[]="*3\r\n$9\r\nPEXPIREAT\r\n";

                // 写入 PEXPIREAT expiretime 命令
                if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr;
                if (rioWriteBulkObject(&aof,&key) == 0) goto werr;
                if (rioWriteBulkLongLong(&aof,expiretime) == 0) goto werr;
            }
        }

        // 释放迭代器
        dictReleaseIterator(di);
    }

    /* Make sure data will not remain on the OS's output buffers */
    // 冲洗并关闭新 AOF 文件
    if (fflush(fp) == EOF) goto werr;
    if (aof_fsync(fileno(fp)) == -1) goto werr;
    if (fclose(fp) == EOF) goto werr;

    /* Use RENAME to make sure the DB file is changed atomically only
     * if the generate DB file is ok. 
     *
     * 原子地改名，用重写后的新 AOF 文件覆盖旧 AOF 文件
     */
    if (rename(tmpfile,filename) == -1) {
        redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
        unlink(tmpfile);
        return REDIS_ERR;
    }

    redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");

    return REDIS_OK;

werr:
    fclose(fp);
    unlink(tmpfile);
    redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
    if (di) dictReleaseIterator(di);
    return REDIS_ERR;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1d8, %rsp            # imm = 0x1D8
movq %rdi, %r14
callq 0x232a3
movq %rax, %r15
callq 0x1f410
leaq 0x4fd45(%rip), %rdx     # 0x9ab5f
leaq 0xd0(%rsp), %rbx
movl $0x100, %esi            # imm = 0x100
movq %rbx, %rdi
movl %eax, %ecx
xorl %eax, %eax
callq 0x1f120
leaq 0x4c61e(%rip), %rsi     # 0x97458
movq %rbx, %rdi
callq 0x1fa60
testq %rax, %rax
je 0x4b28a
movq %rax, %r13
leaq 0x60(%rsp), %rdi
movq %rax, %rsi
callq 0x58e24
leaq 0x7f146(%rip), %rbx     # 0xc9fa8
cmpl $0x0, 0x550(%rbx)
je 0x4ae7a
leaq 0x60(%rsp), %rdi
movl $0x2000000, %esi        # imm = 0x2000000
callq 0x58e7a
movq %r14, 0x58(%rsp)
cmpl $0x0, 0x480(%rbx)
jle 0x4b2b1
xorl %ecx, %ecx
leaq 0x60(%rsp), %rbp
xorl %r12d, %r12d
movq %r13, 0x20(%rsp)
movq %r15, 0x8(%rsp)
movaps 0x50129(%rip), %xmm0    # 0x9afd0
movaps %xmm0, 0xb0(%rsp)
movb $0x0, 0xc0(%rsp)
movq 0x10(%rbx), %rax
movq %rcx, 0x30(%rsp)
movq %rcx, %rbx
shlq $0x6, %rbx
movq %rax, 0x38(%rsp)
movq (%rax,%rbx), %rdi
movq 0x28(%rdi), %rcx
movl $0x4, %eax
addq 0x48(%rdi), %rcx
je 0x4b25c
callq 0x228e4
testq %rax, %rax
je 0x4b232
movq %rax, %r12
addq %rbx, 0x38(%rsp)
movl $0x10, %ecx
leaq 0xb0(%rsp), %rbx
testq %rcx, %rcx
je 0x4af77
movq %rcx, %r14
movq 0x78(%rsp), %rax
movq 0x90(%rsp), %rcx
cmpq %r14, %rcx
movq %r14, %r15
cmovbq %rcx, %r15
testq %rcx, %rcx
cmoveq %r14, %r15
testq %rax, %rax
je 0x4af3c
movq %rbp, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq *%rax
movq %rbp, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq *0x68(%rsp)
testq %rax, %rax
je 0x4af61
addq %r15, %rbx
movq %r14, %rcx
subq %r15, %rcx
addq %r15, 0x88(%rsp)
jmp 0x4af64
movq %r14, %rcx
testq %rax, %rax
jne 0x4af06
movl $0x5, %eax
testq %r14, %r14
jne 0x4b25c
movq %rbp, %rdi
movq 0x30(%rsp), %rsi
callq 0x59069
testq %rax, %rax
je 0x4b250
movq %r12, %rdi
callq 0x22913
testq %rax, %rax
movq 0x8(%rsp), %r15
je 0x4b244
movq %r12, 0x28(%rsp)
movq (%rax), %rcx
movq 0x8(%rax), %r12
movl $0x1, 0x14(%rsp)
movb $0x0, 0x10(%rsp)
movq %rcx, 0x18(%rsp)
movq 0x38(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x326b1
movq %rax, %rbx
cmpq $-0x1, %rax
setne %cl
cmpq %r15, %rax
setl %dl
movl $0x6, %eax
testb %dl, %cl
jne 0x4b1f6
movl (%r12), %eax
andl $0xf, %eax
cmpl $0x4, %eax
ja 0x4b3ae
leaq 0x4f5ac(%rip), %rcx     # 0x9a5b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movabsq $0xa0d5445530a0d, %rax  # imm = 0xA0D5445530A0D
movq %rax, 0x46(%rsp)
movabsq $0xa0d33240a0d332a, %rax # imm = 0xA0D33240A0D332A
movq %rax, 0x40(%rsp)
movl $0xd, %ecx
leaq 0x40(%rsp), %r15
testq %rcx, %rcx
je 0x4b0a1
movq %rcx, %r13
movq 0x78(%rsp), %rax
movq 0x90(%rsp), %rcx
cmpq %r13, %rcx
movq %r13, %r14
cmovbq %rcx, %r14
testq %rcx, %rcx
cmoveq %r13, %r14
testq %rax, %rax
je 0x4b06b
movq %rbp, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq *%rax
movq %rbp, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq *0x68(%rsp)
testq %rax, %rax
je 0x4b090
addq %r14, %r15
movq %r13, %rcx
subq %r14, %rcx
addq %r14, 0x88(%rsp)
jmp 0x4b093
movq %r13, %rcx
testq %rax, %rax
jne 0x4b035
testq %r13, %r13
jne 0x4b217
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
callq 0x4a4c3
testl %eax, %eax
je 0x4b217
movq %rbp, %rdi
movq %r12, %rsi
callq 0x4a4c3
xorl %edx, %edx
testl %eax, %eax
setne %cl
sete %dl
leal (%rdx,%rdx,4), %eax
jmp 0x4b21e
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
movq %r12, %rdx
callq 0x4ac32
jmp 0x4b119
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
movq %r12, %rdx
callq 0x4a73d
jmp 0x4b119
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
movq %r12, %rdx
callq 0x4a941
jmp 0x4b119
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
movq %r12, %rdx
callq 0x4a514
testl %eax, %eax
je 0x4b1dd
cmpq $-0x1, %rbx
je 0x4b1f4
movaps 0x4febe(%rip), %xmm0    # 0x9aff0
movaps %xmm0, 0x40(%rsp)
movl $0xa0d54, 0x50(%rsp)    # imm = 0xA0D54
movl $0x13, %ecx
leaq 0x40(%rsp), %r15
testq %rcx, %rcx
je 0x4b1b1
movq %rcx, %r12
movq 0x78(%rsp), %rax
movq 0x90(%rsp), %rcx
cmpq %r12, %rcx
movq %r12, %r14
cmovbq %rcx, %r14
testq %rcx, %rcx
cmoveq %r12, %r14
testq %rax, %rax
je 0x4b17f
movq %rbp, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq *%rax
movq %rbp, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq *0x68(%rsp)
testq %rax, %rax
je 0x4b1a4
addq %r14, %r15
movq %r12, %rcx
subq %r14, %rcx
addq %r14, 0x88(%rsp)
jmp 0x4b1a7
movq %r12, %rcx
testq %rax, %rax
jne 0x4b149
testq %r12, %r12
jne 0x4b1e4
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
callq 0x4a4c3
testl %eax, %eax
je 0x4b1e4
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x59069
xorl %edx, %edx
testq %rax, %rax
setne %cl
sete %dl
leal (%rdx,%rdx,4), %eax
jmp 0x4b1eb
movl $0x5, %eax
jmp 0x4b1f6
movl $0x5, %eax
xorl %ecx, %ecx
movq 0x8(%rsp), %r15
testb %cl, %cl
je 0x4b1f6
xorl %eax, %eax
cmpl $0x6, %eax
je 0x4b1ff
testl %eax, %eax
jne 0x4b257
movq 0x28(%rsp), %r12
movq %r12, %rdi
callq 0x22913
testq %rax, %rax
jne 0x4afa8
jmp 0x4b244
movl $0x5, %eax
xorl %ecx, %ecx
movq 0x20(%rsp), %r13
movq 0x8(%rsp), %r15
testb %cl, %cl
jne 0x4b121
jmp 0x4b1f6
movq %r13, %rdi
callq 0x1f9a0
movl $0x1, %eax
xorl %r12d, %r12d
jmp 0x4b25c
movq %r12, %rdi
callq 0x229b9
xorl %eax, %eax
jmp 0x4b25c
movl $0x5, %eax
jmp 0x4b25c
movq 0x28(%rsp), %r12
testl %eax, %eax
je 0x4b269
cmpl $0x4, %eax
jne 0x4b316
movq 0x30(%rsp), %rcx
incq %rcx
leaq 0x7ed30(%rip), %rbx     # 0xc9fa8
movslq 0x480(%rbx), %rax
cmpq %rax, %rcx
jl 0x4aea0
jmp 0x4b2b4
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4f8d9(%rip), %rsi     # 0x9ab76
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23064
jmp 0x4b395
xorl %r12d, %r12d
movq %r13, %rdi
callq 0x1fc60
cmpl $-0x1, %eax
movq 0x58(%rsp), %rbx
je 0x4b31b
movq %r13, %rdi
callq 0x1f070
movl %eax, %edi
callq 0x1f560
cmpl $-0x1, %eax
je 0x4b31b
movq %r13, %rdi
callq 0x1f9a0
cmpl $-0x1, %eax
je 0x4b31b
leaq 0xd0(%rsp), %rdi
movq %rbx, %rsi
callq 0x1fc20
cmpl $-0x1, %eax
je 0x4b366
leaq 0x4f906(%rip), %rsi     # 0x9ac09
xorl %ebx, %ebx
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
jmp 0x4b39a
cmpl $0x5, %eax
jne 0x4b395
movq %r13, %rdi
callq 0x1f9a0
leaq 0xd0(%rsp), %rdi
callq 0x1f3a0
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4f8ee(%rip), %rsi     # 0x9ac31
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23064
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
testq %r12, %r12
je 0x4b39a
movq %r12, %rdi
callq 0x229b9
jmp 0x4b39a
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4f850(%rip), %rsi     # 0x9abc9
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23064
leaq 0xd0(%rsp), %rdi
callq 0x1f3a0
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
movl %ebx, %eax
addq $0x1d8, %rsp            # imm = 0x1D8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x4bffe(%rip), %rdi     # 0x973b3
leaq 0x4f24d(%rip), %rsi     # 0x9a609
movl $0x596, %edx            # imm = 0x596
callq 0x4d0e5
movl $0x1, %edi
callq 0x1f3b0