zoukankan      html  css  js  c++  java
  • REdis AOF文件结构分析

    REdis-4.0之前的AOF文件没有文件头,而从REdis-4.0开始AOF文件带有一个文件头,文件头格式和RDB文件头相同。

    REdis-4.0版本,如果开启aof-use-rdb-preamble(值为yes5.0默认为yes4.0默认为no),则AOF文件内容由三部分组成:

    1) 文件头(和RDB文件头格式相同)

    2) RDB格式的二进制数据段

    3) AOF格式的文本数据段

     

    AOF格式的文本数据段和之前版本的保持相同,如下图所示:

     

     

    从REdis-4.0开始,AOF有文件头,目的是支持同时加载RDB格式和AOF格式数据。AOF文件头和RDB文件头基本相同,但RDB文件头多了三个字段。

    先看AOFRDB通用部分的文件头内容:

    1) 头5字节固定为REDIS

    2) 第6~9共四字节为RDB版本号

    3) 接下来为redis-ver和它的值,即redis版本

    4) 接着redis-bits和它的值,即redis的位数,值为3264

    5) 接着为ctime和它的值,值为当前时间戳

    6) 接着为used-mem和它的值

    7) 最后是aof-preamble和它的值,值为011表示RDB有效。

     

    RDB的文件头和AOF的文件基本相同,但RDB文件头aof-preamble之前多了如下三项:

    1) repl-stream-db

    2) repl-id

    3) repl-offset

     

    如果配置项appendonly值为no,则不会加载AOF文件,而是直接加载RDB文件,因为RDB文件保存了复制信息,所以进程重启可增量复制。而如果置项appendonly值为yes,因为AOF文件头不包含复制信息,所以只能全量复制。

     

    相关代码:

    /* Replay the append log file. 

     * On success C_OK is returned. On non fatal

     * error (the append only file is zero-length)

     * C_ERR is returned. On

     * fatal error an error message is logged

     * and the program exists. */

    int loadAppendOnlyFile(char *filename) // aof.c:673

    {

      /* Check if this AOF file has an RDB preamble. In that case we need to

       * load the RDB file and later continue loading the AOF tail. */

      char sig[5]; /* "REDIS" */

      if (fread(sig,1,5,fp) != 5 || memcmp(sig,"REDIS",5) != 0) // aof.c:707

      {

        /* No RDB preamble, seek back at 0 offset. */

        if (fseek(fp,0,SEEK_SET) == -1) goto readerr;

      } else {

        /* RDB preamble. Pass loading the RDB functions. */

        if (rdbLoadRio(&rdb,NULL,1) != C_OK) { // aof.c:717

          。。。。。。

        }

      }

    }

     

    /* Load an RDB file from the rio stream 'rdb'. 

     * On success C_OK is returned,

     * otherwise C_ERR is returned and 'errno' is set accordingly. */

    int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof) // rdb.c:1850

    {

      。。。。。。

    }

     

    /* Save a few default AUX fields with information about the RDB generated. */

    int rdbSaveInfoAuxFields(rio *rdb, int flags, rdbSaveInfo *rsi) // rdb.c:1071

    {

        int redis_bits = (sizeof(void*) == 8) ? 64 : 32;

        int aof_preamble = (flags & RDB_SAVE_AOF_PREAMBLE) != 0;

     

        /* Add a few fields about the state when the RDB was created. */

        if (rdbSaveAuxFieldStrStr(rdb,"redis-ver",REDIS_VERSION) == -1) return -1;

        if (rdbSaveAuxFieldStrInt(rdb,"redis-bits",redis_bits) == -1) return -1;

        if (rdbSaveAuxFieldStrInt(rdb,"ctime",time(NULL)) == -1) return -1;

        if (rdbSaveAuxFieldStrInt(rdb,"used-mem",zmalloc_used_memory()) == -1) return -1;

     

        /* Handle saving options that generate aux fields. */

        // 如果是AOF,传入的rsi为NULL,

        // 因此不会记录以下三项辅助数据

        // 可参见函数rewriteAppendOnlyFile(aof.c:1344)的实现

        if (rsi) { // rdb.c:1082

            if (rdbSaveAuxFieldStrInt(rdb,"repl-stream-db",rsi->repl_stream_db)

                == -1) return -1;

            if (rdbSaveAuxFieldStrStr(rdb,"repl-id",server.replid)

                == -1) return -1;

            if (rdbSaveAuxFieldStrInt(rdb,"repl-offset",server.master_repl_offset)

                == -1) return -1;

        }

        if (rdbSaveAuxFieldStrInt(rdb,"aof-preamble",aof_preamble) == -1) return -1;

        return 1;

    }

     

    /* Produces a dump of the database in RDB format sending it to the specified

     * Redis I/O channel. On success C_OK is returned, otherwise C_ERR

     * is returned and part of the output, or all the output, can be

     * missing because of I/O errors.

     *

     * When the function returns C_ERR and if 'error' is not NULL, the

     * integer pointed by 'error' is set to the value of errno just after the I/O

     * error. */

    int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) // rdb.c:1102

    {

       if (rdbSaveInfoAuxFields(rdb,flags,rsi) == -1) goto werr; // rdb.c:1114

    }

     

    /* Write a sequence of commands able to fully rebuild the dataset into

     * "filename". Used both by REWRITEAOF and BGREWRITEAOF.

     *

     * In order to minimize the number of commands needed in the rewritten

     * log Redis uses variadic commands when possible, such as RPUSH, SADD

     * and ZADD. However at max AOF_REWRITE_ITEMS_PER_CMD items per time

     * are inserted using a single command. */

    int rewriteAppendOnlyFile(char *filename) // aof.c:1344

    {

      // 对于AOF,传入的第三个参数rsi值为NULL,

      // 因此不会记录复制信息,这样进程重启需要全量复制。

      if (rdbSaveRio(&aof,&error,RDB_SAVE_AOF_PREAMBLE,NULL) == C_ERR) { // aof.c:1367

    }

     

    启动时调用顺序:

       main(server.c:4003)

    -> loadDataFromDisk(server.c:3850)

    -> loadAppendOnlyFile(aof.c:673,当配置appendonly值为yes时)

    -> rdbLoadRio(rdb.c:1850)

     

     

     

  • 相关阅读:
    rsync命令详解
    Android Studio手动下载配置Gradle的方法
    "standard,singleTop,singleTask,singleInstance"-Android启动模式
    "Activity" 总结
    Android应用开发完全退出程序的通用方法
    SVN服务器使用(一)
    使用PyInstaller打包Python程序
    py2exe把python程序转换exe
    python 下载安装setuptools及pip应用
    Python的库和资源(转)
  • 原文地址:https://www.cnblogs.com/aquester/p/10529549.html
Copyright © 2011-2022 走看看