Merge Bug#28323 to mysql-5.1.29-rc
This commit is contained in:
commit
d7263d2a70
@ -55,3 +55,22 @@ select * from t1;
|
|||||||
a
|
a
|
||||||
20
|
20
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
drop table if exists t1;
|
||||||
|
create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb;
|
||||||
|
insert into t1 values(1, 1, 'a');
|
||||||
|
insert into t1 values(2, 2, 'b');
|
||||||
|
xa start 'a','b';
|
||||||
|
update t1 set c = 'aa' where a = 1;
|
||||||
|
xa start 'a','c';
|
||||||
|
update t1 set c = 'bb' where a = 2;
|
||||||
|
update t1 set c = 'bb' where a = 2;
|
||||||
|
update t1 set c = 'aa' where a = 1;
|
||||||
|
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
2
|
||||||
|
xa end 'a','c';
|
||||||
|
ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected
|
||||||
|
xa rollback 'a','c';
|
||||||
|
xa start 'a','c';
|
||||||
|
End of 5.0 tests
|
||||||
|
@ -74,3 +74,47 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#28323: Server crashed in xid cache operations
|
||||||
|
#
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb;
|
||||||
|
insert into t1 values(1, 1, 'a');
|
||||||
|
insert into t1 values(2, 2, 'b');
|
||||||
|
|
||||||
|
connect (con1,localhost,root,,);
|
||||||
|
connect (con2,localhost,root,,);
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
xa start 'a','b';
|
||||||
|
update t1 set c = 'aa' where a = 1;
|
||||||
|
--connection con2
|
||||||
|
xa start 'a','c';
|
||||||
|
update t1 set c = 'bb' where a = 2;
|
||||||
|
--connection con1
|
||||||
|
--send update t1 set c = 'bb' where a = 2
|
||||||
|
--connection con2
|
||||||
|
--sleep 1
|
||||||
|
--error ER_LOCK_DEADLOCK
|
||||||
|
update t1 set c = 'aa' where a = 1;
|
||||||
|
select count(*) from t1;
|
||||||
|
--error ER_XA_RBDEADLOCK
|
||||||
|
xa end 'a','c';
|
||||||
|
xa rollback 'a','c';
|
||||||
|
--disconnect con2
|
||||||
|
|
||||||
|
connect (con3,localhost,root,,);
|
||||||
|
--connection con3
|
||||||
|
xa start 'a','c';
|
||||||
|
|
||||||
|
--disconnect con1
|
||||||
|
--disconnect con3
|
||||||
|
--connection default
|
||||||
|
|
||||||
|
--echo End of 5.0 tests
|
||||||
|
@ -1278,7 +1278,12 @@ int ha_rollback_trans(THD *thd, bool all)
|
|||||||
trans->ha_list= 0;
|
trans->ha_list= 0;
|
||||||
trans->no_2pc=0;
|
trans->no_2pc=0;
|
||||||
if (is_real_trans)
|
if (is_real_trans)
|
||||||
thd->transaction.xid_state.xid.null();
|
{
|
||||||
|
if (thd->transaction_rollback_request)
|
||||||
|
thd->transaction.xid_state.rm_error= thd->main_da.sql_errno();
|
||||||
|
else
|
||||||
|
thd->transaction.xid_state.xid.null();
|
||||||
|
}
|
||||||
if (all)
|
if (all)
|
||||||
{
|
{
|
||||||
thd->variables.tx_isolation=thd->session_tx_isolation;
|
thd->variables.tx_isolation=thd->session_tx_isolation;
|
||||||
|
@ -6128,6 +6128,12 @@ ER_LOAD_DATA_INVALID_COLUMN
|
|||||||
ER_LOG_PURGE_NO_FILE
|
ER_LOG_PURGE_NO_FILE
|
||||||
eng "Being purged log %s was not found"
|
eng "Being purged log %s was not found"
|
||||||
|
|
||||||
|
ER_XA_RBTIMEOUT XA106
|
||||||
|
eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long"
|
||||||
|
|
||||||
|
ER_XA_RBDEADLOCK XA102
|
||||||
|
eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected"
|
||||||
|
|
||||||
ER_NEED_REPREPARE
|
ER_NEED_REPREPARE
|
||||||
eng "Prepared statement needs to be re-prepared"
|
eng "Prepared statement needs to be re-prepared"
|
||||||
|
|
||||||
|
@ -739,7 +739,7 @@ struct st_savepoint {
|
|||||||
Ha_trx_info *ha_list;
|
Ha_trx_info *ha_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
|
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
|
||||||
extern const char *xa_state_names[];
|
extern const char *xa_state_names[];
|
||||||
|
|
||||||
typedef struct st_xid_state {
|
typedef struct st_xid_state {
|
||||||
@ -747,6 +747,8 @@ typedef struct st_xid_state {
|
|||||||
XID xid; // transaction identifier
|
XID xid; // transaction identifier
|
||||||
enum xa_states xa_state; // used by external XA only
|
enum xa_states xa_state; // used by external XA only
|
||||||
bool in_thd;
|
bool in_thd;
|
||||||
|
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */
|
||||||
|
uint rm_error;
|
||||||
} XID_STATE;
|
} XID_STATE;
|
||||||
|
|
||||||
extern pthread_mutex_t LOCK_xid_cache;
|
extern pthread_mutex_t LOCK_xid_cache;
|
||||||
|
@ -83,9 +83,57 @@ const LEX_STRING command_name[]={
|
|||||||
};
|
};
|
||||||
|
|
||||||
const char *xa_state_names[]={
|
const char *xa_state_names[]={
|
||||||
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
|
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Mark a XA transaction as rollback-only if the RM unilaterally
|
||||||
|
rolled back the transaction branch.
|
||||||
|
|
||||||
|
@note If a rollback was requested by the RM, this function sets
|
||||||
|
the appropriate rollback error code and transits the state
|
||||||
|
to XA_ROLLBACK_ONLY.
|
||||||
|
|
||||||
|
@return TRUE if transaction was rolled back or if the transaction
|
||||||
|
state is XA_ROLLBACK_ONLY. FALSE otherwise.
|
||||||
|
*/
|
||||||
|
static bool xa_trans_rolled_back(XID_STATE *xid_state)
|
||||||
|
{
|
||||||
|
if (xid_state->rm_error)
|
||||||
|
{
|
||||||
|
switch (xid_state->rm_error) {
|
||||||
|
case ER_LOCK_WAIT_TIMEOUT:
|
||||||
|
my_error(ER_XA_RBTIMEOUT, MYF(0));
|
||||||
|
break;
|
||||||
|
case ER_LOCK_DEADLOCK:
|
||||||
|
my_error(ER_XA_RBDEADLOCK, MYF(0));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
my_error(ER_XA_RBROLLBACK, MYF(0));
|
||||||
|
}
|
||||||
|
xid_state->xa_state= XA_ROLLBACK_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (xid_state->xa_state == XA_ROLLBACK_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Rollback work done on behalf of at ransaction branch.
|
||||||
|
*/
|
||||||
|
static bool xa_trans_rollback(THD *thd)
|
||||||
|
{
|
||||||
|
bool status= test(ha_rollback(thd));
|
||||||
|
|
||||||
|
thd->options&= ~(ulong) OPTION_BEGIN;
|
||||||
|
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||||
|
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
||||||
|
xid_cache_delete(&thd->transaction.xid_state);
|
||||||
|
thd->transaction.xid_state.xa_state= XA_NOTR;
|
||||||
|
thd->transaction.xid_state.rm_error= 0;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static void unlock_locked_tables(THD *thd)
|
static void unlock_locked_tables(THD *thd)
|
||||||
{
|
{
|
||||||
if (thd->locked_tables)
|
if (thd->locked_tables)
|
||||||
@ -4505,6 +4553,7 @@ create_sp_error:
|
|||||||
}
|
}
|
||||||
DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
|
DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
|
||||||
thd->transaction.xid_state.xa_state=XA_ACTIVE;
|
thd->transaction.xid_state.xa_state=XA_ACTIVE;
|
||||||
|
thd->transaction.xid_state.rm_error= 0;
|
||||||
thd->transaction.xid_state.xid.set(thd->lex->xid);
|
thd->transaction.xid_state.xid.set(thd->lex->xid);
|
||||||
xid_cache_insert(&thd->transaction.xid_state);
|
xid_cache_insert(&thd->transaction.xid_state);
|
||||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
thd->transaction.all.modified_non_trans_table= FALSE;
|
||||||
@ -4530,6 +4579,8 @@ create_sp_error:
|
|||||||
my_error(ER_XAER_NOTA, MYF(0));
|
my_error(ER_XAER_NOTA, MYF(0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (xa_trans_rolled_back(&thd->transaction.xid_state))
|
||||||
|
break;
|
||||||
thd->transaction.xid_state.xa_state=XA_IDLE;
|
thd->transaction.xid_state.xa_state=XA_IDLE;
|
||||||
my_ok(thd);
|
my_ok(thd);
|
||||||
break;
|
break;
|
||||||
@ -4561,6 +4612,12 @@ create_sp_error:
|
|||||||
XID_STATE *xs=xid_cache_search(thd->lex->xid);
|
XID_STATE *xs=xid_cache_search(thd->lex->xid);
|
||||||
if (!xs || xs->in_thd)
|
if (!xs || xs->in_thd)
|
||||||
my_error(ER_XAER_NOTA, MYF(0));
|
my_error(ER_XAER_NOTA, MYF(0));
|
||||||
|
else if (xa_trans_rolled_back(xs))
|
||||||
|
{
|
||||||
|
ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
|
||||||
|
xid_cache_delete(xs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
|
ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
|
||||||
@ -4569,6 +4626,11 @@ create_sp_error:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (xa_trans_rolled_back(&thd->transaction.xid_state))
|
||||||
|
{
|
||||||
|
xa_trans_rollback(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (thd->transaction.xid_state.xa_state == XA_IDLE &&
|
if (thd->transaction.xid_state.xa_state == XA_IDLE &&
|
||||||
thd->lex->xa_opt == XA_ONE_PHASE)
|
thd->lex->xa_opt == XA_ONE_PHASE)
|
||||||
{
|
{
|
||||||
@ -4615,28 +4677,26 @@ create_sp_error:
|
|||||||
my_error(ER_XAER_NOTA, MYF(0));
|
my_error(ER_XAER_NOTA, MYF(0));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
bool ok= !xa_trans_rolled_back(xs);
|
||||||
ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
|
ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
|
||||||
xid_cache_delete(xs);
|
xid_cache_delete(xs);
|
||||||
my_ok(thd);
|
if (ok)
|
||||||
|
my_ok(thd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (thd->transaction.xid_state.xa_state != XA_IDLE &&
|
if (thd->transaction.xid_state.xa_state != XA_IDLE &&
|
||||||
thd->transaction.xid_state.xa_state != XA_PREPARED)
|
thd->transaction.xid_state.xa_state != XA_PREPARED &&
|
||||||
|
thd->transaction.xid_state.xa_state != XA_ROLLBACK_ONLY)
|
||||||
{
|
{
|
||||||
my_error(ER_XAER_RMFAIL, MYF(0),
|
my_error(ER_XAER_RMFAIL, MYF(0),
|
||||||
xa_state_names[thd->transaction.xid_state.xa_state]);
|
xa_state_names[thd->transaction.xid_state.xa_state]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ha_rollback(thd))
|
if (xa_trans_rollback(thd))
|
||||||
my_error(ER_XAER_RMERR, MYF(0));
|
my_error(ER_XAER_RMERR, MYF(0));
|
||||||
else
|
else
|
||||||
my_ok(thd);
|
my_ok(thd);
|
||||||
thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
|
|
||||||
thd->transaction.all.modified_non_trans_table= FALSE;
|
|
||||||
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
|
||||||
xid_cache_delete(&thd->transaction.xid_state);
|
|
||||||
thd->transaction.xid_state.xa_state=XA_NOTR;
|
|
||||||
break;
|
break;
|
||||||
case SQLCOM_XA_RECOVER:
|
case SQLCOM_XA_RECOVER:
|
||||||
res= mysql_xa_recover(thd);
|
res= mysql_xa_recover(thd);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user