關於innodb mtr模塊

mtr (mini-transaction)微事務 node

mtr做用數據庫

 mtr模塊主要保證物理操做的一致性和原子性數組

 1 一致性:經過讀寫鎖來保證函數

 2 原子性:涉及到的物理更新,都記入redo日誌 測試

mtr什麼時候使用優化

1 文件管理:innodb表空間以segment,extent,page的方式管理,segment,extent,page的申請釋放,都會修改對應的控制信息。ui

   如fseg_alloc_free_page_general 申請頁this

   對錶空間加鎖     spa

latch = fil_space_get_latch(space, &flags);
mtr_x_lock(latch, mtr);

 fseg_alloc_free_page_low->fseg_alloc_free_page_low 寫控制信息並記入redo, 部分代碼以下debug

xdes_set_state(ret_descr, XDES_FSEG, mtr);
mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
flst_add_last(seg_inode + FSEG_FREE,
ret_descr + XDES_FLST_NODE, mtr);

2 B樹操做:(b樹包括索引和insert buffer)

  這裏的讀寫鎖有兩種:btree lock,page lock

  btree lock 爲了防止B樹分裂(不肯定,還有些疑問?)

  例如: 向彙集索引插入一行記錄,row_ins_clust_index_entry_low

  btree lock   

mtr_s_lock(dict_index_get_lock(index), &mtr);

 page lock

  獲取頁 buf_page_get_gen

......
rw_lock_x_lock_inline(&(block->lock), 0, file, line);
......
mtr_memo_push(mtr, block, fix_type);

 redo log     

trx_undo_page_report_insert  //先以redo log方式寫入undo log
page_cur_insert_rec_write_log//寫redo log

mtr中的鎖

  鎖均爲讀寫鎖,原子操做完成後當即釋放(mtr_commit),不須要事務結束時釋放

  遵照兩階段加鎖協議,不會死鎖。  

mtr中redo log

  mtr過程當中的redo log會存入本身的動態數組mtr->log中,mtr_commit時將mtr->log刷入 redo log buffer中。

一些思考

1 redo log buffer的 block的大小爲512,參見如下注釋

/** The next value should be smaller or equal to the smallest sector size used
on any disk. A log block is required to be a portion of disk which is written
so that if the start and the end of a block get written to disk, then the
whole block gets written. This should be true even in most cases of a crash:
if this fails for a log block, then it is equivalent to a media failure in the
log. */

#define OS_FILE_LOG_BLOCK_SIZE        512

 512 爲普通磁盤的扇區大小,對於SSD來講扇區大小爲4K

  OS_FILE_LOG_BLOCK_SIZE 應設置爲可調節參數,對SSD能夠設爲4096。若是不考慮binlog,能夠必定程度上提高寫redo的速度,加快commit。
  經測試改成

#define OS_FILE_LOG_BLOCK_SIZE     4096

  數據庫能夠正常使用

  注:以上測試數據庫需正常關閉,而後刪除log file文件

2 代碼優化

 mtr_memo_pop_all 中有以下代碼,這是一個O(n2)的查找遍歷 

offset = dyn_array_get_data_size(memo); 
    while (offset > 0) {
        offset -= sizeof(mtr_memo_slot_t); 
        slot = static_cast<mtr_memo_slot_t*>(dyn_array_get_element(memo, offset)); 
        mtr_memo_slot_release(mtr, slot);
    }
其中dyn_array_get_element是一個遍歷查找元素的過程。  

  改進後,是一個O(n)的遍歷 

element_size = sizeof(mtr_memo_slot_t); 
    block = dyn_array_get_first_block(memo); 
    while (block != NULL)
    {
        offset  = dyn_block_get_used(block); 
        while (offset != 0)        {
            offset -= element_size; 
            slot = static_cast<mtr_memo_slot_t*>((void*)(block->data + offset));
            mtr_memo_slot_release(mtr, slot);
        }   
        ut_ad(offset == 0);   
        block = dyn_array_get_next_block(memo, block);
    } 

 相似的代碼出如今如下函數中

mtr_memo_contains (debug)
mtr_memo_pop_all
mtr_memo_note_modifications
mtr_memo_release

  ps:以上分析基於5.6.10,最近看5.6.16這塊已優化。

相關文章
相關標籤/搜索