// File: /workspace/github_c_makefile_star2_O3/nilyang[P]redis-tdd-annotation/src/rdb.c
// Function: rdbLoad
int rdbLoad(char *filename) {
    uint32_t dbid;
    int type, rdbver;
    redisDb *db = server.db+0;
    char buf[1024];
    long long expiretime, now = mstime();
    FILE *fp;
    rio rdb;

    // 打开 rdb 文件
    if ((fp = fopen(filename,"r")) == NULL) return REDIS_ERR;

    // 初始化写入流
    rioInitWithFile(&rdb,fp);
    rdb.update_cksum = rdbLoadProgressCallback;
    rdb.max_processing_chunk = server.loading_process_events_interval_bytes;
    if (rioRead(&rdb,buf,9) == 0) goto eoferr;
    buf[9] = '\0';

    // 检查版本号
    if (memcmp(buf,"REDIS",5) != 0) {
        fclose(fp);
        redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
        errno = EINVAL;
        return REDIS_ERR;
    }
    rdbver = atoi(buf+5);
    if (rdbver < 1 || rdbver > REDIS_RDB_VERSION) {
        fclose(fp);
        redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
        errno = EINVAL;
        return REDIS_ERR;
    }

    // 将服务器状态调整到开始载入状态
    startLoading(fp);
    while(1) {
        robj *key, *val;
        expiretime = -1;

        /* Read type. 
         *
         * 读入类型指示，决定该如何读入之后跟着的数据。
         *
         * 这个指示可以是 rdb.h 中定义的所有以
         * REDIS_RDB_TYPE_* 为前缀的常量的其中一个
         * 或者所有以 REDIS_RDB_OPCODE_* 为前缀的常量的其中一个
         */
        if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;

        // 读入过期时间值
        if (type == REDIS_RDB_OPCODE_EXPIRETIME) {

            // 以秒计算的过期时间

            if ((expiretime = rdbLoadTime(&rdb)) == -1) goto eoferr;

            /* We read the time so we need to read the object type again. 
             *
             * 在过期时间之后会跟着一个键值对，我们要读入这个键值对的类型
             */
            if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;

            /* the EXPIRETIME opcode specifies time in seconds, so convert
             * into milliseconds. 
             *
             * 将格式转换为毫秒*/
            expiretime *= 1000;
        } else if (type == REDIS_RDB_OPCODE_EXPIRETIME_MS) {

            // 以毫秒计算的过期时间

            /* Milliseconds precision expire times introduced with RDB
             * version 3. */
            if ((expiretime = rdbLoadMillisecondTime(&rdb)) == -1) goto eoferr;

            /* We read the time so we need to read the object type again.
             *
             * 在过期时间之后会跟着一个键值对，我们要读入这个键值对的类型
             */
            if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;
        }
            
        // 读入数据 EOF （不是 rdb 文件的 EOF）
        if (type == REDIS_RDB_OPCODE_EOF)
            break;

        /* Handle SELECT DB opcode as a special case 
         *
         * 读入切换数据库指示
         */
        if (type == REDIS_RDB_OPCODE_SELECTDB) {

            // 读入数据库号码
            if ((dbid = rdbLoadLen(&rdb,NULL)) == REDIS_RDB_LENERR)
                goto eoferr;

            // 检查数据库号码的正确性
            if (dbid >= (unsigned)server.dbnum) {
                redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
                exit(1);
            }

            // 在程序内容切换数据库
            db = server.db+dbid;

            // 跳过
            continue;
        }

        /* Read key 
         *
         * 读入键
         */
        if ((key = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;

        /* Read value 
         *
         * 读入值
         */
        if ((val = rdbLoadObject(type,&rdb)) == NULL) goto eoferr;

        /* Check if the key already expired. This function is used when loading
         * an RDB file from disk, either at startup, or when an RDB was
         * received from the master. In the latter case, the master is
         * responsible for key expiry. If we would expire keys here, the
         * snapshot taken by the master may not be reflected on the slave. 
         *
         * 如果服务器为主节点的话，
         * 那么在键已经过期的时候，不再将它们关联到数据库中去
         */
        if (server.masterhost == NULL && expiretime != -1 && expiretime < now) {
            decrRefCount(key);
            decrRefCount(val);
            // 跳过
            continue;
        }

        /* Add the new object in the hash table 
         *
         * 将键值对关联到数据库中
         */
        dbAdd(db,key,val);

        /* Set the expire time if needed 
         *
         * 设置过期时间
         */
        if (expiretime != -1) setExpire(db,key,expiretime);

        decrRefCount(key);
    }

    /* Verify the checksum if RDB version is >= 5 
     *
     * 如果 RDB 版本 >= 5 ，那么比对校验和
     */
    if (rdbver >= 5 && server.rdb_checksum) {
        uint64_t cksum, expected = rdb.cksum;

        // 读入文件的校验和
        if (rioRead(&rdb,&cksum,8) == 0) goto eoferr;
        memrev64ifbe(&cksum);

        // 比对校验和
        if (cksum == 0) {
            redisLog(REDIS_WARNING,"RDB file was saved with checksum disabled: no check performed.");
        } else if (cksum != expected) {
            redisLog(REDIS_WARNING,"Wrong RDB checksum. Aborting now.");
            exit(1);
        }
    }

    // 关闭 RDB 
    fclose(fp);

    // 服务器从载入状态中退出
    stopLoading();

    return REDIS_OK;

eoferr: /* unexpected end of file is handled here with a fatal exit */
    redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
    exit(1);
    return REDIS_ERR; /* Just to avoid warning */
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x478, %rsp            # imm = 0x478
movq %rdi, %rbx
leaq 0x91cef(%rip), %r13     # 0xc9fa8
movq 0x10(%r13), %r15
callq 0x23461
movq %rax, %r14
leaq 0x69e4e(%rip), %rsi     # 0xa211a
movq %rbx, %rdi
callq 0x1fa60
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
testq %rax, %rax
je 0x383e3
movq %rax, %rsi
leaq 0x20(%rsp), %r12
movq %r12, %rdi
movq %rax, 0x8(%rsp)
callq 0x5887c
leaq -0xe9(%rip), %rax       # 0x38215
movq %rax, 0x18(%r12)
movq 0x310(%r13), %rax
movq %rax, 0x30(%r12)
leaq 0x70(%rsp), %rbx
movl $0x9, %ebp
movq 0x50(%rsp), %rax
cmpq %rbp, %rax
movq %rbp, %r13
cmovbq %rax, %r13
testq %rax, %rax
cmoveq %rbp, %r13
movq %r12, %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq *0x20(%rsp)
testq %rax, %rax
je 0x38646
movq 0x38(%rsp), %rax
testq %rax, %rax
je 0x3835a
movq %r12, %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq *%rax
addq %r13, %rbx
addq %r13, 0x48(%rsp)
subq %r13, %rbp
jne 0x38319
movb $0x0, 0x79(%rsp)
movl $0x49444552, %eax       # imm = 0x49444552
xorl 0x70(%rsp), %eax
movzbl 0x74(%rsp), %ecx
xorl $0x53, %ecx
orl %eax, %ecx
je 0x383a0
movq 0x8(%rsp), %rdi
callq 0x1f9a0
leaq 0x60915(%rip), %rsi     # 0x98ca7
movl $0x3, %edi
xorl %eax, %eax
callq 0x23223
jmp 0x383d3
leaq 0x75(%rsp), %rdi
callq 0x1f710
movl %eax, %ebx
leal -0x7(%rbx), %eax
cmpl $-0x7, %eax
movq 0x8(%rsp), %rdi
ja 0x383f7
callq 0x1f9a0
leaq 0x6090e(%rip), %rsi     # 0x98cd3
movl $0x3, %edi
movl %ebx, %edx
xorl %eax, %eax
callq 0x23223
callq 0x1f810
movl $0x16, (%rax)
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
movl %ecx, %eax
addq $0x478, %rsp            # imm = 0x478
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rbx, 0x10(%rsp)
callq 0x3816a
leaq 0x20(%rsp), %r13
movq %r13, %rdi
callq 0x36237
cmpl $0xfc, %eax
je 0x38464
movl %eax, %r12d
cmpl $0xfd, %eax
je 0x38432
cmpl $-0x1, %r12d
je 0x38646
movq $-0x1, %rbp
jmp 0x3848d
movq %r13, %rdi
callq 0x362aa
cmpq $-0x1, %rax
je 0x38646
movq %rax, %rbx
movq %r13, %rdi
callq 0x36237
cmpl $-0x1, %eax
je 0x38646
movl %eax, %r12d
imulq $0x3e8, %rbx, %rbp      # imm = 0x3E8
jmp 0x3848d
movq %r13, %rdi
callq 0x36335
cmpq $-0x1, %rax
je 0x38646
movq %rax, %rbp
movq %r13, %rdi
callq 0x36237
cmpl $-0x1, %eax
je 0x38646
movl %eax, %r12d
cmpl $0xff, %r12d
je 0x38575
movq %r13, %rdi
cmpl $0xfe, %r12d
je 0x38540
xorl %esi, %esi
callq 0x36bfd
testq %rax, %rax
je 0x38646
movq %rax, %rbx
movl %r12d, %edi
movq %r13, %rsi
callq 0x37998
testq %rax, %rax
je 0x38646
movq %rax, %r12
leaq 0x91acd(%rip), %rax     # 0xc9fa8
cmpq $0x0, 0x650(%rax)
sete %al
cmpq $-0x1, %rbp
setne %cl
cmpq %r14, %rbp
setl %dl
andb %cl, %dl
andb %al, %dl
cmpb $0x1, %dl
jne 0x38511
movq %rbx, %rdi
callq 0x30b0c
movq %r12, %rdi
callq 0x30b0c
jmp 0x38406
movq %r15, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x317f0
cmpq $-0x1, %rbp
je 0x38533
movq %r15, %rdi
movq %rbx, %rsi
movq %rbp, %rdx
callq 0x32a5e
movq %rbx, %rdi
callq 0x30b0c
jmp 0x38406
xorl %esi, %esi
callq 0x3645f
cmpl $-0x1, %eax
je 0x38646
leaq 0x91a51(%rip), %rcx     # 0xc9fa8
movl 0x480(%rcx), %edx
cmpl %edx, %eax
jae 0x38663
movl %eax, %r15d
shlq $0x6, %r15
addq 0x10(%rcx), %r15
jmp 0x38406
cmpl $0x5, 0x10(%rsp)
leaq 0x91a27(%rip), %rbx     # 0xc9fa8
jl 0x3862b
cmpl $0x0, 0x594(%rbx)
je 0x3862b
leaq 0x18(%rsp), %rbx
movl $0x8, %r13d
leaq 0x20(%rsp), %r14
movq 0x20(%r14), %r12
movq 0x50(%rsp), %rax
cmpq %r13, %rax
movq %r13, %r15
cmovbq %rax, %r15
testq %rax, %rax
cmoveq %r13, %r15
movq %r14, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq *0x20(%rsp)
testq %rax, %rax
je 0x38646
movq 0x38(%rsp), %rax
testq %rax, %rax
je 0x385e5
movq %r14, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq *%rax
addq %r15, %rbx
addq %r15, 0x48(%rsp)
subq %r15, %r13
jne 0x385a8
movq 0x18(%rsp), %rax
testq %rax, %rax
je 0x38611
cmpq %r12, %rax
leaq 0x919a2(%rip), %rbx     # 0xc9fa8
je 0x3862b
leaq 0x6078d(%rip), %rsi     # 0x98d9c
jmp 0x3864d
leaq 0x60745(%rip), %rsi     # 0x98d5d
movl $0x3, %edi
xorl %eax, %eax
callq 0x23223
leaq 0x9197d(%rip), %rbx     # 0xc9fa8
movq 0x8(%rsp), %rdi
callq 0x1f9a0
movl $0x0, 0x2f0(%rbx)
xorl %ecx, %ecx
jmp 0x383e3
leaq 0x60771(%rip), %rsi     # 0x98dbe
movl $0x3, %edi
xorl %eax, %eax
callq 0x23223
movl $0x1, %edi
callq 0x1f2b0
leaq 0x6068c(%rip), %rsi     # 0x98cf6
movl $0x3, %edi
xorl %eax, %eax
callq 0x23223
jmp 0x38659