目录
2.1 Prepare阶段存储本事务的last_commit
2.2 Commit第三阶段更新全局的m_max_committed_transaction
2.3 Flush阶段获取事务的sequence_number
1. 基础数据结构
添加全局的事务计数器产生事务timestamp和记录当前最大事务timestamp的clock。
每个BinLog文件对应一对,代码关系为:
class MYSQL_BIN_LOG: public TC_LOG
=>Transaction_dependency_tracker => Commit_order_trx_dependency_tracker
class MYSQL_BIN_LOG: public TC_LOG
{
...
public:
/* Committed transactions timestamp */
Logical_clock max_committed_transaction;
/* "Prepared" transactions timestamp */
Logical_clock transaction_counter;
...
}
class Logical_clock
{
private:
int64 state;
/*
Offset is subtracted from the actual "absolute time" value at
logging a replication event. That is the event holds logical
timestamps in the "relative" format. They are meaningful only in
the context of the current binlog.
The member is updated (incremented) per binary log rotation.
*/
int64 offset;
public:
Logical_clock();
int64 step();
int64 set_if_greater(int64 new_val);
int64 get_timestamp();
int64 get_offset() { return offset; }
/*
Updates the offset.
This operation is invoked when binlog rotates and at that time
there can't any concurrent step() callers so no need to guard
the assignement.
*/
void update_offset(int64 new_offset)
{
DBUG_ASSERT(offset <= new_offset);
offset= new_offset;
}
};
state是一个自增的值,offset在每次二进制日志发生rotate时更新,记录发生rotate时的state值。其实state和offset记录的是全局的计数值,而存在二进制日志中的仅是当前文件的相对值。
对每个事务定义其lock interval,并记录到binlog中,在每个transaction中添加下面两个member。
class Transaction_ctx
{
...
/*
Store for the transaction's commit parent sequence_number.
The value specifies this transaction dependency with a "parent"
transaction.
The member is assigned, when the transaction is about to commit
in binlog to a value of the last committed transaction's sequence_number.
This and last_committed as numbers are kept ever incremented
regardless of binary logs being rotated or when transaction
is logged in multiple pieces.
However the logger to the binary log may convert them
according to its specification.
*/
int64 last_committed;
/*
The transaction's private logical timestamp assigned at the
transaction prepare phase. The timestamp enumerates transactions
in the binary log. The value is gained through incrementing (stepping) a
global clock.
Eventually the value is considered to increase max_committed_transaction
system clock when the transaction has committed.
*/
int64 sequence_number;
...
}
2. 处理逻辑
2.1 Prepare阶段存储本事务的last_commit
从BinLog对象中取出m_max_committed_transaction,存储到(Transaction_ctx)Trx_ctx的last_committed中。
static int binlog_prepare(handlerton *hton, THD *thd, bool all)
{
DBUG_ENTER("binlog_prepare");
if (!all)
{
thd->get_transaction()->store_commit_parent(mysql_bin_log.
m_dependency_tracker.get_max_committed_timestamp());
}
DBUG_RETURN(all && is_loggable_xa_prepare(thd) ?
mysql_bin_log.commit(thd, true) : 0);
}
2.2 Commit第三阶段更新全局的m_max_committed_transaction
if (head->get_transaction()->sequence_number != SEQ_UNINIT)
{
mysql_mutex_lock(&LOCK_slave_trans_dep_tracker);
m_dependency_tracker.update_max_committed(head);
mysql_mutex_unlock(&LOCK_slave_trans_dep_tracker);
}
------
void
Transaction_dependency_tracker::update_max_committed(THD *thd)
{
Transaction_ctx *trn_ctx= thd->get_transaction();
m_commit_order.update_max_committed(trn_ctx->sequence_number);
/*
sequence_number timestamp isn't needed anymore, so it's cleared off.
*/
trn_ctx->sequence_number= SEQ_UNINIT;
DBUG_ASSERT(trn_ctx->last_committed == SEQ_UNINIT ||
thd->commit_error == THD::CE_FLUSH_ERROR);
}
2.3 Flush阶段获取事务的sequence_number
binlog_cache_data::flush(THD *thd, my_off_t *bytes_written, bool *wrote_xid)
{
Transaction_ctx *trn_ctx= thd->get_transaction();
trn_ctx->sequence_number= mysql_bin_log.m_dependency_tracker.step();
mysql_bin_log.write_gtid(thd, this, &writer)
}
------
return m_transaction_counter.step();
return ++state;
https://www.jianshu.com/p/8c416f3f471b
https://www.cnblogs.com/xiaotengyi/p/5532191.html
https://blog.csdn.net/andong154564667/article/details/82117727