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)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM