主要是挖个坑。候补(代码还没看完。。)
https://github.com/antirez/redis/tree/5.0
一、Redis保存持久化文件
二、Redis启动加载持久化文件
src/server.c loadDataFromDisk函数 AOF 和 RDB 通过不同的方式加载
1 /* Function called at startup to load RDB or AOF file in memory. */ 2 void loadDataFromDisk(void) { 3 long long start = ustime(); 4 if (server.aof_state == AOF_ON) { 5 if (loadAppendOnlyFile(server.aof_filename) == C_OK) 6 serverLog(LL_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000); 7 } else { 8 rdbSaveInfo rsi = RDB_SAVE_INFO_INIT; 9 if (rdbLoad(server.rdb_filename,&rsi) == C_OK) { 10 serverLog(LL_NOTICE,"DB loaded from disk: %.3f seconds", 11 (float)(ustime()-start)/1000000); 12 13 /* Restore the replication ID / offset from the RDB file. */ 14 if (server.masterhost && 15 rsi.repl_id_is_set && 16 rsi.repl_offset != -1 && 17 /* Note that older implementations may save a repl_stream_db 18 * of -1 inside the RDB file in a wrong way, see more information 19 * in function rdbPopulateSaveInfo. */ 20 rsi.repl_stream_db != -1) 21 { 22 memcpy(server.replid,rsi.repl_id,sizeof(server.replid)); 23 server.master_repl_offset = rsi.repl_offset; 24 /* If we are a slave, create a cached master from this 25 * information, in order to allow partial resynchronizations 26 * with masters. */ 27 replicationCacheMasterUsingMyself(); 28 selectDb(server.cached_master,rsi.repl_stream_db); 29 } 30 } else if (errno != ENOENT) { 31 serverLog(LL_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno)); 32 exit(1); 33 } 34 } 35 }
AOF路线
src/aof.c loadAppendOnlyFile 主要通过检查是否含有RDB前缀文件,如果有则加载,创建一个FakeClient一条条的执行AOF文件中的指令 。
特别地,事务会单独加载。
1 int loadAppendOnlyFile(char *filename) { 2 struct client *fakeClient; 3 FILE *fp = fopen(filename,"r"); 4 struct redis_stat sb; 5 int old_aof_state = server.aof_state; 6 long loops = 0; 7 off_t valid_up_to = 0; /* Offset of latest well-formed command loaded. */ 8 off_t valid_before_multi = 0; /* Offset before MULTI command loaded. */ 9 10 if (fp == NULL) { 11 serverLog(LL_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno)); 12 exit(1); 13 } 14 15 /* Handle a zero-length AOF file as a special case. An empty AOF file 16 * is a valid AOF because an empty server with AOF enabled will create 17 * a zero length file at startup, that will remain like that if no write 18 * operation is received. */ 19 if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) { 20 server.aof_current_size = 0; 21 fclose(fp); 22 return C_ERR; 23 } 24 25 /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI 26 * to the same file we're about to read. */ 27 server.aof_state = AOF_OFF; 28 29 fakeClient = createFakeClient(); 30 startLoading(fp); 31 32 /* Check if this AOF file has an RDB preamble. In that case we need to 33 * load the RDB file and later continue loading the AOF tail. */ 34 char sig[5]; /* "REDIS" */ 35 if (fread(sig,1,5,fp) != 5 || memcmp(sig,"REDIS",5) != 0) { 36 /* No RDB preamble, seek back at 0 offset. */ 37 if (fseek(fp,0,SEEK_SET) == -1) goto readerr; 38 } else { 39 /* RDB preamble. Pass loading the RDB functions. */ 40 rio rdb; 41 42 serverLog(LL_NOTICE,"Reading RDB preamble from AOF file..."); 43 if (fseek(fp,0,SEEK_SET) == -1) goto readerr; 44 rioInitWithFile(&rdb,fp); 45 if (rdbLoadRio(&rdb,NULL,1) != C_OK) { 46 serverLog(LL_WARNING,"Error reading the RDB preamble of the AOF file, AOF loading aborted"); 47 goto readerr; 48 } else { 49 serverLog(LL_NOTICE,"Reading the remaining AOF tail..."); 50 } 51 } 52 53 /* Read the actual AOF file, in REPL format, command by command. */ 54 while(1) { 55 int argc, j; 56 unsigned long len; 57 robj **argv; 58 char buf[128]; 59 sds argsds; 60 struct redisCommand *cmd; 61 62 /* Serve the clients from time to time */ 63 if (!(loops++ % 1000)) { 64 loadingProgress(ftello(fp)); 65 processEventsWhileBlocked(); 66 } 67 68 if (fgets(buf,sizeof(buf),fp) == NULL) { 69 if (feof(fp)) 70 break; 71 else 72 goto readerr; 73 } 74 if (buf[0] != '*') goto fmterr; 75 if (buf[1] == '