diff options
Diffstat (limited to 'sql/log.cc')
-rw-r--r-- | sql/log.cc | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/sql/log.cc b/sql/log.cc index a23abad2bc5..b8f8d3daae7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1995,29 +1995,62 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) int binlog_commit_by_xid(handlerton *hton, XID *xid) { + int rc= 0; THD *thd= current_thd; if (thd->is_current_stmt_binlog_disabled()) return 0; + + /* the asserted state can't be reachable with xa commit */ + DBUG_ASSERT(!thd->get_stmt_da()->is_error() || + thd->get_stmt_da()->sql_errno() != ER_XA_RBROLLBACK); + /* + This is a recovered user xa transaction commit. + Create a "temporary" binlog transaction to write the commit record + into binlog. + */ + THD_TRANS trans; + trans.ha_list= NULL; + + thd->ha_data[hton->slot].ha_info[1].register_ha(&trans, hton); + thd->ha_data[binlog_hton->slot].ha_info[1].set_trx_read_write(); (void) thd->binlog_setup_trx_data(); DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT); - return binlog_commit(thd, TRUE, FALSE); + rc= binlog_commit(thd, TRUE, FALSE); + thd->ha_data[binlog_hton->slot].ha_info[1].reset(); + + return rc; } int binlog_rollback_by_xid(handlerton *hton, XID *xid) { + int rc= 0; THD *thd= current_thd; if (thd->is_current_stmt_binlog_disabled()) return 0; + + if (thd->get_stmt_da()->is_error() && + thd->get_stmt_da()->sql_errno() == ER_XA_RBROLLBACK) + return rc; + + THD_TRANS trans; + trans.ha_list= NULL; + + thd->ha_data[hton->slot].ha_info[1].register_ha(&trans, hton); + thd->ha_data[hton->slot].ha_info[1].set_trx_read_write(); (void) thd->binlog_setup_trx_data(); DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK || (thd->transaction->xid_state.get_state_code() == XA_ROLLBACK_ONLY)); - return binlog_rollback(hton, thd, TRUE); + + rc= binlog_rollback(hton, thd, TRUE); + thd->ha_data[hton->slot].ha_info[1].reset(); + + return rc; } @@ -2151,10 +2184,16 @@ int binlog_commit(THD *thd, bool all, bool ro_1pc) } if (cache_mngr->trx_cache.empty() && - thd->transaction->xid_state.get_state_code() != XA_PREPARED) + (thd->transaction->xid_state.get_state_code() != XA_PREPARED || + !(thd->ha_data[binlog_hton->slot].ha_info[1].is_started() && + thd->ha_data[binlog_hton->slot].ha_info[1].is_trx_read_write()))) { /* - we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid() + This is an empty transaction commit (both the regular and xa), + or such transaction xa-prepare or + either one's statement having no effect on the transactional cache + as any prior to it. + The empty xa-prepare sinks in only when binlog is read-only. */ cache_mngr->reset(false, true); THD_STAGE_INFO(thd, org_stage); @@ -2239,10 +2278,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) } if (!cache_mngr->trx_cache.has_incident() && cache_mngr->trx_cache.empty() && - thd->transaction->xid_state.get_state_code() != XA_PREPARED) + (thd->transaction->xid_state.get_state_code() != XA_PREPARED || + !(thd->ha_data[binlog_hton->slot].ha_info[1].is_started() && + thd->ha_data[binlog_hton->slot].ha_info[1].is_trx_read_write()))) { /* - we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid() + The same comments apply as in the binlog commit method's branch. */ cache_mngr->reset(false, true); thd->reset_binlog_for_next_statement(); @@ -10444,6 +10485,7 @@ int TC_LOG_BINLOG::unlog_xa_prepare(THD *thd, bool all) /* an empty XA-prepare event group is logged */ rc= write_empty_xa_prepare(thd, cache_mngr); // normally gains need_unlog trans_register_ha(thd, true, binlog_hton, 0); // do it for future commmit + thd->ha_data[binlog_hton->slot].ha_info[1].set_trx_read_write(); } if (rw_count == 0 || !cache_mngr->need_unlog) return rc; |