写在前面
为了使代码好看, 很多时候 函数返回 True
表示失败, False
表示成功. 但还是得看个人习惯, 比如我更习惯在条件前面加个not或者!, 虽然会有额外的转换, 但是代码更易读.
可以结合debug信息一起分析(mysqld --debug).
本来准备继续写5.7.38的, 结果打开了8.31, 但是debug的是5.7.41的... 差别不大,不影响 -_-
如何找到commit代码
其实就是搜索commit关键字.
如果你看过mysql代码结构的话, 你会知道sql/sql_parse.cc 就是解析客户端发过来的sql的, 只需要在里面搜索commit就可以...
没看过的话, 可以使用grep搜索, 但是会很多....
代码语言:javascript复制grep -r 'COMMIT' | awk -F ':' '{print $1}' | sort | uniq | grep -vE 'storage|test|*.h'
也可以从mysql连接,到handler再到command处理... 有空了再说吧...
SQLCOM_COMMIT
看起来很多, 实际上就是:
1.判断空指针之类的
2.获取参数completion_type
3.事务提交(主要看这个)
4.释放锁
5.根据参数completion_type决定要不要开启新事务或者断开客户端连接.
completion_type值: 0(默认):不管 1:事务提交后,开启新事务 2:事务提交后,断开客户端连接.
代码语言:javascript复制case SQLCOM_COMMIT: {
assert(thd->lock == nullptr ||
thd->locked_tables_mode == LTM_LOCK_TABLES);
bool tx_chain =
(lex->tx_chain == TVL_YES ||
(thd->variables.completion_type == 1 && lex->tx_chain != TVL_NO));
bool tx_release =
(lex->tx_release == TVL_YES ||
(thd->variables.completion_type == 2 && lex->tx_release != TVL_NO));
if (trans_commit(thd)) goto error;
thd->mdl_context.release_transactional_locks();
/* Begin transaction with the same isolation level. */
if (tx_chain) {
if (trans_begin(thd)) goto error;
} else {
/* Reset the isolation level and access mode if no chaining
* transaction.*/
trans_reset_one_shot_chistics(thd);
}
/* Disconnect the current client connection. */
if (tx_release) thd->killed = THD::KILL_CONNECTION;
my_ok(thd);
break;
}
trans_commit
sql/transaction.cc
值列出关键信息,去掉断言,dbug之类的
代码语言:javascript复制trans_check_state(thd) /*检查状态*/
ha_commit_trans(thd, true, ignore_global_read_lock) /*主要看这个*/
/*重置事务状态*/
trans_track_end_trx(thd) /*事务结束*/
ha_commit_trans
sql/transaction.cc
不考虑slave. 不考虑太多的if情况,不考虑read_only情况,不考虑原子DDL
代码语言:javascript复制commit_owned_gtids(thd, all);
Transaction_ctx *trn_ctx = thd->get_transaction()
XID_STATE *xid_state = trn_ctx->xid_state(); /*使用xa控制内部两阶段提交*/
MDL_request mdl_request /*获取MDL锁对象*/
thd->mdl_context.acquire_lock(&mdl_request,thd->variables.lock_wait_timeout))/*获取锁失败就rollback*/
release_mdl = true
tc_log->prepare(thd, all) /*tc_log: Transaction Coordinator Log*/
xid_state->set_state(XID_STATE::XA_PREPARED) /*如果上一步不报错的话, 就设置xa状态为XA_PREPARED*/
tc_log->commit(thd, all)
thd->mdl_context.release_lock(mdl_request.ticket) /*释放锁*/
/*剩下的就是重置状态之类的了*/
主要看 tc_log->prepare 和 tc_log->commit
mysqld.cc启动的时候就有tc_log
代码语言:javascript复制/* sql/mysqld.cc init_server_components*/
if (total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log)) {
if (opt_bin_log)
tc_log = &mysql_bin_log; /* class MYSQL_BIN_LOG : public TC_LOG */
else
tc_log = &tc_log_mmap;
}
tc_log->prepare
binlog.cc MYSQL_BIN_LOG::prepare
代码语言:javascript复制ha_prepare_low(thd, all)
代码语言:javascript复制ha_prepare_low
binlog_prepare /*实际上啥也没做*/
innobase_xa_prepare /*storage/innobase/handler/ha_innodb.cc*/
debug信息
代码语言:javascript复制T@2: | | | | | | | >ha_prepare_low
T@2: | | | | | | | | >binlog_prepare
T@2: | | | | | | | | <binlog_prepare 1829
T@2: | | | | | | | | >innobase_xa_prepare /*自己加的*/
T@2: | | | | | | | | | >innobase_trx_init
T@2: | | | | | | | | | <innobase_trx_init 2628
T@2: | | | | | | | | <innobase_xa_prepare 17248
T@2: | | | | | | | <ha_prepare_low 2371
tc_log->commit
binlog.cc MYSQL_BIN_LOG::commit
代码语言:javascript复制ha_commit_low
binlog_commit
Ha_trx_info::reset
innobase_commit
Ha_trx_info::reset
debug信息
代码语言:javascript复制T@2: | | | | | | | | >ha_commit_low
T@2: | | | | | | | | | >binlog_commit
T@2: | | | | | | | | | <binlog_commit 2021
T@2: | | | | | | | | | >Ha_trx_info::reset
T@2: | | | | | | | | | <Ha_trx_info::reset 101
T@2: | | | | | | | | | >innobase_commit
T@2: | | | | | | | | | | trans: ending transaction
T@2: | | | | | | | | | | >innobase_trx_init
T@2: | | | | | | | | | | <innobase_trx_init 2628
T@2: | | | | | | | | | | >THD::get_trans_pos
T@2: | | | | | | | | | | | return: file: m3342.000003, pos: 767
T@2: | | | | | | | | | | <THD::get_trans_pos 2863
T@2: | | | | | | | | | <innobase_commit 4515
T@2: | | | | | | | | | >Ha_trx_info::reset
T@2: | | | | | | | | | <Ha_trx_info::reset 101
T@2: | | | | | | | | | >Transaction_ctx::cleanup
T@2: | | | | | | | | | | >Rpl_transaction_ctx::cleanup
T@2: | | | | | | | | | | <Rpl_transaction_ctx::cleanup 47
T@2: | | | | | | | | | | >free_root
T@2: | | | | | | | | | | | enter: root: 0x7f79c4004610 flags: 1
T@2: | | | | | | | | | | <free_root 489
T@2: | | | | | | | | | <Transaction_ctx::cleanup 416
T@2: | | | | | | | | <ha_commit_low 1951
总结
关于redo和binlog先后顺序, 从函数调用来看是先调用的binlog,后redo. 还挺复杂的,以后再细看吧...