Commit 3db404c3 authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#59440 Race condition in XA ROLLBACK and XA COMMIT after server restart

trx_get_trx_by_xid(): Invalidate trx->xid after a successful lookup,
so that subsequent callers will not find the same transaction.

The only callers of trx_get_trx_by_xid() will be invoking
innobase_commit_low() or innobase_rollback_trx(), and those code paths
should not depend on trx->xid.

rb://584 approved by Jimmy Yang
parent 5f20aa2b
...@@ -198,8 +198,9 @@ which is in the prepared state */ ...@@ -198,8 +198,9 @@ which is in the prepared state */
trx_t * trx_t *
trx_get_trx_by_xid( trx_get_trx_by_xid(
/*===============*/ /*===============*/
/* out: trx or NULL */ /* out: trx or NULL;
XID* xid); /* in: X/Open XA transaction identification */ on match, the trx->xid will be invalidated */
const XID* xid); /* in: X/Open XA transaction identifier */
/************************************************************************** /**************************************************************************
If required, flushes the log to disk if we called trx_commit_for_mysql() If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. */ with trx->flush_log_later == TRUE. */
......
...@@ -2041,14 +2041,15 @@ which is in the prepared state */ ...@@ -2041,14 +2041,15 @@ which is in the prepared state */
trx_t* trx_t*
trx_get_trx_by_xid( trx_get_trx_by_xid(
/*===============*/ /*===============*/
/* out: trx or NULL */ /* out: trx or NULL;
XID* xid) /* in: X/Open XA transaction identification */ on match, the trx->xid will be invalidated */
const XID* xid) /* in: X/Open XA transaction identifier */
{ {
trx_t* trx; trx_t* trx;
if (xid == NULL) { if (xid == NULL) {
return (NULL); return(NULL);
} }
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
...@@ -2061,10 +2062,16 @@ trx_get_trx_by_xid( ...@@ -2061,10 +2062,16 @@ trx_get_trx_by_xid(
of gtrid_lenght+bqual_length bytes should be of gtrid_lenght+bqual_length bytes should be
the same */ the same */
if (xid->gtrid_length == trx->xid.gtrid_length if (trx->conc_state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length && xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data, && memcmp(xid->data, trx->xid.data,
xid->gtrid_length + xid->bqual_length) == 0) { xid->gtrid_length + xid->bqual_length) == 0) {
/* Invalidate the XID, so that subsequent calls
will not find it. */
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
break; break;
} }
...@@ -2073,14 +2080,5 @@ trx_get_trx_by_xid( ...@@ -2073,14 +2080,5 @@ trx_get_trx_by_xid(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
if (trx) {
if (trx->conc_state != TRX_PREPARED) {
return(NULL);
}
return(trx); return(trx);
} else {
return(NULL);
}
} }
2011-01-27 The InnoDB Team
* include/trx0trx.h, trx/trx0trx.c:
Bug#59440 Race condition in XA ROLLBACK and XA COMMIT
after server restart
2011-01-25 The InnoDB Team 2011-01-25 The InnoDB Team
* row/row0upd.c: * row/row0upd.c:
......
...@@ -214,12 +214,12 @@ trx_recover_for_mysql( ...@@ -214,12 +214,12 @@ trx_recover_for_mysql(
/*******************************************************************//** /*******************************************************************//**
This function is used to find one X/Open XA distributed transaction This function is used to find one X/Open XA distributed transaction
which is in the prepared state which is in the prepared state
@return trx or NULL */ @return trx or NULL; on match, the trx->xid will be invalidated */
UNIV_INTERN UNIV_INTERN
trx_t * trx_t *
trx_get_trx_by_xid( trx_get_trx_by_xid(
/*===============*/ /*===============*/
XID* xid); /*!< in: X/Open XA transaction identification */ const XID* xid); /*!< in: X/Open XA transaction identifier */
/**********************************************************************//** /**********************************************************************//**
If required, flushes the log to disk if we called trx_commit_for_mysql() If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. with trx->flush_log_later == TRUE.
......
...@@ -2010,18 +2010,18 @@ trx_recover_for_mysql( ...@@ -2010,18 +2010,18 @@ trx_recover_for_mysql(
/*******************************************************************//** /*******************************************************************//**
This function is used to find one X/Open XA distributed transaction This function is used to find one X/Open XA distributed transaction
which is in the prepared state which is in the prepared state
@return trx or NULL */ @return trx or NULL; on match, the trx->xid will be invalidated */
UNIV_INTERN UNIV_INTERN
trx_t* trx_t*
trx_get_trx_by_xid( trx_get_trx_by_xid(
/*===============*/ /*===============*/
XID* xid) /*!< in: X/Open XA transaction identification */ const XID* xid) /*!< in: X/Open XA transaction identifier */
{ {
trx_t* trx; trx_t* trx;
if (xid == NULL) { if (xid == NULL) {
return (NULL); return(NULL);
} }
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
...@@ -2034,10 +2034,16 @@ trx_get_trx_by_xid( ...@@ -2034,10 +2034,16 @@ trx_get_trx_by_xid(
of gtrid_lenght+bqual_length bytes should be of gtrid_lenght+bqual_length bytes should be
the same */ the same */
if (xid->gtrid_length == trx->xid.gtrid_length if (trx->conc_state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length && xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data, && memcmp(xid->data, trx->xid.data,
xid->gtrid_length + xid->bqual_length) == 0) { xid->gtrid_length + xid->bqual_length) == 0) {
/* Invalidate the XID, so that subsequent calls
will not find it. */
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
break; break;
} }
...@@ -2046,14 +2052,5 @@ trx_get_trx_by_xid( ...@@ -2046,14 +2052,5 @@ trx_get_trx_by_xid(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
if (trx) {
if (trx->conc_state != TRX_PREPARED) {
return(NULL);
}
return(trx); return(trx);
} else {
return(NULL);
}
} }
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