// File: /workspace/github_c_makefile_star2_O1/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 $0x488, %rsp            # imm = 0x488
movq %rdi, %rbx
leaq 0x91e73(%rip), %r14     # 0xc9fa8
movq 0x10(%r14), %r12
callq 0x232a3
movq %rax, %r15
leaq 0x69f42(%rip), %rsi     # 0xa208a
movq %rbx, %rdi
callq 0x1fa60
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
testq %rax, %rax
je 0x3828e
movq %r12, 0x10(%rsp)
movq %r15, 0x20(%rsp)
leaq 0x30(%rsp), %r12
movq %r12, %rdi
movq %rax, 0x8(%rsp)
movq %rax, %rsi
callq 0x58e24
leaq -0xf3(%rip), %rax       # 0x38091
movq %rax, 0x18(%r12)
movq 0x310(%r14), %rax
movq %rax, 0x30(%r12)
movl $0x9, %eax
leaq 0x80(%rsp), %r13
testq %rax, %rax
je 0x3820b
movq %rax, %r15
movq 0x60(%rsp), %rax
cmpq %r15, %rax
movq %r15, %r14
cmovbq %rax, %r14
testq %rax, %rax
cmoveq %r15, %r14
movq %r12, %rdi
movq %r13, %rsi
movq %r14, %rdx
callq *0x30(%rsp)
movq %rax, %rbx
testq %rax, %rax
je 0x381fa
movq 0x48(%rsp), %rax
testq %rax, %rax
je 0x381ea
movq %r12, %rdi
movq %r13, %rsi
movq %r14, %rdx
callq *%rax
addq %r14, %r13
movq %r15, %rax
subq %r14, %rax
addq %r14, 0x58(%rsp)
jmp 0x381fd
movq %r15, %rax
testq %rbx, %rbx
jne 0x381a2
testq %r15, %r15
jne 0x3854f
movb $0x0, 0x89(%rsp)
movl $0x49444552, %eax       # imm = 0x49444552
xorl 0x80(%rsp), %eax
movzbl 0x84(%rsp), %ecx
xorl $0x53, %ecx
orl %eax, %ecx
je 0x3824d
movq 0x8(%rsp), %rdi
callq 0x1f9a0
leaq 0x60a1f(%rip), %rsi     # 0x98c5e
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
jmp 0x38283
leaq 0x85(%rsp), %rdi
callq 0x1f710
movl %eax, %ebx
leal -0x7(%rbx), %eax
cmpl $-0x7, %eax
ja 0x382a2
movq 0x8(%rsp), %rdi
callq 0x1f9a0
leaq 0x60a15(%rip), %rsi     # 0x98c8a
movl $0x3, %edi
movl %ebx, %edx
xorl %eax, %eax
callq 0x23064
callq 0x1f810
movl $0x16, (%rax)
movl %ebp, %eax
addq $0x488, %rsp            # imm = 0x488
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rbx, 0x18(%rsp)
movq 0x8(%rsp), %rdi
callq 0x37fe6
leaq 0x30(%rsp), %r13
leaq 0x6070f(%rip), %r14     # 0x989cc
movq %r13, %rdi
callq 0x35e06
movl $0x2, %r15d
cmpl $-0x1, %eax
je 0x3844b
movl %eax, %r12d
cmpl $0xfc, %eax
je 0x38319
cmpl $0xfd, %r12d
jne 0x38344
movq %r13, %rdi
callq 0x35e97
cmpq $-0x1, %rax
je 0x3844b
movq %rax, %rbx
movq %r13, %rdi
callq 0x35e06
cmpl $-0x1, %eax
je 0x3844b
movl %eax, %r12d
imulq $0x3e8, %rbx, %rbp      # imm = 0x3E8
jmp 0x3834b
movq %r13, %rdi
callq 0x35f40
cmpq $-0x1, %rax
je 0x3844b
movq %rax, %rbp
movq %r13, %rdi
callq 0x35e06
cmpl $-0x1, %eax
je 0x3844b
movl %eax, %r12d
jmp 0x3834b
movq $-0x1, %rbp
cmpl $0xff, %r12d
je 0x3839f
movq %r13, %rdi
cmpl $0xfe, %r12d
jne 0x383aa
xorl %esi, %esi
callq 0x36088
cmpl $-0x1, %eax
je 0x3844b
leaq 0x91c31(%rip), %rcx     # 0xc9fa8
movl 0x480(%rcx), %edx
cmpl %edx, %eax
jae 0x3856c
movl %eax, %eax
shlq $0x6, %rax
addq 0x10(%rcx), %rax
movq %rax, 0x10(%rsp)
movl $0x3, %r15d
jmp 0x3844b
movl $0x4, %r15d
jmp 0x3844b
xorl %esi, %esi
callq 0x36973
testq %rax, %rax
je 0x38444
movq %rax, %r14
movl %r12d, %edi
movq %r13, %rsi
callq 0x377d0
testq %rax, %rax
je 0x38444
movq %rax, %rbx
leaq 0x91bd1(%rip), %rax     # 0xc9fa8
cmpq $0x0, 0x650(%rax)
sete %al
cmpq $-0x1, %rbp
setne %cl
cmpq 0x20(%rsp), %rbp
setl %dl
andb %cl, %dl
andb %al, %dl
cmpb $0x1, %dl
jne 0x38412
movq %r14, %rdi
callq 0x30834
movq %rbx, %rdi
callq 0x30834
movl $0x3, %r15d
jmp 0x38444
movq 0x10(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x314ef
cmpq $-0x1, %rbp
je 0x38439
movq %r15, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0x32732
movq %r14, %rdi
callq 0x30834
xorl %r15d, %r15d
leaq 0x60581(%rip), %r14     # 0x989cc
cmpl $0x4, %r15d
ja 0x38510
movl %r15d, %eax
movslq (%r14,%rax,4), %rax
addq %r14, %rax
jmpq *%rax
cmpl $0x5, 0x18(%rsp)
jl 0x3852d
leaq 0x91b35(%rip), %rax     # 0xc9fa8
cmpl $0x0, 0x594(%rax)
je 0x3852d
movl $0x8, %eax
leaq 0x28(%rsp), %r14
leaq 0x30(%rsp), %r15
movq 0x20(%r15), %rbp
movq %rax, %r13
testq %rax, %rax
je 0x384f8
movq 0x60(%rsp), %rax
cmpq %r13, %rax
movq %r13, %r12
cmovbq %rax, %r12
testq %rax, %rax
cmoveq %r13, %r12
movq %r15, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *0x30(%rsp)
movq %rax, %rbx
testq %rax, %rax
je 0x384eb
movq 0x48(%rsp), %rax
testq %rax, %rax
je 0x384db
movq %r15, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq *%rax
addq %r12, %r14
movq %r13, %rax
subq %r12, %rax
addq %r12, 0x58(%rsp)
jmp 0x384ee
movq %r13, %rax
testq %rbx, %rbx
jne 0x38493
testq %r13, %r13
jne 0x3854f
movq 0x28(%rsp), %rax
testq %rax, %rax
je 0x38515
cmpq %rbp, %rax
je 0x38528
leaq 0x60845(%rip), %rsi     # 0x98d53
jmp 0x38556
jmp 0x3828e
leaq 0x607f8(%rip), %rsi     # 0x98d14
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
testq %r13, %r13
jne 0x3854f
movq 0x8(%rsp), %rdi
callq 0x1f9a0
leaq 0x91a6a(%rip), %rax     # 0xc9fa8
movl $0x0, 0x2f0(%rax)
xorl %ebp, %ebp
jmp 0x3828e
leaq 0x6081f(%rip), %rsi     # 0x98d75
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
movl $0x1, %edi
callq 0x1f2b0
leaq 0x6073a(%rip), %rsi     # 0x98cad
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
jmp 0x38562