<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                在上一篇《[innodb源碼分析之重做日志結構](http://blog.csdn.net/yuanrxdu/article/details/42430187)》中我們知道redo log的基本結構和日志寫入步驟,那么redo log是怎么進行數據恢復的呢?在什么時候進行redo log的日志推演呢?redo log的推演只有在數據庫異常或者關閉后,數據庫重新啟動時會進行日志推演,將數據庫狀態恢復到關閉前的狀態。那么這個過程是怎么進行的呢?以下我們逐步來解析。 ## 1.recv_sys_t結構 innodb在MySQL啟動的時候,會對重做日志文件進行日志重做,重做日志是通過一個recv_sys_t的結構來進行數據恢 復和控制的。它的結構如下: ~~~ struct recv_sys_struct { mutex_t mutex; /*保護鎖*/ ibool apply_log_recs; /*正在應用log record到page中*/ ibool apply_batch_on; /*批量應用log record標志*/ dulint lsn; ulint last_log_buf_size; byte* last_block; /*恢復時最后的塊內存緩沖區*/ byte* last_block_buf_start; /*最后塊內存緩沖區的起始位置,因為last_block是512地址對齊的,需要這個變量記錄free的地址位置*/ byte* buf; /*從日志塊中讀取的重做日志信息數據*/ ulint len; /*buf有效的日志數據長度*/ dulint parse_start_lsn; /*開始parse的lsn*/ dulint scanned_lsn; /*已經掃描過的lsn序號*/ ulint scanned_checkpoint_no; /*恢復日志的checkpoint 序號*/ ulint recovered_offset; /*恢復位置的偏移量*/ dulint recovered_lsn; /*恢復的lsn位置*/ dulint limit_lsn; /*日志恢復最大的lsn,暫時在日志重做的過程沒有使用*/ ibool found_corrupt_log; /*是否開啟日志恢復診斷*/ log_group_t* archive_group; mem_heap_t* heap; /*recv sys的內存分配堆,用來管理恢復過程的內存占用*/ hash_table_t* addr_hash; /*recv_addr的hash表,以space id和page no為KEY*/ ulint n_addrs; /*addr_hash中包含recv_addr的個數*/ }; ~~~ 在這個結構中,比較復雜的是addr_hash這個哈希表,這個哈希表是用sapce_id和page_no作為hash key,里面存儲有恢復時對應的記錄內容。恢復日志在從日志文件中讀出后,進行解析成若干個recv_t并存儲在哈希表當中。在一個讀取解析周期過后,日志恢復會對hash表中的recv_t中的數據寫入到ibuf和page中。這里為什么要使用hash表呢?個人覺得是為了同一個page的數據批量進行恢復的緣故,這樣可以page減少隨機插入和修改。 以下是和這個過程相關的幾個數據結構: ~~~ /*對應頁的數據恢復操作集合*/ struct recv_addr_struct { ulint state; /*狀態,RECV_NOT_PROCESSED、RECV_BEING_PROCESSED、RECV_PROCESSED*/ ulint space; /*space的ID*/ ulint page_no; /*頁序號*/ UT_LIST_BASE_NODE_T(recv_t) rec_list; hash_node_t addr_hash; }; /*當前的記錄操作*/ struct recv_struct { byte type; /*log類型*/ ulint len; /*當前記錄數據長度*/ recv_data_t* data; /*當前的記錄數據list*/ dulint start_lsn; /*mtr起始lsn*/ dulint end_lsn; /*mtr結尾lns*/ UT_LIST_NODE_T(recv_t) rec_list; }; /*具體的數據體*/ struct recv_data_struct { recv_data_t* next; /*下一個recv_data_t,next的地址后面接了一大塊內存,用于存儲rec body*/ }; ~~~ 他們的內存關系結構圖如下: ![](https://box.kancloud.cn/2016-08-17_57b42163b8f66.jpg) ## 2.重做日志推演過程的LSN關系 除了這個恢復的哈希表以外,recv_sys_t中的各種LSN也是和日志恢復有非常緊密的關系。以下是各種lsn的解釋: ??parse_start_lsn ? ?本次日志重做恢復起始的lsn,如果是從checkpoint處開始恢復,等于checkpoint_lsn。 ??scanned_lsn ? ? ? ?在恢復過程,將恢復日志從log_sys->buf解析塊后存入recv_sys->buf的日志lsn. ? recovered_lsn ? ? ?已經將數據恢復到page中或者已經將日志操作存儲addr_hash當中的日志lsn; ? 在日志開始恢復時: ? ?parse_start_lsn = scanned_lsn = recovered_lsn = 檢查點的lsn。 ?在日志完成恢復時: ? ? ?parse_start_lsn = ?檢查點的lsn ? ? ?scanned_lsn = recovered_lsn = log_sys->lsn。 在日志推演過程中lsn大小關系如下: ![](https://box.kancloud.cn/2016-08-17_57b42163d98c0.jpg) ## 3.日志恢復的主要接口和流程 恢復日志主要的接口函數: ?recv_recovery_from_checkpoint_start ? ?從重做日志組內的最近的checkpoint開始恢復數據 ? recv_recovery_from_checkpoint_finish ?結束從重做日志組內的checkpoint的數據恢復操作 ? recv_recovery_from_archive_start ? ? ? ? ? 從歸檔日志文件中進行數據恢復 ? recv_recovery_from_archive_finish ? ? ? ? 結束從歸檔日志中的數據恢復操作 ? recv_reset_logs ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ??截取重做日志最后一段作為新的重做日志的起始位置,可能會丟失數據。 **重做日志恢復數據的流程(checkpoint方式)** ?1.當MySQL啟動的時候,先會從數據庫文件中讀取出上次保存最大的LSN。 ? 2.然后調用recv_recovery_from_checkpoint_start,并將最大的LSN作為參數傳入函數當中。 ? 3.函數會先最近建立checkpoint的日志組,并讀取出對應的checkpoint信息 ? 4.通過checkpoint lsn和傳入的最大LSN進行比較,如果相等,不進行日志恢復數據,如果不相等,進行日志恢復。 ? 5.在啟動恢復之前,先會同步各個日志組的archive歸檔狀態 ? 6.在開始恢復時,先會從日志文件中讀取2M的日志數據到log_sys->buf,然后對這2M的數據進行scan,校驗其合法性,而后將去掉block header的日志放入recv_sys->buf當中,這個過程稱為scan,會改變scanned lsn. ? 7.在對2M的日志數據scan后,innodb會對日志進行mtr操作解析,并執行相關的mtr函數。如果mtr合法,會將對應的記錄數據按space page_no作為KEY存入recv_sys->addr_hash當中。 ? 8.當對scan的日志數據進行mtr解析后,innodb對會調用recv_apply_hashed_log_recs對整個recv_sys->addr_hash進行掃描,并按照日志相對應的操作進行對應page的數據恢復。這個過程會改變recovered_lsn。 ? 9.如果完成第8步后,會再次從日志組文件中讀取2M數據,跳到步驟6繼續相對應的處理,直到日志文件沒有需要恢復的日志數據。 ? 10.innodb在恢復完成日志文件中的數據后,會調用recv_recovery_from_checkpoint_finish結束日志恢復操作,主要是釋放一些開辟的內存。并進行事務和binlog的處理。 上面過程的示意圖如下: ![](https://box.kancloud.cn/2016-08-17_57b42163f0f54.jpg)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看