Commit 228514e5 authored by Sergey Vojtovich's avatar Sergey Vojtovich

Move XID_STATE::xa_state to XID_cache_element

Simplified away XA_NOTR, use XID_STATE::is_explicit_XA() instead.

Part of MDEV-7974 - backport fix for mysql bug#12161 (XA and binlog)
parent a168cfb3
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
/*************************************************************************** /***************************************************************************
Handling of XA id cacheing Handling of XA id cacheing
***************************************************************************/ ***************************************************************************/
enum xa_states { XA_ACTIVE= 0, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY };
class XID_cache_element class XID_cache_element
{ {
/* /*
...@@ -63,6 +65,7 @@ class XID_cache_element ...@@ -63,6 +65,7 @@ class XID_cache_element
XID_STATE *m_xid_state; XID_STATE *m_xid_state;
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */ /* Error reported by the Resource Manager (RM) to the Transaction Manager. */
uint rm_error; uint rm_error;
enum xa_states xa_state;
bool is_set(int32_t flag) bool is_set(int32_t flag)
{ return m_state.load(std::memory_order_relaxed) & flag; } { return m_state.load(std::memory_order_relaxed) & flag; }
void set(int32_t flag) void set(int32_t flag)
...@@ -153,11 +156,13 @@ void XID_STATE::set_error(uint error) ...@@ -153,11 +156,13 @@ void XID_STATE::set_error(uint error)
xid_cache_element->rm_error= error; xid_cache_element->rm_error= error;
} }
void XID_STATE::er_xaer_rmfail() const void XID_STATE::er_xaer_rmfail() const
{ {
static const char *xa_state_names[]= static const char *xa_state_names[]=
{ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY" }; { "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY" };
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); my_error(ER_XAER_RMFAIL, MYF(0), is_explicit_XA() ?
xa_state_names[xid_cache_element->xa_state] : "NON-EXISTING");
} }
...@@ -174,9 +179,7 @@ void XID_STATE::er_xaer_rmfail() const ...@@ -174,9 +179,7 @@ void XID_STATE::er_xaer_rmfail() const
bool XID_STATE::check_has_uncommitted_xa() const bool XID_STATE::check_has_uncommitted_xa() const
{ {
if (xa_state == XA_IDLE || if (is_explicit_XA() && xid_cache_element->xa_state != XA_ACTIVE)
xa_state == XA_PREPARED ||
xa_state == XA_ROLLBACK_ONLY)
{ {
er_xaer_rmfail(); er_xaer_rmfail();
return true; return true;
...@@ -246,7 +249,7 @@ bool xid_cache_insert(XID *xid) ...@@ -246,7 +249,7 @@ bool xid_cache_insert(XID *xid)
my_free(xs); my_free(xs);
else else
{ {
xs->xa_state= XA_PREPARED; xs->xid_cache_element->xa_state= XA_PREPARED;
xs->xid_cache_element->set(XID_cache_element::RECOVERED); xs->xid_cache_element->set(XID_cache_element::RECOVERED);
} }
if (res == 1) if (res == 1)
...@@ -266,7 +269,7 @@ bool xid_cache_insert(THD *thd, XID_STATE *xid_state) ...@@ -266,7 +269,7 @@ bool xid_cache_insert(THD *thd, XID_STATE *xid_state)
switch (res) switch (res)
{ {
case 0: case 0:
xid_state->xa_state= XA_ACTIVE; xid_state->xid_cache_element->xa_state= XA_ACTIVE;
xid_state->xid_cache_element->set(XID_cache_element::ACQUIRED); xid_state->xid_cache_element->set(XID_cache_element::ACQUIRED);
break; break;
case 1: case 1:
...@@ -293,7 +296,6 @@ void xid_cache_delete(THD *thd, XID_STATE *xid_state) ...@@ -293,7 +296,6 @@ void xid_cache_delete(THD *thd, XID_STATE *xid_state)
else else
{ {
xid_state->xid_cache_element= 0; xid_state->xid_cache_element= 0;
xid_state->xa_state= XA_NOTR;
xid_state->xid.null(); xid_state->xid.null();
} }
} }
...@@ -354,10 +356,10 @@ static bool xa_trans_rolled_back(XID_STATE *xid_state) ...@@ -354,10 +356,10 @@ static bool xa_trans_rolled_back(XID_STATE *xid_state)
default: default:
my_error(ER_XA_RBROLLBACK, MYF(0)); my_error(ER_XA_RBROLLBACK, MYF(0));
} }
xid_state->xa_state= XA_ROLLBACK_ONLY; xid_state->xid_cache_element->xa_state= XA_ROLLBACK_ONLY;
} }
return (xid_state->xa_state == XA_ROLLBACK_ONLY); return xid_state->xid_cache_element->xa_state == XA_ROLLBACK_ONLY;
} }
...@@ -389,16 +391,17 @@ static bool xa_trans_force_rollback(THD *thd) ...@@ -389,16 +391,17 @@ static bool xa_trans_force_rollback(THD *thd)
bool trans_xa_start(THD *thd) bool trans_xa_start(THD *thd)
{ {
enum xa_states xa_state= thd->transaction.xid_state.xa_state;
DBUG_ENTER("trans_xa_start"); DBUG_ENTER("trans_xa_start");
if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME) if (thd->transaction.xid_state.is_explicit_XA() &&
thd->transaction.xid_state.xid_cache_element->xa_state == XA_IDLE &&
thd->lex->xa_opt == XA_RESUME)
{ {
bool not_equal= !thd->transaction.xid_state.xid.eq(thd->lex->xid); bool not_equal= !thd->transaction.xid_state.xid.eq(thd->lex->xid);
if (not_equal) if (not_equal)
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
else else
thd->transaction.xid_state.xa_state= XA_ACTIVE; thd->transaction.xid_state.xid_cache_element->xa_state= XA_ACTIVE;
DBUG_RETURN(not_equal); DBUG_RETURN(not_equal);
} }
...@@ -442,15 +445,16 @@ bool trans_xa_end(THD *thd) ...@@ -442,15 +445,16 @@ bool trans_xa_end(THD *thd)
/* TODO: SUSPEND and FOR MIGRATE are not supported yet. */ /* TODO: SUSPEND and FOR MIGRATE are not supported yet. */
if (thd->lex->xa_opt != XA_NONE) if (thd->lex->xa_opt != XA_NONE)
my_error(ER_XAER_INVAL, MYF(0)); my_error(ER_XAER_INVAL, MYF(0));
else if (thd->transaction.xid_state.xa_state != XA_ACTIVE) else if (!thd->transaction.xid_state.is_explicit_XA() ||
thd->transaction.xid_state.xid_cache_element->xa_state != XA_ACTIVE)
thd->transaction.xid_state.er_xaer_rmfail(); thd->transaction.xid_state.er_xaer_rmfail();
else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
else if (!xa_trans_rolled_back(&thd->transaction.xid_state)) else if (!xa_trans_rolled_back(&thd->transaction.xid_state))
thd->transaction.xid_state.xa_state= XA_IDLE; thd->transaction.xid_state.xid_cache_element->xa_state= XA_IDLE;
DBUG_RETURN(thd->is_error() || DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xa_state != XA_IDLE); thd->transaction.xid_state.xid_cache_element->xa_state != XA_IDLE);
} }
...@@ -467,7 +471,8 @@ bool trans_xa_prepare(THD *thd) ...@@ -467,7 +471,8 @@ bool trans_xa_prepare(THD *thd)
{ {
DBUG_ENTER("trans_xa_prepare"); DBUG_ENTER("trans_xa_prepare");
if (thd->transaction.xid_state.xa_state != XA_IDLE) if (!thd->transaction.xid_state.is_explicit_XA() ||
thd->transaction.xid_state.xid_cache_element->xa_state != XA_IDLE)
thd->transaction.xid_state.er_xaer_rmfail(); thd->transaction.xid_state.er_xaer_rmfail();
else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
...@@ -477,10 +482,10 @@ bool trans_xa_prepare(THD *thd) ...@@ -477,10 +482,10 @@ bool trans_xa_prepare(THD *thd)
my_error(ER_XA_RBROLLBACK, MYF(0)); my_error(ER_XA_RBROLLBACK, MYF(0));
} }
else else
thd->transaction.xid_state.xa_state= XA_PREPARED; thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED;
DBUG_RETURN(thd->is_error() || DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xa_state != XA_PREPARED); thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED);
} }
...@@ -496,7 +501,6 @@ bool trans_xa_prepare(THD *thd) ...@@ -496,7 +501,6 @@ bool trans_xa_prepare(THD *thd)
bool trans_xa_commit(THD *thd) bool trans_xa_commit(THD *thd)
{ {
bool res= TRUE; bool res= TRUE;
enum xa_states xa_state= thd->transaction.xid_state.xa_state;
DBUG_ENTER("trans_xa_commit"); DBUG_ENTER("trans_xa_commit");
if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
...@@ -525,13 +529,15 @@ bool trans_xa_commit(THD *thd) ...@@ -525,13 +529,15 @@ bool trans_xa_commit(THD *thd)
xa_trans_force_rollback(thd); xa_trans_force_rollback(thd);
res= thd->is_error(); res= thd->is_error();
} }
else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE) else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_IDLE &&
thd->lex->xa_opt == XA_ONE_PHASE)
{ {
int r= ha_commit_trans(thd, TRUE); int r= ha_commit_trans(thd, TRUE);
if ((res= MY_TEST(r))) if ((res= MY_TEST(r)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
} }
else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED &&
thd->lex->xa_opt == XA_NONE)
{ {
MDL_request mdl_request; MDL_request mdl_request;
...@@ -591,7 +597,6 @@ bool trans_xa_commit(THD *thd) ...@@ -591,7 +597,6 @@ bool trans_xa_commit(THD *thd)
bool trans_xa_rollback(THD *thd) bool trans_xa_rollback(THD *thd)
{ {
bool res= TRUE; bool res= TRUE;
enum xa_states xa_state= thd->transaction.xid_state.xa_state;
DBUG_ENTER("trans_xa_rollback"); DBUG_ENTER("trans_xa_rollback");
if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
...@@ -614,7 +619,7 @@ bool trans_xa_rollback(THD *thd) ...@@ -614,7 +619,7 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(thd->get_stmt_da()->is_error()); DBUG_RETURN(thd->get_stmt_da()->is_error());
} }
if (xa_state != XA_IDLE && xa_state != XA_PREPARED && xa_state != XA_ROLLBACK_ONLY) if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_ACTIVE)
{ {
thd->transaction.xid_state.er_xaer_rmfail(); thd->transaction.xid_state.er_xaer_rmfail();
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -746,7 +751,7 @@ static uint get_sql_xid(XID *xid, char *buf) ...@@ -746,7 +751,7 @@ static uint get_sql_xid(XID *xid, char *buf)
static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol, static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol,
char *data, uint data_len, CHARSET_INFO *data_cs) char *data, uint data_len, CHARSET_INFO *data_cs)
{ {
if (xs->xa_state == XA_PREPARED) if (xs->xid_cache_element->xa_state == XA_PREPARED)
{ {
protocol->prepare_for_resend(); protocol->prepare_for_resend();
protocol->store_longlong((longlong) xs->xid.formatID, FALSE); protocol->store_longlong((longlong) xs->xid.formatID, FALSE);
......
...@@ -17,13 +17,11 @@ ...@@ -17,13 +17,11 @@
*/ */
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
class XID_cache_element; class XID_cache_element;
struct XID_STATE { struct XID_STATE {
/* For now, this is only used to catch duplicated external xids */ /* For now, this is only used to catch duplicated external xids */
XID xid; // transaction identifier XID xid; // transaction identifier
enum xa_states xa_state; // used by external XA only
XID_cache_element *xid_cache_element; XID_cache_element *xid_cache_element;
bool check_has_uncommitted_xa() const; bool check_has_uncommitted_xa() const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment