// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x4c0, %rsp            # imm = 0x4C0
movq %rdi, -0x10(%rbp)
leaq 0xcd972(%rip), %rax     # 0x1138f8
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
callq 0x252e0
movq %rax, -0x440(%rbp)
movq -0x10(%rbp), %rdi
leaq 0x9ad2e(%rip), %rsi     # 0xe0cd3
callq 0x1fa70
movq %rax, -0x448(%rbp)
cmpq $0x0, %rax
jne 0x45fc3
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x463c3
movq -0x448(%rbp), %rsi
leaq -0x498(%rbp), %rdi
callq 0x75d70
leaq -0x14d(%rip), %rax      # 0x45e90
movq %rax, -0x480(%rbp)
leaq 0xcd90d(%rip), %rax     # 0x1138f8
movq 0x310(%rax), %rax
movq %rax, -0x468(%rbp)
leaq -0x430(%rbp), %rsi
leaq -0x498(%rbp), %rdi
movl $0x9, %edx
callq 0x42fc0
cmpq $0x0, %rax
jne 0x4601c
jmp 0x463a6
movb $0x0, -0x427(%rbp)
leaq -0x430(%rbp), %rdi
leaq 0x9ccef(%rip), %rsi     # 0xe2d20
movl $0x5, %edx
callq 0x1f950
cmpl $0x0, %eax
je 0x46076
movq -0x448(%rbp), %rdi
callq 0x1f9b0
movl $0x3, %edi
leaq 0x9ccce(%rip), %rsi     # 0xe2d26
movb $0x0, %al
callq 0x24fb0
callq 0x1f820
movl $0x16, (%rax)
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x463c3
leaq -0x430(%rbp), %rdi
addq $0x5, %rdi
callq 0x1f700
movl %eax, -0x1c(%rbp)
cmpl $0x1, -0x1c(%rbp)
jl 0x46095
cmpl $0x6, -0x1c(%rbp)
jle 0x460ce
movq -0x448(%rbp), %rdi
callq 0x1f9b0
movl -0x1c(%rbp), %edx
movl $0x3, %edi
leaq 0x9cca2(%rip), %rsi     # 0xe2d52
movb $0x0, %al
callq 0x24fb0
callq 0x1f820
movl $0x16, (%rax)
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x463c3
movq -0x448(%rbp), %rdi
callq 0x45d80
movq $-0x1, -0x438(%rbp)
leaq -0x498(%rbp), %rdi
callq 0x42f80
movl %eax, -0x18(%rbp)
cmpl $-0x1, %eax
jne 0x460fe
jmp 0x463a6
cmpl $0xfd, -0x18(%rbp)
jne 0x46152
leaq -0x498(%rbp), %rdi
callq 0x430a0
movq %rax, -0x438(%rbp)
cmpq $-0x1, %rax
jne 0x46125
jmp 0x463a6
leaq -0x498(%rbp), %rdi
callq 0x42f80
movl %eax, -0x18(%rbp)
cmpl $-0x1, %eax
jne 0x4613e
jmp 0x463a6
imulq $0x3e8, -0x438(%rbp), %rax # imm = 0x3E8
movq %rax, -0x438(%rbp)
jmp 0x46196
cmpl $0xfc, -0x18(%rbp)
jne 0x46194
leaq -0x498(%rbp), %rdi
callq 0x43110
movq %rax, -0x438(%rbp)
cmpq $-0x1, %rax
jne 0x46179
jmp 0x463a6
leaq -0x498(%rbp), %rdi
callq 0x42f80
movl %eax, -0x18(%rbp)
cmpl $-0x1, %eax
jne 0x46192
jmp 0x463a6
jmp 0x46194
jmp 0x46196
cmpl $0xff, -0x18(%rbp)
jne 0x461a4
jmp 0x462f4
cmpl $0xfe, -0x18(%rbp)
jne 0x46224
leaq -0x498(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x43260
movl %eax, -0x14(%rbp)
cmpl $-0x1, %eax
jne 0x461ca
jmp 0x463a6
movl -0x14(%rbp), %eax
leaq 0xcd724(%rip), %rcx     # 0x1138f8
cmpl 0x480(%rcx), %eax
jb 0x46206
leaq 0xcd715(%rip), %rax     # 0x1138f8
movl 0x480(%rax), %edx
movl $0x3, %edi
leaq 0x9cb80(%rip), %rsi     # 0xe2d75
movb $0x0, %al
callq 0x24fb0
movl $0x1, %edi
callq 0x1f2c0
leaq 0xcd6eb(%rip), %rax     # 0x1138f8
movq 0x10(%rax), %rax
movl -0x14(%rbp), %ecx
shlq $0x6, %rcx
addq %rcx, %rax
movq %rax, -0x28(%rbp)
jmp 0x460da
leaq -0x498(%rbp), %rdi
callq 0x43cc0
movq %rax, -0x4a0(%rbp)
cmpq $0x0, %rax
jne 0x46242
jmp 0x463a6
movl -0x18(%rbp), %edi
leaq -0x498(%rbp), %rsi
callq 0x450d0
movq %rax, -0x4a8(%rbp)
cmpq $0x0, %rax
jne 0x46263
jmp 0x463a6
leaq 0xcd68e(%rip), %rax     # 0x1138f8
cmpq $0x0, 0x650(%rax)
jne 0x462ab
cmpq $-0x1, -0x438(%rbp)
je 0x462ab
movq -0x438(%rbp), %rax
cmpq -0x440(%rbp), %rax
jge 0x462ab
movq -0x4a0(%rbp), %rdi
callq 0x3aaa0
movq -0x4a8(%rbp), %rdi
callq 0x3aaa0
jmp 0x460da
movq -0x28(%rbp), %rdi
movq -0x4a0(%rbp), %rsi
movq -0x4a8(%rbp), %rdx
callq 0x3c160
cmpq $-0x1, -0x438(%rbp)
je 0x462e3
movq -0x28(%rbp), %rdi
movq -0x4a0(%rbp), %rsi
movq -0x438(%rbp), %rdx
callq 0x3dda0
movq -0x4a0(%rbp), %rdi
callq 0x3aaa0
jmp 0x460da
cmpl $0x5, -0x1c(%rbp)
jl 0x4638c
leaq 0xcd5f3(%rip), %rax     # 0x1138f8
cmpl $0x0, 0x594(%rax)
je 0x4638c
movq -0x478(%rbp), %rax
movq %rax, -0x4b8(%rbp)
leaq -0x498(%rbp), %rdi
leaq -0x4b0(%rbp), %rsi
movl $0x8, %edx
callq 0x42fc0
cmpq $0x0, %rax
jne 0x4633c
jmp 0x463a6
cmpq $0x0, -0x4b0(%rbp)
jne 0x4635b
movl $0x3, %edi
leaq 0x9ca8a(%rip), %rsi     # 0xe2ddc
movb $0x0, %al
callq 0x24fb0
jmp 0x4638a
movq -0x4b0(%rbp), %rax
cmpq -0x4b8(%rbp), %rax
je 0x46388
movl $0x3, %edi
leaq 0x9caa4(%rip), %rsi     # 0xe2e1b
movb $0x0, %al
callq 0x24fb0
movl $0x1, %edi
callq 0x1f2c0
jmp 0x4638a
jmp 0x4638c
movq -0x448(%rbp), %rdi
callq 0x1f9b0
callq 0x45e70
movl $0x0, -0x4(%rbp)
jmp 0x463c3
movl $0x3, %edi
leaq 0x9ca8b(%rip), %rsi     # 0xe2e3d
movb $0x0, %al
callq 0x24fb0
movl $0x1, %edi
callq 0x1f2c0
movl -0x4(%rbp), %eax
addq $0x4c0, %rsp            # imm = 0x4C0
popq %rbp
retq
nop