https://www.cnblogs.com/jackhub/p/3830683.html
binlog文件的內容 log event
MySQL的binlog文件中記錄的是對數據庫的各種修改操作,用來表示修改操作的數據結構是Log event。不同的修改操作對應的不同的log event。比較常用的幾種log event有:Query event、Row event、Xid event等。其中Query event對應的是一條SQL語句,在DDL操作和STMT格式的binlog中用的比較多。Row event是個基礎類,它的派生類有Row insert event、Row update event、Row delete event三種,分別對應ROW格式binlog的增、改、刪操作。Xid event 對應的是支持事務的commit操作,對於不支持事務的commit操作,記錄的形式是Query event。其他還有一些event,比如Format log event、Rotate event等等,可以查看MySQL的官方文檔瞭解更多相關信息。log event的種類一直在增加,比如InnoSQL中新增的checkpoint event等。要MySQL本身就留有接口以便新增一個Log event,但是新增一個Log event時需要實現幾個必要的方法函數,比如print、write、get_code_type等。binlog文件的內容就是各種Log event的集合。
產生Log event
事務在執行DDL,或則update等操作時會記錄操作的event到線程的cache_mngr中。
1,執行DDL操作會在db的操作函數中記錄event,這些函數有:mysql_upgrade_db,mysql_alter_db,mysql_rm_db等。其他的DDL操作會調用函數write_bin_log來記錄binlog。
2,執行修改操作的DML語句會根據binlog格式的不同做不同的操作。若binlog格式是STMT,則記錄event的函數是binlog_query,該函數所做的事情是:
1,根據DML操作語句構造一個Query event:
Query_log_event qinfo(this,query_arg,query_len, ...)
2,將event寫入緩存中
mysql_bin_log.write(&qinfo)
調用binlog_query的函數有:mysql_insert,mysql_delete,mysql_update等.
3,若binlog格式是ROW,修改操作的DML語句記錄event的過程會調用binlog_log_row,每一條行的修改記錄一個Row event,所以調用binlog_log_row的都是對單個行進行修改的引擎層接口函數:ha_write_row、ha_update_row、ha_delete_row。
函數binlog_log_row會根據行操作的具體類型分別調用三個不同的函數:binlog_write_row、binlog_update_row、binlog_delete_row。
這三個函數的功能是:構造相應的Row event,並將行的數據寫入到Row event中。
具體過程是:
binlog_write_row
1,binlog_prepare_pending_rows_event(table, server_id, cols,...);
2,ev->add_row_data(row_data, len);
binlog_update_row
1,ev= binlog_prepare_pending_rows_event(table, server_id, cols,...);
2,ev->add_row_data(before_row, before_size)
ev->add_row_data(after_row, after_size)
binlog_delete_row
1,ev= binlog_prepare_pending_rows_event(table, server_id, cols,...);
2,ev->add_row_data(row_data, len);
新構造的Row event會在下一次記錄event的時候寫入到線程的緩存區中。
IO_CACHE
寫binlog的過程都是緩存寫,使用的緩存結構是IO_CACHE。
cache_mngr,cache_data
事務在執行過程中產生log event,這些Log event記錄在線程相關的一塊緩衝區中,每一個事務線程都有這樣一個緩存塊(前提是事務開啓了記錄binlog的功能),這塊緩存區的名稱是binlog_cache_mngr,結構如下:
class binlog_cache_mngr {
binlog_cache_data stmt_cache; //不支持事務的存儲引擎使用的binlog緩存區
binlog_cache_data trx_cache; //支持事務的存儲引擎使用的binlog緩存區
。。。
}
Log event保存在cache_mngr的緩存結構cache_data中,cache_data內有一個IO_CACHE緩存空間,Log event實際寫入到這個IO_CACHE中binlog_cache_data的結構如下:
class binlog_cache_data{
IO_CACHE cache_log;
。。。
}
事務執行完一個修改操作後,寫相應的Log event到線程緩存區的過程是:
1),獲得線程的cache_mngr指針:
cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
2),獲得cache_data緩存區的指針:
cache_data= cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
3),將event寫入到IO_CACHE中:
IO_CACHE *file= &cache_data->cache_log;
event->write(file);
寫binlog
一個事務在提交階段會將產生的log event寫入到外部binlog文件中。不同事務以串行的方式將log event寫入到外部binlog文件中,所以一個事務的所有log event在binlog文件中是連續的,中間不會插入任何其他事務的log event。MySQL整體是一個插件式的結構,binlog也是作爲一個引擎插件被上層調用,事務提交的時候MySQL上層會依次調用事務所有引擎的提交接口,binlog的提交接口第一個被調用,然後再調用其它引擎的提交接口。所以事務提交的時候是先寫binlog然後再進行底層引擎的提交過程(如InnoDB提交過程的寫redo log和刷髒頁)