diff --git a/sql/xa.cc b/sql/xa.cc index 199d4c5..f0dacba 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -709,7 +738,28 @@ bool Sql_cmd_xa_prepare::trans_xa_prepare(THD *thd) my_error(ER_XAER_RMFAIL, MYF(0), xid_state->state_name()); else if (!xid_state->has_same_xid(m_xid)) my_error(ER_XAER_NOTA, MYF(0)); - else if (ha_prepare(thd)) + else + { + MDL_request mdl_request; + + /* + We acquire the COMMIT lock in 'xa prepare' so that xtrabackup can work + correctly --- otherwise redo logs of prepared txns might by partially + copied by xtrabackup, and becomes inconsistent with binlog position it + notes down right after the engine log copy operation, and some + transactions would get lost. + */ + MDL_REQUEST_INIT(&mdl_request, + MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE, + MDL_TRANSACTION); + if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) + { + ha_rollback_trans(thd, true); + my_error(ER_XAER_RMERR, MYF(0)); + goto end; + } + + if (ha_prepare(thd)) { #ifdef HAVE_PSI_TRANSACTION_INTERFACE DBUG_ASSERT(thd->m_transaction_psi == NULL); @@ -728,7 +778,8 @@ bool Sql_cmd_xa_prepare::trans_xa_prepare(THD *thd) if (thd->rpl_thd_ctx.session_gtids_ctx().notify_after_xa_prepare(thd)) sql_print_warning("Failed to collect GTID to send in the response packet!"); } - + } +end: DBUG_RETURN(thd->is_error() || !xid_state->has_state(XID_STATE::XA_PREPARED)); }