<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        Redis源碼學(xué)習(xí)-AOF

        來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-09 14:46:24
        文檔

        Redis源碼學(xué)習(xí)-AOF

        Redis源碼學(xué)習(xí)-AOF:前言 網(wǎng)絡(luò)上也有許多介紹redis的AOF機(jī)制的文章,但是從宏觀上介紹aof的流程,沒(méi)有具體分析在AOF過(guò)程中涉及到的數(shù)據(jù)結(jié)構(gòu)和控制機(jī)制。昨晚特別看了2.8源碼,感覺(jué)源碼中的許多細(xì)節(jié)是值得細(xì)細(xì)深究的。特別是list *aof_rewrite_buf_blocks結(jié)構(gòu)。仔細(xì)看
        推薦度:
        導(dǎo)讀Redis源碼學(xué)習(xí)-AOF:前言 網(wǎng)絡(luò)上也有許多介紹redis的AOF機(jī)制的文章,但是從宏觀上介紹aof的流程,沒(méi)有具體分析在AOF過(guò)程中涉及到的數(shù)據(jù)結(jié)構(gòu)和控制機(jī)制。昨晚特別看了2.8源碼,感覺(jué)源碼中的許多細(xì)節(jié)是值得細(xì)細(xì)深究的。特別是list *aof_rewrite_buf_blocks結(jié)構(gòu)。仔細(xì)看

        前言 網(wǎng)絡(luò)上也有許多介紹redis的AOF機(jī)制的文章,但是從宏觀上介紹aof的流程,沒(méi)有具體分析在AOF過(guò)程中涉及到的數(shù)據(jù)結(jié)構(gòu)和控制機(jī)制。昨晚特別看了2.8源碼,感覺(jué)源碼中的許多細(xì)節(jié)是值得細(xì)細(xì)深究的。特別是list *aof_rewrite_buf_blocks結(jié)構(gòu)。仔細(xì)看源碼,會(huì)發(fā)

        前言

        網(wǎng)絡(luò)上也有許多介紹redis的AOF機(jī)制的文章,但是從宏觀上介紹aof的流程,沒(méi)有具體分析在AOF過(guò)程中涉及到的數(shù)據(jù)結(jié)構(gòu)和控制機(jī)制。昨晚特別看了2.8源碼,感覺(jué)源碼中的許多細(xì)節(jié)是值得細(xì)細(xì)深究的。特別是list *aof_rewrite_buf_blocks結(jié)構(gòu)。仔細(xì)看源碼,會(huì)發(fā)現(xiàn)原來(lái)看網(wǎng)絡(luò)文章多的到的領(lǐng)會(huì)是片面的,最好的學(xué)習(xí)還是得自己動(dòng)手...

        原文鏈接: http://blog.csdn.net/ordeder/article/details/39271543

        作者提及的AOF簡(jiǎn)化的流程為:
        * 1) The user calls BGREWRITEAOF
        * 2) Redis calls this function, that forks():
        * 2a) the child rewrite the append only file in a temp file.
        * 2b) the parent accumulates differences in server.aof_rewrite_buf.
        * 3) When the child finished '2a' exists.
        * 4) The parent will trap the exit code, if it's OK, will append the
        * data accumulated into server.aof_rewrite_buf into the temp file, and
        * finally will rename(2) the temp file in the actual file name.
        * The the new file is reopened as the new append only file. Profit!

        AOF流程

        依據(jù)源碼,AOF總體有一下操作:

        主要函數(shù):
        //函數(shù)1:將command寫入aof_buff
        void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
        //函數(shù)2:?jiǎn)?dòng)子進(jìn)程,子進(jìn)程用于刷一遍redis中的數(shù)據(jù)
        int rewriteAppendOnlyFileBackground(void);
        //函數(shù)3:刷一遍server.db[16],依次將對(duì)象寫入磁盤臨時(shí)文件tmpfile
        int rewriteAppendOnlyFile(char *filename);
        //函數(shù)4:將aof_buff內(nèi)容持久化
        void flushAppendOnlyFile(int force);
        //函數(shù)5:將server.aof_rewrite_buf_blocks中的內(nèi)容寫入tmpfile,并替換aof文件

        void backgroundRewriteDoneHandler(exitcode,bysignal);

        1 AOF日常命令append:
        1.1. Redis執(zhí)行文件事件:執(zhí)行用戶命令,并將該命令緩存于Server.aof_buf中{函數(shù)1}
        1.2. Redis執(zhí)行時(shí)間時(shí)間的ServerCron:依據(jù)參數(shù)server.aof_flush_postponed_start,{函數(shù)4}
        1.2.1. 將redisServer.aof_buf寫入文件Server.aof_fd。
        1.2.2. 該文件何時(shí)fsync到磁盤有三種機(jī)制:
        AOF_FSYNC_EVERYSEC 每秒調(diào)用fsync
        AOF_FSYNC_ALWAYS 寫文件后立即調(diào)用fsync
        其他 聽系統(tǒng)的

        2 AOF日志簡(jiǎn)化操作:
        2.1. Redis執(zhí)行時(shí)間時(shí)間的ServerCron:{函數(shù)2-3}
        2.1.1. 開啟后臺(tái)AOF進(jìn)程,依據(jù)redis內(nèi)存數(shù)據(jù)(redis.db[16]),生成可重建數(shù)據(jù)庫(kù)的命令集,并寫入tmpfile臨時(shí)文件
        2.2. Redis執(zhí)行文件事件:
        執(zhí)行用戶命令時(shí),{函數(shù)1}
        2.2.1. 將該命令緩存于redisServer.aof_buf;
        2.2.2. 同時(shí)將該命令緩存于server.aof_rewrite_buf_blocks
        2.3. Redis執(zhí)行時(shí)間時(shí)間的ServerCron:
        2.3.1 {函數(shù)4}在aof子進(jìn)程還未結(jié)束期間,步驟 1.2 照常執(zhí)行,將aof_buf寫入aof_fd(該干嘛干嘛)
        2.3.2 wait3發(fā)現(xiàn)aof子進(jìn)程結(jié)束,那么:{函數(shù)5}
        2.3.2.1 將server.aof_rewrite_buf_blocks中的內(nèi)容寫入tmpfile中
        2.3.2.2 用tmpfile替換原有aof文件,并重置Server.aof_fd

        函數(shù)和數(shù)據(jù)間關(guān)系如下圖所示:

        \

        源碼

        struct redisServer{
        	...
         /* AOF persistence */
         int aof_state; /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */
         int aof_fsync; /* Kind of fsync() policy (每個(gè)操作|每秒|緩沖區(qū)滿)*/
         char *aof_filename; /* Name of the AOF file */
         int aof_no_fsync_on_rewrite; /* Don't fsync if a rewrite is in prog. */
         int aof_rewrite_perc; /* Rewrite AOF if % growth is > M and... */
         off_t aof_rewrite_min_size; /* the AOF file is at least N bytes. */
         off_t aof_rewrite_base_size; /* AOF size on latest startup or rewrite. */
         off_t aof_current_size; /* AOF current size. */
         int aof_rewrite_scheduled; /* Rewrite once BGSAVE terminates. 是否需要開啟后臺(tái)aof子進(jìn)程*/
         pid_t aof_child_pid; /* PID if rewriting process */
         list *aof_rewrite_buf_blocks; /* Hold changes during an AOF rewrite. 在aof bgsave期間redis執(zhí)行的命令將存儲(chǔ)到aof_rewrite_buf_blocks,當(dāng)然aof_buf還是要照常使用的,二者不沖突*/
         sds aof_buf; /* AOF buffer, written before entering the event loop */
         int aof_fd; /* File descriptor of currently selected AOF file */
         int aof_selected_db; /* Currently selected DB in AOF */
         time_t aof_flush_postponed_start; /* UNIX time of postponed AOF flush */
         time_t aof_last_fsync; /* UNIX time of last fsync() */
         time_t aof_rewrite_time_last; /* Time used by last AOF rewrite run. */
         time_t aof_rewrite_time_start; /* Current AOF rewrite start time. */
         int aof_lastbgrewrite_status; /* REDIS_OK or REDIS_ERR */
         unsigned long aof_delayed_fsync; /* delayed AOF fsync() counter */
         int aof_rewrite_incremental_fsync;/* fsync incrementally while rewriting? */
        	...
        }
        
        /////////////////////////////////////////////////////////////////////////////////
        /* Call() is the core of Redis execution of a command */
        void call(redisClient *c, int flags) {
         long long dirty, start = ustime(), duration;
         int client_old_flags = c->flags;
        	
        	...
        	
        	 /* 執(zhí)行用戶命令 */
         c->flags &= ~(REDIS_FORCE_AOF|REDIS_FORCE_REPL);
         redisOpArrayInit(&server.also_propagate);
         dirty = server.dirty;
         c->cmd->proc(c);
         dirty = server.dirty-dirty;
         duration = ustime()-start;
        	
        	...
        	
        	/* 將用戶命令進(jìn)行AOF備份 */
         if (flags & REDIS_CALL_PROPAGATE) {
         int flags = REDIS_PROPAGATE_NONE;
        
         if (c->flags & REDIS_FORCE_REPL) flags |= REDIS_PROPAGATE_REPL;
         if (c->flags & REDIS_FORCE_AOF) flags |= REDIS_PROPAGATE_AOF;
         if (dirty)
         flags |= (REDIS_PROPAGATE_REPL | REDIS_PROPAGATE_AOF);
         if (flags != REDIS_PROPAGATE_NONE)
         propagate(c->cmd,c->db->id,c->argv,c->argc,flags);
         }
        }
        
        void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc,
         int flags)
        {
         if (server.aof_state != REDIS_AOF_OFF && flags & REDIS_PROPAGATE_AOF)
         feedAppendOnlyFile(cmd,dbid,argv,argc);
         if (flags & REDIS_PROPAGATE_REPL)
         replicationFeedSlaves(server.slaves,dbid,argv,argc);
        }
        
        void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
         sds buf = sdsempty();
         robj *tmpargv[3];
        
         /* 如果當(dāng)前操作的dict和前一次操作的dict不同,
        	那么redis要在aof中添加一條:select命令,選擇當(dāng)前dict */
         if (dictid != server.aof_selected_db) {
         char seldb[64];
        
         snprintf(seldb,sizeof(seldb),"%d",dictid);
         buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
         (unsigned long)strlen(seldb),seldb);
         server.aof_selected_db = dictid;
         }
        	//依據(jù)不同的命令,進(jìn)行字符畫處理,并將結(jié)果寫入臨時(shí)的buff中
         if (cmd->proc == expireCommand || cmd->proc == pexpireCommand ||
         cmd->proc == expireatCommand) {
         /* Translate EXPIRE/PEXPIRE/EXPIREAT into PEXPIREAT */
         buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);
         } else if (cmd->proc == setexCommand || cmd->proc == psetexCommand) {
         /* Translate SETEX/PSETEX to SET and PEXPIREAT */
         tmpargv[0] = createStringObject("SET",3);
         tmpargv[1] = argv[1];
         tmpargv[2] = argv[3];
         buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
         decrRefCount(tmpargv[0]);
         buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);
         } else {
         /* All the other commands don't need translation or need the
         * same translation already operated in the command vector
         * for the replication itself. */
         buf = catAppendOnlyGenericCommand(buf,argc,argv);
         }
        
         /* Append to the AOF buffer. This will be flushed on disk just before
         * of re-entering the event loop, so before the client will get a
         * positive reply about the operation performed. */
        	//如果用戶開啟的AOF,那么將當(dāng)前命令的buff Append到server.aof_buf緩沖的尾部
         if (server.aof_state == REDIS_AOF_ON)
         server.aof_buf = sdscatlen(server.aof_buf,buf,sdslen(buf));
        
         /* If a background append only file rewriting is in progress we want to
         * accumulate the differences between the child DB and the current one
         * in a buffer, so that when the child process will do its work we
         * can append the differences to the new append only file. */
        	 //如果當(dāng)前有子進(jìn)程正在進(jìn)行AOF日志的重構(gòu)(即掃描redis數(shù)據(jù)庫(kù),依據(jù)數(shù)據(jù)構(gòu)建日志)
        	 //那么將當(dāng)前命令的buff添加到server.aof_rewrite_buf_blocks內(nèi)存中(該部分內(nèi)存
        	 //專門記錄在重構(gòu)AOF期間redis處理的操作)
         if (server.aof_child_pid != -1)
         aofRewriteBufferAppend((unsigned char*)buf,sdslen(buf));
        
         sdsfree(buf);
        }
        
        ////////////////////////////////////////////////////////////////////////////////////////
        
        int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
         int j;
         REDIS_NOTUSED(eventLoop);
         REDIS_NOTUSED(id);
         REDIS_NOTUSED(clientData);
        
         /* Software watchdog: deliver the SIGALRM that will reach the signal
         * handler if we don't return here fast enough. */
         if (server.watchdog_period) watchdogScheduleSignal(server.watchdog_period);
        
         /* We take a cached value of the unix time in the global state because
         * with virtual memory and aging there is to store the current time
         * in objects at every object access, and accuracy is not needed.
         * To access a global var is faster than calling time(NULL) */
        	 //緩存系統(tǒng)時(shí)間...
         server.unixtime = time(NULL);
         server.mstime = mstime();
        
         ...
        
         /* Start a scheduled AOF rewrite if this was requested by the user while
         * a BGSAVE was in progress. */
        	 //開啟AOF日志重建的子進(jìn)程(簡(jiǎn)化日志)
        	 //后臺(tái)AOF子進(jìn)程通過(guò)掃描redis.db[16]數(shù)據(jù),生成可重建當(dāng)前數(shù)據(jù)庫(kù)的命令,
        	 //并寫入臨時(shí)文件tmpfile
         if (server.rdb_child_pid == -1 && server.aof_child_pid == -1 &&
         server.aof_rewrite_scheduled)
         {
         	//AOF
         rewriteAppendOnlyFileBackground();
         }
        
         /* Check if a background saving or AOF rewrite in progress terminated. */
        	//后臺(tái)AOF進(jìn)程結(jié)束:將在后臺(tái)AOF子進(jìn)程構(gòu)建AOF日志期間redis執(zhí)行的新命令
        	//(記錄于server.aof_rewrite_buf_blocks)append 到后臺(tái)子進(jìn)程構(gòu)建的tmpfile中
        	//最后將tmpfile重名為server.aof_filename 替換原有AOF
         if (server.rdb_child_pid != -1 || server.aof_child_pid != -1) {
         int statloc;
         pid_t pid;
        
         if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
         int exitcode = WEXITSTATUS(statloc);
         int bysignal = 0;
         
         if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);
        
         if (pid == server.rdb_child_pid) {
         backgroundSaveDoneHandler(exitcode,bysignal);
         } else if (pid == server.aof_child_pid) {
         backgroundRewriteDoneHandler(exitcode,bysignal);
         } else {
         redisLog(REDIS_WARNING,
         "Warning, detected child with unmatched pid: %ld",
         (long)pid);
         }
         updateDictResizePolicy();
         }
         } else {
         /* If there is not a background saving/rewrite in progress check if
         * we have to save/rewrite now */
         //沒(méi)有后臺(tái)子進(jìn)程在跑,那么檢查是否要開啟一個(gè)AOF或者RDB的子進(jìn)程。。
        	 ...
         }
        
         /* If we postponed an AOF buffer flush, let's try to do it every time the
         * cron function is called. */
        	 //將server.aof_buf(緩存redis最近執(zhí)行過(guò)的命名)flush到磁盤AOF文件中
        	 //flush的策略有如下:
        	 //每個(gè)操作,調(diào)用fync將命令持久化
        	 //間隔1秒,調(diào)用fync將aof_buf持久化
        	 //從不調(diào)用fync,由系統(tǒng)自行安排時(shí)機(jī)
         if (server.aof_flush_postponed_start) flushAppendOnlyFile(0);
        
         ...
        
         server.cronloops++;
         return 1000/server.hz;
        }
        
        /* This is how rewriting of the append only file in background works:
         *
         * 1) The user calls BGREWRITEAOF
         * 2) Redis calls this function, that forks():
         * 2a) the child rewrite the append only file in a temp file.
         * 2b) the parent accumulates differences in server.aof_rewrite_buf.
         * 3) When the child finished '2a' exists.
         * 4) The parent will trap the exit code, if it's OK, will append the
         * data accumulated into server.aof_rewrite_buf into the temp file, and
         * finally will rename(2) the temp file in the actual file name.
         * The the new file is reopened as the new append only file. Profit!
         */
        int rewriteAppendOnlyFileBackground(void) {
         pid_t childpid;
         long long start;
        
         if (server.aof_child_pid != -1) return REDIS_ERR;
         start = ustime();
         if ((childpid = fork()) == 0) {
         char tmpfile[256];
        
         /* Child */
         closeListeningSockets(0);
         redisSetProcTitle("redis-aof-rewrite");
         snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
         if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
         size_t private_dirty = zmalloc_get_private_dirty();
        
         if (private_dirty) {
         redisLog(REDIS_NOTICE,
         "AOF rewrite: %zu MB of memory used by copy-on-write",
         private_dirty/(1024*1024));
         }
         exitFromChild(0);
         } else {
         exitFromChild(1);
         }
         } else {
         /* Parent */
         server.stat_fork_time = ustime()-start;
         if (childpid == -1) {
         redisLog(REDIS_WARNING,
         "Can't rewrite append only file in background: fork: %s",
         strerror(errno));
         return REDIS_ERR;
         }
         redisLog(REDIS_NOTICE,
         "Background append only file rewriting started by pid %d",childpid);
         server.aof_rewrite_scheduled = 0;
         server.aof_rewrite_time_start = time(NULL);
         server.aof_child_pid = childpid;
         updateDictResizePolicy();
         /* We set appendseldb to -1 in order to force the next call to the
         * feedAppendOnlyFile() to issue a SELECT command, so the differences
         * accumulated by the parent into server.aof_rewrite_buf will start
         * with a SELECT statement and it will be safe to merge. */
         server.aof_selected_db = -1;
         replicationScriptCacheFlush();
         return REDIS_OK;
         }
         return REDIS_OK; /* unreached */
        }
        
        /* 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 REDIS_AOF_REWRITE_ITEMS_PER_CMD items per time
         * are inserted using a single command. */
        int rewriteAppendOnlyFile(char *filename) {
         dictIterator *di = NULL;
         dictEntry *de;
         rio aof;
         FILE *fp;
         char tmpfile[256];
         int j;
         long long now = mstime();
        
         /* Note that we have to use a different temp name here compared to the
         * one used by rewriteAppendOnlyFileBackground() function. */
         snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
         fp = fopen(tmpfile,"w");
         if (!fp) {
         redisLog(REDIS_WARNING, "Opening the temp file for AOF rewrite in rewriteAppendOnlyFile(): %s", strerror(errno));
         return REDIS_ERR;
         }
        
         rioInitWithFile(&aof,fp);
         if (server.aof_rewrite_incremental_fsync)
         rioSetAutoSync(&aof,REDIS_AOF_AUTOSYNC_BYTES);
         for (j = 0; j < server.dbnum; j++) {
        	//添加一條定位dict的命令
         char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
         redisDb *db = server.db+j;
         dict *d = db->dict;
         if (dictSize(d) == 0) continue;
         di = dictGetSafeIterator(d);
         if (!di) {
         fclose(fp);
         return REDIS_ERR;
         }
        
         /* SELECT the new DB */
         if (rioWrite(&aof,selectcmd,sizeof(selectcmd)-1) == 0) goto werr;
         if (rioWriteBulkLongLong(&aof,j) == 0) goto werr;
        
         /* Iterate this DB writing every entry */
         while((de = dictNext(di)) != NULL) {
         sds keystr;
         robj key, *o;
         long long expiretime;
        
         keystr = dictGetKey(de);
         o = dictGetVal(de);
         initStaticStringObject(key,keystr);
        
         expiretime = getExpire(db,&key);
        
         /* If this key is already expired skip it */
         if (expiretime != -1 && expiretime < now) continue;
        
         /* Save the key and associated value */
         if (o->type == REDIS_STRING) {
         /* Emit a SET command */
         char cmd[]="*3\r\n$3\r\nSET\r\n";
         if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr;
         /* Key and value */
         if (rioWriteBulkObject(&aof,&key) == 0) goto werr;
         if (rioWriteBulkObject(&aof,o) == 0) goto werr;
         } else if (o->type == REDIS_LIST) {
         if (rewriteListObject(&aof,&key,o) == 0) goto werr;
         } else if (o->type == REDIS_SET) {
         if (rewriteSetObject(&aof,&key,o) == 0) goto werr;
         } else if (o->type == REDIS_ZSET) {
         if (rewriteSortedSetObject(&aof,&key,o) == 0) goto werr;
         } else if (o->type == REDIS_HASH) {
         if (rewriteHashObject(&aof,&key,o) == 0) goto werr;
         } else {
         redisPanic("Unknown object type");
         }
         /* Save the expire time */
         if (expiretime != -1) {
         char cmd[]="*3\r\n$9\r\nPEXPIREAT\r\n";
         if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr;
         if (rioWriteBulkObject(&aof,&key) == 0) goto werr;
         if (rioWriteBulkLongLong(&aof,expiretime) == 0) goto werr;
         }
         }
         dictReleaseIterator(di);
         }
        
         /* Make sure data will not remain on the OS's output buffers */
         fflush(fp);
         aof_fsync(fileno(fp));
         fclose(fp);
        
         /* Use RENAME to make sure the DB file is changed atomically only
         * if the generate DB file is ok. */
         if (rename(tmpfile,filename) == -1) {
         redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
         unlink(tmpfile);
         return REDIS_ERR;
         }
         redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
         return REDIS_OK;
        
        werr:
         fclose(fp);
         unlink(tmpfile);
         redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
         if (di) dictReleaseIterator(di);
         return REDIS_ERR;
        }
        
        /* Write the append only file buffer on disk.
         *
         * Since we are required to write the AOF before replying to the client,
         * and the only way the client socket can get a write is entering when the
         * the event loop, we accumulate all the AOF writes in a memory
         * buffer and write it on disk using this function just before entering
         * the event loop again.
         *
         * About the 'force' argument:
         *
         * When the fsync policy is set to 'everysec' we may delay the flush if there
         * is still an fsync() going on in the background thread, since for instance
         * on Linux write(2) will be blocked by the background fsync anyway.
         * When this happens we remember that there is some aof buffer to be
         * flushed ASAP, and will try to do that in the serverCron() function.
         *
         * However if force is set to 1 we'll write regardless of the background
         * fsync. */
        void flushAppendOnlyFile(int force) {
         ssize_t nwritten;
         int sync_in_progress = 0;
        
         if (sdslen(server.aof_buf) == 0) return;
        
         if (server.aof_fsync == AOF_FSYNC_EVERYSEC)
         sync_in_progress = bioPendingJobsOfType(REDIS_BIO_AOF_FSYNC) != 0;
        
        	//判定是否該開始將server.aof_buff中緩存的命令flush到server.aof_fd文件的寫緩沖中
         if (server.aof_fsync == AOF_FSYNC_EVERYSEC && !force) {
         /* With this append fsync policy we do background fsyncing.
         * If the fsync is still in progress we can try to delay
         * the write for a couple of seconds. */
         if (sync_in_progress) {
         if (server.aof_flush_postponed_start == 0) {
         /* No previous write postponinig, remember that we are
         * postponing the flush and return. */
         server.aof_flush_postponed_start = server.unixtime;
         return;
         } else if (server.unixtime - server.aof_flush_postponed_start < 2) {
         /* We were already waiting for fsync to finish, but for less
         * than two seconds this is still ok. Postpone again. */
         return;
         }
         /* Otherwise fall trough, and go write since we can't wait
         * over two seconds. */
         server.aof_delayed_fsync++;
         redisLog(REDIS_NOTICE,"Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.");
         }
         }
         /* If you are following this code path, then we are going to write so
         * set reset the postponed flush sentinel to zero. */
         server.aof_flush_postponed_start = 0;	
        
         /* We want to perform a single write. This should be guaranteed atomic
         * at least if the filesystem we are writing is a real physical one.
         * While this will save us against the server being killed I don't think
         * there is much to do about the whole server stopping for power problems
         * or alike */
        	 //將redis最近執(zhí)行的一些命令(存于server.aof_buf)寫入文件(server.aof_fd)
        	 //注意,寫入文件并不能保證馬上寫入磁盤,因?yàn)檫@是帶緩沖的寫。關(guān)于何時(shí)將
        	 //文件寫緩沖中的命令fync到磁盤,這就要看用戶的設(shè)置:(見下文)
         nwritten = write(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));
         if (nwritten != (signed)sdslen(server.aof_buf)) {
         /* Ooops, we are in troubles. The best thing to do for now is
         * aborting instead of giving the illusion that everything is
         * working as expected. */
         ...
         exit(1);
         }
         server.aof_current_size += nwritten;	
        
         /* Re-use AOF buffer when it is small enough. The maximum comes from the
         * arena size of 4k minus some overhead (but is otherwise arbitrary). */
         if ((sdslen(server.aof_buf)+sdsavail(server.aof_buf)) < 4000) {
         sdsclear(server.aof_buf);
         } else {
         sdsfree(server.aof_buf);
         server.aof_buf = sdsempty();
         }
        
        	 //aof_no_fsync_on_rewrite : 該標(biāo)志位表示當(dāng)有aof或rdb子進(jìn)程時(shí),不進(jìn)行fsync操作
         if (server.aof_no_fsync_on_rewrite &&
         (server.aof_child_pid != -1 || server.rdb_child_pid != -1))
         return;
        
        	//fsync...
        	//每個(gè)操作,調(diào)用fync將命令持久化 [1]
        	//間隔1秒,調(diào)用fync將aof_buf持久化 [2]
        	//從不調(diào)用fync,由系統(tǒng)自行安排時(shí)機(jī)(fd的寫緩沖區(qū)滿了)[3]
        	
        	//【1】
        	//每個(gè)操作都需要將文件緩沖區(qū)的寫 buff sync到磁盤。從而保證每個(gè)redis操作在
        	//被redis執(zhí)行后,都能馬上持久化,安全性很高,就是磁盤寫的系統(tǒng)開銷有點(diǎn)大大
         if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
         /* aof_fsync is defined as fdatasync() for Linux in order to avoid
         * flushing metadata. */
         aof_fsync(server.aof_fd); /* Let's try to get this data on the disk */
         server.aof_last_fsync = server.unixtime;
         } 
        	//【2】
        	//每隔1s將文件緩沖區(qū)的寫緩沖區(qū)sync到磁盤
        	else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&
         server.unixtime > server.aof_last_fsync)) {
         if (!sync_in_progress) aof_background_fsync(server.aof_fd);
         server.aof_last_fsync = server.unixtime;
         }
        	
        	//【3】
        	//else fd的寫緩沖滿后會(huì)由系統(tǒng)安排執(zhí)行(聽天由命)
        }

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        Redis源碼學(xué)習(xí)-AOF

        Redis源碼學(xué)習(xí)-AOF:前言 網(wǎng)絡(luò)上也有許多介紹redis的AOF機(jī)制的文章,但是從宏觀上介紹aof的流程,沒(méi)有具體分析在AOF過(guò)程中涉及到的數(shù)據(jù)結(jié)構(gòu)和控制機(jī)制。昨晚特別看了2.8源碼,感覺(jué)源碼中的許多細(xì)節(jié)是值得細(xì)細(xì)深究的。特別是list *aof_rewrite_buf_blocks結(jié)構(gòu)。仔細(xì)看
        推薦度:
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 国产日韩久久免费影院| 一个人看的免费视频www在线高清动漫 | 亚洲第一精品福利| 中文在线免费不卡视频| 久久久无码精品亚洲日韩软件 | 国产精品69白浆在线观看免费 | 亚洲aⅴ无码专区在线观看春色| 最近中文字幕mv免费高清电影| 亚洲一区二区影视| 嫩草视频在线免费观看| 亚洲精品无码AV人在线播放| 视频免费在线观看| 免费v片在线观看品善网| 污污免费在线观看| 亚洲香蕉网久久综合影视| 麻豆一区二区三区蜜桃免费| 永久免费av无码不卡在线观看| 中文字幕亚洲男人的天堂网络| 免费无码一区二区三区蜜桃大| 国产成人 亚洲欧洲| 午夜免费福利在线观看| 色屁屁www影院免费观看视频 | 国产片免费福利片永久| 亚洲人成777在线播放| 日本免费中文字幕| 中文字幕精品亚洲无线码一区| 国产亚洲精品精品精品| 亚洲精品无码永久在线观看你懂的 | 19禁啪啪无遮挡免费网站| 久久国产亚洲精品麻豆| 114级毛片免费观看| 亚洲爆乳少妇无码激情| 成年女人看片免费视频播放器| 国产成人亚洲午夜电影| 久久亚洲免费视频| 啦啦啦www免费视频| 抽搐一进一出gif免费视频| 77777午夜亚洲| 亚洲精品无码久久久久去q| 成年女人色毛片免费看| 男人天堂免费视频|