diff --git a/sql/binlog.cc b/sql/binlog.cc index cef949f..b55e541 100644 --- a/sql/binlog.cc +++ b/sql/binlog.cc @@ -86,7 +86,7 @@ static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton, THD *thd); static int binlog_commit(handlerton *hton, THD *thd, bool all); static int binlog_rollback(handlerton *hton, THD *thd, bool all); -static int binlog_prepare(handlerton *hton, THD *thd, bool all); +int binlog_prepare(handlerton *hton, THD *thd, bool all); static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd); static int binlog_clone_consistent_snapshot(handlerton *hton, THD *thd, THD *from_thd); @@ -1505,7 +1505,7 @@ inline bool is_loggable_xa_prepare(THD *thd) has_state(XID_STATE::XA_IDLE)); } -static int binlog_prepare(handlerton *hton, THD *thd, bool all) +int binlog_prepare(handlerton *hton, THD *thd, bool all) { DBUG_ENTER("binlog_prepare"); if (!all) diff --git a/sql/handler.cc b/sql/handler.cc index 33d9690..65a1171 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1459,6 +1459,8 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg, DBUG_VOID_RETURN; } +int binlog_prepare(handlerton *hton, THD *thd, bool all); + /** @retval 0 ok @@ -1473,6 +1475,8 @@ int ha_prepare(THD *thd) if (trn_ctx->is_active(Transaction_ctx::SESSION)) { + const bool is_xa_prepare= (thd->lex->sql_command == SQLCOM_XA_PREPARE); + handlerton *ht0 = NULL; const Ha_trx_info *ha_info= trn_ctx->ha_trx_info( Transaction_ctx::SESSION); bool gtid_error= false, need_clear_owned_gtid= false; @@ -1490,6 +1494,25 @@ int ha_prepare(THD *thd) while (ha_info) { handlerton *ht= ha_info->ht(); + /* + Work around mysql bug: Bug #84297 Engine prepare executed after flush + stage. + Binlog is always the 1st storage engine, in xa prepare execution, + binlog of the txn is flushed in binlog_prepare() which is executed first + in the loop here, and this is wrong! + THe work around is to execute it last, after innodb_xa_prepare() so that + the txn is flushed to innodb log *before* it's flushed onto binlog, just + as normal non-xa txn commits do. + */ + if (ht0 == NULL && is_xa_prepare && ht->prepare == binlog_prepare) + { + DBUG_ASSERT(ht->prepare == binlog_prepare); + ht0= ht; + ha_info= ha_info->next(); + DBUG_ASSERT(ha_info != NULL); + continue; + } +again: thd->status_var.ha_prepare_count++; if (ht->prepare) { @@ -1510,7 +1533,21 @@ int ha_prepare(THD *thd) ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), ha_resolve_storage_engine_name(ht)); } + + if (!ha_info) + break; // binlog_prepare() is just called. + ha_info= ha_info->next(); + if (!ha_info && ht0) + { + /* + Run binlog_prepare() at last, after all engines have prepared. + */ + DBUG_ASSERT(is_xa_prepare); + ht= ht0; + ht0= NULL; + goto again; + } } DBUG_ASSERT(thd->get_transaction()->xid_state()->