Mysql 存储引擎设计:xa协议相关接口功能及实现
创始人
2024-05-25 03:00:53
0

需要对接的接口以及每个接口的实现

recovery 阶段

此阶段由 xa.cc 文件中的 xarecover_handlerton() 函数完成,它通过三个接口实现与存储引擎的沟通:recover()commit_by_xid()rollback_by_xid()。其流程如下:

  1. 此函数首先已经收集到了最后一个 binlog 文件中成功提交了的事物 xid,将其放入一个 SET 中(具体是不是从最后一个 binlog 文件收集的,怎么收集的,下层存储引擎不需要知道)。
  2. 调用recover()收集存储引擎中处于 prepared 阶段的事务,对于其中的每一个事物的 xid 判断其是否存在于上述 SET 。
  3. 如果 xid 存在于 SET 中,则调用commit_by_xid()。否则则调用rollback_by_xid()

🔗 **recover()**
/** This function is used to recover X/Open XA distributed transactions.@return number of prepared transactions stored in xid_list */
static int innobase_xa_recover(handlerton *hton,         /*!< in: InnoDB handlerton */XA_recover_txn *txn_list, /*!< in/out: prepared transactions */uint len,                 /*!< in: number of slots in xid_list */MEM_ROOT *mem_root);      /*!< in: memory for table names */// init
innobase_hton->recover = innobase_xa_recover;

返回值表示收集到的事务的数量

*txn_list 用于返回事务链。对于每一个处于prepare 状态的事务,InnoDB 做如下工作:

  1. 将其事务 xid 写入 txn_list
  2. 将事务对应的 table 信息 push 入 txn_list
// xid
txn_list->id = *trx->xid;
txn_list->mod_tables = new (mem_root) List();// tables
for (auto dd_table : trx->mod_tables) {st_handler_tablename *table = new (mem_root) st_handler_tablename();if (!table || get_table_name_info(table, dd_table, mem_root) ||txn_list->mod_tables->push_back(table, mem_root))}

len表示 txn_list 最长的长度,InnoDB 中如果 prepared 阶段的事务数量达到了 len 个,直接返回。

if (count == len)break;
🔗 **commit_by_xid()**
/** This function is used to commit one X/Open XA distributed transaction which is in the prepared state@return 0 or error number */
static xa_status_code innobase_commit_by_xid(handlerton *hton, /*!< in: InnoDB handlerton */XID *xid);        /*!< in: X/Open XA transaction identification */innobase_hton->commit_by_xid = innobase_commit_by_xid;

这个接口由于底层实现原因,可以不用参考 InnoDB 具体的操作,只需要在引擎中完成以下操作即可:

  1. 对该 xid 对应的事务完成恢复。
  2. 补充该事务的 commit_record。
🔗 **commit_by_xid()**
/** This function is used to rollback one X/Open XA distributed transactionwhich is in the prepared state@return 0 or error number */
static xa_status_code innobase_rollback_by_xid(handlerton *hton, /*!< in: InnoDB handlerton */XID *xid);        /*!< in: X/Open XA transaction identification */innobase_hton->rollback_by_xid = innobase_rollback_by_xid;

直接抛弃 xid 对应的事务,不做恢复。

甚至可以不用实现该接口,在恢复完成后抛弃没有恢复的事务就行。

XID 的设计有点坑:

用于恢复的 xid 本身只是一个 uint64 类型,但 mysql 设计的 xid_t 类型占用了 152 byte 。真正的 xid 被存进了 data 字符数组中。

按道理日志只需要记录 uint64 大小的 xid 就行,但是 xit_t 并没有提供设置其 xid 的办法,只有 set_data() 设置其 data 数据。

目前在 prepare_record 中将整个 xid_t 的内容都存入了(152b),恢复时会恢复一个完整的 xid_t。

#define XIDDATASIZE 128
typedef struct xid_t {private:/**-1 means that the XID is null*/long formatID;/**value from 1 through 64*/long gtrid_length;/**value from 1 through 64*/long bqual_length;/**distributed trx identifier. not \0-terminated.*/char data[XIDDATASIZE];
...
} XID;

prepare 阶段

此阶段只有一个 stage,对应 prepare 接口


🔗 **prepare()**
/** This function is used to prepare an X/Open XA distributed transaction.@return 0 or error number */
static int innobase_xa_prepare(handlerton *hton, /*!< in: InnoDB handlerton */THD *thd,  /*!< in: handle to the MySQL thread ofthe user whose XA transaction shouldbe prepared */bool all); /*!< in: true - prepare transactionfalse - the current SQL statementended */// init
innobase_hton->prepare = innobase_xa_prepare;

此接口需要实现两个功能:

  1. 判断事务是否需要回滚,如果需要,则返回错误码。
  2. 如果事务可以正常提交,则生成该事务的日志,生成 prepare_record(其中存储 xid),并等待落盘完成。

commit

分为了三个阶段,三个阶段之间可以并发进行,但每个阶段内顺序运行:第一个进入某个阶段的事务为 leader,后续进入的事务为 follower。leader 所在的线程领导 follower 顺序完成此阶段的任务。

  1. 其中第一个阶段刷 redo-log,进入这个阶段的所有事务只刷盘一次。除了刷盘 redo-log,bin-log 需要在这个阶段顺序产生,这样一来保证了 redo-log 和 bin-log 日志中事务的顺序是相同的。
  2. 第二个阶段刷 bin-log
  3. 第三个阶段执行 commit,顺序调用存储引擎的 commit 接口

🔗 **flush_logs()** 第一个阶段
/** Flush InnoDB redo logs to the file system.
@param[in]	hton			InnoDB handlerton
@param[in]	binlog_group_flush	true if we got invoked by binlog
group commit during flush stage, false in other cases.
@return false */
static bool innobase_flush_logs(handlerton *hton, bool binlog_group_flush);innobase_hton->flush_logs = innobase_flush_logs;

这个接口的作用是等待 redo_log 进行刷盘,是进行组提交的接口。但是测试发现,每一个事务prepare 之后都会调用此接口,且 InnoDB 都会执行刷盘或者等待刷盘操作。

🔗 **commit()** 第三个阶段
int ha_commit_low(THD *thd, bool all, bool run_after_commit = true);innobase_hton->commit = innobase_commit;

此接口需要实现两个功能:

  1. 这个接口不需要做回滚操作,如果事务没有执行成功,需要执行回滚,只需要返回一个错误码。mysql 随后会调用 rollback接口回滚。
  2. 执行存储引擎的提交操作,并在提交结束后,生成一条 commit_record 日志记录,这里不需要等待此日志记录落盘,因为此日志记录是否落盘不影响已经提交了的事务对应的 tuple 的可见性。且日志的完整性已由 prepare_record 保证。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...