// File: /workspace/github_c_makefile_star2_O3/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 0x23461
movq %rax, %r12
callq 0x1f410
leaq 0x5032e(%rip), %rdx     # 0x9aba7
leaq 0xd0(%rsp), %rbx
movl $0x100, %esi            # imm = 0x100
movq %rbx, %rdi
movl %eax, %ecx
xorl %eax, %eax
callq 0x1f120
leaq 0x4cc1f(%rip), %rsi     # 0x974b8
movq %rbx, %rdi
callq 0x1fa60
testq %rax, %rax
je 0x4ac42
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
movq %rax, %rsi
callq 0x5887c
leaq 0x7f6e7(%rip), %rcx     # 0xc9fa8
cmpl $0x0, 0x550(%rcx)
je 0x4a8df
leaq 0x60(%rsp), %rdi
movl $0x2000000, %esi        # imm = 0x2000000
movq %rcx, %r15
callq 0x588e8
movq %r15, %rcx
movq %rbx, 0x10(%rsp)
movq %r14, 0x50(%rsp)
cmpl $0x0, 0x480(%rcx)
jle 0x4ac7d
xorl %r13d, %r13d
movaps 0x50720(%rip), %xmm0    # 0x9b020
leaq 0x60(%rsp), %rbp
xorl %r15d, %r15d
movq %r12, 0x18(%rsp)
movaps %xmm0, 0xb0(%rsp)
movb $0x0, 0xc0(%rsp)
movq 0x10(%rcx), %rbx
movq %r13, %r14
shlq $0x6, %r14
movq (%rbx,%r14), %rdi
movq 0x28(%rdi), %rax
addq 0x48(%rdi), %rax
jne 0x4a94a
incq %r13
movslq 0x480(%rcx), %rax
cmpq %rax, %r13
jl 0x4a90d
jmp 0x4ac80
callq 0x22aa0
testq %rax, %rax
je 0x4ad20
movq %rax, 0x8(%rsp)
addq %r14, %rbx
movl $0x10, %r15d
leaq 0xb0(%rsp), %r14
movq 0x78(%rsp), %rax
movq 0x90(%rsp), %rcx
cmpq %r15, %rcx
movq %r15, %r12
cmovbq %rcx, %r12
testq %rcx, %rcx
cmoveq %r15, %r12
testq %rax, %rax
je 0x4a99c
movq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *%rax
movq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *0x68(%rsp)
testq %rax, %rax
je 0x4ac6e
addq %r12, %r14
addq %r12, 0x88(%rsp)
subq %r12, %r15
jne 0x4a96e
movq %rbp, %rdi
movq %r13, %rsi
callq 0x58ab3
testq %rax, %rax
je 0x4ac6e
movq %rbx, 0x58(%rsp)
movq 0x8(%rsp), %r15
movq %r15, %rdi
callq 0x22acf
testq %rax, %rax
movq 0x18(%rsp), %r12
leaq 0x20(%rsp), %r14
je 0x4ac27
movq (%rax), %rcx
movq 0x8(%rax), %rbx
movabsq $0x100000000, %rax      # imm = 0x100000000
movq %rax, 0x20(%rsp)
movq %rcx, 0x28(%rsp)
movq 0x58(%rsp), %rdi
movq %r14, %rsi
callq 0x329dd
cmpq $-0x1, %rax
setne %dl
cmpq %r12, %rax
setl %cl
testb %cl, %dl
jne 0x4ac16
movl (%rbx), %esi
andl $0xf, %esi
cmpl $0x4, %esi
ja 0x4ad91
movq %rax, (%rsp)
leaq 0x4fba7(%rip), %rcx     # 0x9a5f8
movslq (%rcx,%rsi,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %rbx, 0x48(%rsp)
movabsq $0xa0d5445530a0d, %rax  # imm = 0xA0D5445530A0D
movq %rax, 0x36(%rsp)
movabsq $0xa0d33240a0d332a, %rax # imm = 0xA0D33240A0D332A
movq %rax, 0x30(%rsp)
movl $0xd, %r15d
leaq 0x30(%rsp), %r14
movq 0x78(%rsp), %rax
movq 0x90(%rsp), %rcx
cmpq %r15, %rcx
movq %r15, %r12
cmovbq %rcx, %r12
testq %rcx, %rcx
cmoveq %r15, %r12
testq %rax, %rax
je 0x4aab6
movq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *%rax
movq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *0x68(%rsp)
testq %rax, %rax
je 0x4ac6e
addq %r12, %r14
addq %r12, 0x88(%rsp)
subq %r12, %r15
jne 0x4aa88
movq %rbp, %rdi
leaq 0x20(%rsp), %rsi
callq 0x49f3a
testl %eax, %eax
je 0x4ac6e
movq %rbp, %rdi
movq 0x48(%rsp), %rsi
callq 0x49f3a
testl %eax, %eax
movq 0x8(%rsp), %r15
movq 0x18(%rsp), %r12
leaq 0x20(%rsp), %r14
movq (%rsp), %rax
jne 0x4ab64
jmp 0x4ad2f
movq %rbp, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x4a691
jmp 0x4ab58
movq %rbp, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x4a1b8
jmp 0x4ab58
movq %rbp, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x4a3b4
jmp 0x4ab58
movq %rbp, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x49f8b
testl %eax, %eax
movq (%rsp), %rax
je 0x4ac6e
cmpq $-0x1, %rax
je 0x4ac16
movaps 0x504cb(%rip), %xmm0    # 0x9b040
movaps %xmm0, 0x30(%rsp)
movl $0xa0d54, 0x40(%rsp)    # imm = 0xA0D54
movl $0x13, %r15d
leaq 0x30(%rsp), %r14
movq 0x78(%rsp), %rax
movq 0x90(%rsp), %rcx
cmpq %r15, %rcx
movq %r15, %r12
cmovbq %rcx, %r12
testq %rcx, %rcx
cmoveq %r15, %r12
testq %rax, %rax
je 0x4abbb
movq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *%rax
movq %rbp, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *0x68(%rsp)
testq %rax, %rax
je 0x4ac6e
addq %r12, %r14
addq %r12, 0x88(%rsp)
subq %r12, %r15
jne 0x4ab8d
movq %rbp, %rdi
leaq 0x20(%rsp), %rsi
callq 0x49f3a
testl %eax, %eax
je 0x4ac6e
movq %rbp, %rdi
movq (%rsp), %rsi
callq 0x58ab3
testq %rax, %rax
movq 0x8(%rsp), %r15
movq 0x18(%rsp), %r12
leaq 0x20(%rsp), %r14
je 0x4ad2f
movq %r15, %rdi
callq 0x22acf
testq %rax, %rax
jne 0x4a9fb
movq %r15, %rdi
callq 0x22b86
leaq 0x7f372(%rip), %rcx     # 0xc9fa8
movaps 0x503e3(%rip), %xmm0    # 0x9b020
jmp 0x4a936
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4ff69(%rip), %rsi     # 0x9abbe
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23223
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x4ad7d
movq 0x10(%rsp), %rbx
movq 0x8(%rsp), %r15
jmp 0x4ad34
xorl %r15d, %r15d
movq 0x10(%rsp), %rbx
movq %rbx, %rdi
callq 0x1fc60
cmpl $-0x1, %eax
je 0x4ad34
movq %rbx, %rdi
callq 0x1f070
movl %eax, %edi
callq 0x1f560
cmpl $-0x1, %eax
je 0x4ad34
movq %rbx, %rdi
callq 0x1f9a0
cmpl $-0x1, %eax
je 0x4ad34
leaq 0xd0(%rsp), %rdi
movq 0x50(%rsp), %rsi
callq 0x1fc20
cmpl $-0x1, %eax
je 0x4acec
leaq 0x4ff78(%rip), %rsi     # 0x9ac51
xorl %ebx, %ebx
movl $0x2, %edi
xorl %eax, %eax
callq 0x23223
jmp 0x4ad7d
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4ff12(%rip), %rsi     # 0x9ac11
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23223
leaq 0xd0(%rsp), %rdi
callq 0x1f3a0
jmp 0x4ac64
movq 0x10(%rsp), %rdi
callq 0x1f9a0
jmp 0x4ac64
movq 0x10(%rsp), %rbx
movq %rbx, %rdi
callq 0x1f9a0
leaq 0xd0(%rsp), %rdi
callq 0x1f3a0
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4ff1d(%rip), %rsi     # 0x9ac79
movl $0x3, %edi
movq %rax, %rdx
xorl %eax, %eax
callq 0x23223
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
testq %r15, %r15
je 0x4ad7d
movq %r15, %rdi
callq 0x22b86
movl %ebx, %eax
addq $0x1d8, %rsp            # imm = 0x1D8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x4c67b(%rip), %rdi     # 0x97413
leaq 0x4f8b2(%rip), %rsi     # 0x9a651
movl $0x596, %edx            # imm = 0x596
callq 0x4cae0
movl $0x1, %edi
callq 0x1f3b0