// File: /workspace/github_c_makefile_star2_O2/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 $0x1c8, %rsp            # imm = 0x1C8
movq %rdi, %r14
callq 0x22843
movq %rax, %r15
callq 0x1f410
leaq 0x4997b(%rip), %rdx     # 0x90b6b
leaq 0xc0(%rsp), %rbx
movl $0x100, %esi            # imm = 0x100
movq %rbx, %rdi
movl %eax, %ecx
xorl %eax, %eax
callq 0x1f120
leaq 0x4629c(%rip), %rsi     # 0x8d4ac
movq %rbx, %rdi
callq 0x1fa60
testq %rax, %rax
je 0x474ed
movq %r15, 0x28(%rsp)
movq %r14, 0x48(%rsp)
leaq 0x70(%rsp), %rdi
movq %rax, 0x8(%rsp)
movq %rax, %rsi
callq 0x541e8
leaq 0x7fd64(%rip), %rcx     # 0xc6fa8
cmpl $0x0, 0x550(%rcx)
je 0x47263
leaq 0x70(%rsp), %rdi
movl $0x2000000, %esi        # imm = 0x2000000
callq 0x5424f
leaq 0x7fd45(%rip), %rcx     # 0xc6fa8
xorl %edx, %edx
leaq 0x70(%rsp), %r12
leaq 0x50(%rsp), %rbx
xorl %r15d, %r15d
movslq 0x480(%rcx), %rax
cmpq %rax, %rdx
jge 0x47524
movaps 0x49d57(%rip), %xmm0    # 0x90fe0
movaps %xmm0, 0x50(%rsp)
movb $0x0, 0x60(%rsp)
movq 0x10(%rcx), %r14
movq %rdx, %r13
shlq $0x6, %r13
movq (%r14,%r13), %rdi
movq 0x28(%rdi), %rax
addq 0x48(%rdi), %rax
je 0x47499
movq %rdx, 0x20(%rsp)
callq 0x21f20
testq %rax, %rax
je 0x4758f
movq %rax, %r15
movq %r12, %rdi
movq %rbx, %rsi
pushq $0x10
popq %rdx
callq 0x475f0
testq %rax, %rax
je 0x474a1
movq %r12, %rdi
movq 0x20(%rsp), %rsi
callq 0x543ad
testq %rax, %rax
je 0x474a1
movq %r12, %rbx
addq %r13, %r14
movq 0x28(%rsp), %r12
movq %r15, %rdi
callq 0x21f2f
testq %rax, %rax
je 0x4747d
movq (%rax), %rcx
movq 0x8(%rax), %rbp
movabsq $0x100000000, %rax      # imm = 0x100000000
movq %rax, 0x10(%rsp)
movq %rcx, 0x18(%rsp)
movq %r14, %rdi
leaq 0x10(%rsp), %rsi
callq 0x30ab1
movq %rax, %r13
cmpq $-0x1, %rax
setne %al
cmpq %r12, %r13
setl %cl
testb %cl, %al
jne 0x472fe
movl (%rbp), %eax
andl $0xf, %eax
cmpl $0x4, %eax
ja 0x475d0
leaq 0x4925b(%rip), %rcx     # 0x905bc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movabsq $0xa0d5445530a0d, %rax  # imm = 0xA0D5445530A0D
movq %rax, 0x36(%rsp)
movabsq $0xa0d33240a0d332a, %rax # imm = 0xA0D33240A0D332A
movq %rax, 0x30(%rsp)
movq %rbx, %r12
movq %rbx, %rdi
leaq 0x30(%rsp), %rsi
pushq $0xd
popq %rdx
callq 0x475f0
testq %rax, %rax
je 0x474a1
movq %r12, %rdi
leaq 0x10(%rsp), %rsi
callq 0x46979
testl %eax, %eax
je 0x474a1
movq %r12, %rdi
movq %rbp, %rsi
callq 0x46979
testl %eax, %eax
movq 0x28(%rsp), %r12
jne 0x47420
jmp 0x474a1
movq %rbx, %rdi
leaq 0x10(%rsp), %rsi
movq %rbp, %rdx
callq 0x4702d
jmp 0x47418
movq %rbx, %rdi
leaq 0x10(%rsp), %rsi
movq %rbp, %rdx
callq 0x46bb2
jmp 0x47418
movq %rbx, %rdi
leaq 0x10(%rsp), %rsi
movq %rbp, %rdx
callq 0x46d6c
jmp 0x47418
movq %rbx, %rdi
leaq 0x10(%rsp), %rsi
movq %rbp, %rdx
callq 0x469c8
testl %eax, %eax
je 0x474a1
cmpq $-0x1, %r13
je 0x472fe
movaps 0x49bcf(%rip), %xmm0    # 0x91000
movaps %xmm0, 0x30(%rsp)
movl $0xa0d54, 0x40(%rsp)    # imm = 0xA0D54
movq %rbx, %rbp
movq %rbx, %rdi
leaq 0x30(%rsp), %rsi
pushq $0x13
popq %rdx
callq 0x475f0
testq %rax, %rax
je 0x474a1
movq %rbp, %rdi
leaq 0x10(%rsp), %rsi
callq 0x46979
testl %eax, %eax
je 0x474a1
movq %rbp, %rdi
movq %r13, %rsi
callq 0x543ad
testq %rax, %rax
jne 0x472fe
jmp 0x474a1
movq %r15, %rdi
callq 0x21fe6
leaq 0x7fb1c(%rip), %rcx     # 0xc6fa8
movq 0x20(%rsp), %rdx
movq %rbx, %r12
leaq 0x50(%rsp), %rbx
incq %rdx
jmp 0x47272
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
callq 0x1f9a0
leaq 0xc0(%rsp), %rdi
callq 0x1f3a0
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x4976f(%rip), %rsi     # 0x90c3d
pushq $0x3
popq %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x22613
pushq $-0x1
popq %rbx
testq %r15, %r15
je 0x47510
movq %r15, %rdi
callq 0x21fe6
jmp 0x47510
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x49682(%rip), %rsi     # 0x90b82
pushq $0x3
popq %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x22613
pushq $-0x1
popq %rbx
movl %ebx, %eax
addq $0x1c8, %rsp            # imm = 0x1C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
callq 0x1fc60
cmpl $-0x1, %eax
je 0x474a6
movq %rbx, %rdi
callq 0x1f070
movl %eax, %edi
callq 0x1f560
cmpl $-0x1, %eax
je 0x474a6
movq %rbx, %rdi
callq 0x1f9a0
cmpl $-0x1, %eax
je 0x474a6
leaq 0xc0(%rsp), %rdi
movq 0x48(%rsp), %rsi
callq 0x1fc20
cmpl $-0x1, %eax
je 0x4759e
leaq 0x49694(%rip), %rsi     # 0x90c15
xorl %ebx, %ebx
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
jmp 0x47510
movq 0x8(%rsp), %rdi
callq 0x1f9a0
jmp 0x4750d
callq 0x1f810
movl (%rax), %edi
callq 0x1f630
leaq 0x49624(%rip), %rsi     # 0x90bd5
pushq $0x3
popq %rdi
movq %rax, %rdx
xorl %eax, %eax
callq 0x22613
leaq 0xc0(%rsp), %rdi
callq 0x1f3a0
jmp 0x4750d
leaq 0x45e30(%rip), %rdi     # 0x8d407
leaq 0x49037(%rip), %rsi     # 0x90615
movl $0x596, %edx            # imm = 0x596
callq 0x490e8
pushq $0x1
popq %rdi
callq 0x1f3b0