summaryrefslogtreecommitdiff
path: root/sql/transaction.cc
diff options
context:
space:
mode:
authorDmitry Shulga <Dmitry.Shulga@oracle.com>2012-12-06 15:59:15 +0600
committerDmitry Shulga <Dmitry.Shulga@oracle.com>2012-12-06 15:59:15 +0600
commit54769c281ec9cf7d52740ed5ca503c5d81ed1744 (patch)
tree09347fd41ab35e614f325750babcb7973da605a2 /sql/transaction.cc
parent46cfbf35f86a6ff63bdfcd85297bd8269efc2826 (diff)
downloadmariadb-git-54769c281ec9cf7d52740ed5ca503c5d81ed1744.tar.gz
This patch fixes bug#14729757 - MY_HASH_SEARCH(&XID_CACHE,
XID_STATE->XID.KEY(), XID_STATE->XID.KEY_LENGTH())==0 This bug is a regression of bug#11759534 - 51855: RACE CONDITION IN XA START. The reason for regression is that the changes that fixes the original bug wasn't merged from mysql-5.1 into mysql-5.5 and mysql-trunk. Only null-merge was done for the patch changeset. To incorporate lost changes the manual merge have been done. Additionally the call of trans_rolback() was added into trans_xa_start() in case if xid_cache_insert is failed() after transaction has been started. If we don't call trans_rollback() we would never reset the flag SERVER_STATUS_IN_TRANS in THD::server_status and therefore all subsequent attempts to execute XA START in the connection where the error was occurred will be failed since thd->in_active_multi_stmt_transaction() will return the true every time when trans_xa_start is called. The latest changes were absent in patch for mysql-5.1
Diffstat (limited to 'sql/transaction.cc')
-rw-r--r--sql/transaction.cc20
1 files changed, 17 insertions, 3 deletions
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 3359decbcd5..1623cd57d77 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -567,15 +567,19 @@ bool trans_xa_start(THD *thd)
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
my_error(ER_XAER_OUTSIDE, MYF(0));
- else if (xid_cache_search(thd->lex->xid))
- my_error(ER_XAER_DUPID, MYF(0));
else if (!trans_begin(thd))
{
DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
thd->transaction.xid_state.xa_state= XA_ACTIVE;
thd->transaction.xid_state.rm_error= 0;
thd->transaction.xid_state.xid.set(thd->lex->xid);
- xid_cache_insert(&thd->transaction.xid_state);
+ if (xid_cache_insert(&thd->transaction.xid_state))
+ {
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+ thd->transaction.xid_state.xid.null();
+ trans_rollback(thd);
+ DBUG_RETURN(true);
+ }
DBUG_RETURN(FALSE);
}
@@ -661,6 +665,16 @@ bool trans_xa_commit(THD *thd)
if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
+ /*
+ xid_state.in_thd is always true beside of xa recovery procedure.
+ Note, that there is no race condition here between xid_cache_search
+ and xid_cache_delete, since we always delete our own XID
+ (thd->lex->xid == thd->transaction.xid_state.xid).
+ The only case when thd->lex->xid != thd->transaction.xid_state.xid
+ and xid_state->in_thd == 0 is in the function
+ xa_cache_insert(XID, xa_states), which is called before starting
+ client connections, and thus is always single-threaded.
+ */
XID_STATE *xs= xid_cache_search(thd->lex->xid);
res= !xs || xs->in_thd;
if (res)