Commit ca53651d authored by Davi Arnaut's avatar Davi Arnaut
Browse files

Bug#28323: Server crashed in xid cache operations

The problem was that the server did not robustly handle a
unilateral roll back issued by the Resource Manager (RM)
due to a resource deadlock within the transaction branch.
By not acknowledging the roll back, the server (TM) would
eventually corrupt the XA transaction state and crash.

The solution is to mark the transaction as rollback-only
if the RM indicates that it rolled back its branch of the
transaction.
parent 41f139bb
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -55,3 +55,22 @@ select * from t1;
a
20
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
+44 −0
Original line number Diff line number Diff line
@@ -74,3 +74,47 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
select * from 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
+6 −1
Original line number Diff line number Diff line
@@ -817,7 +817,12 @@ int ha_rollback_trans(THD *thd, bool all)
    trans->nht=0;
    trans->no_2pc=0;
    if (is_real_trans)
    {
      if (thd->transaction_rollback_request)
        thd->transaction.xid_state.rm_error= thd->net.last_errno;
      else
        thd->transaction.xid_state.xid.null();
    }
    if (all)
    {
      thd->variables.tx_isolation=thd->session_tx_isolation;
+4 −0
Original line number Diff line number Diff line
@@ -5645,3 +5645,7 @@ ER_LOAD_DATA_INVALID_COLUMN
  eng "Invalid column reference (%-.64s) in LOAD DATA"
ER_LOG_PURGE_NO_FILE  
	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"
+3 −1
Original line number Diff line number Diff line
@@ -927,7 +927,7 @@ struct st_savepoint {
  uint                 length, nht;
};

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[];

typedef struct st_xid_state {
@@ -935,6 +935,8 @@ typedef struct st_xid_state {
  XID  xid;                           // transaction identifier
  enum xa_states xa_state;            // used by external XA only
  bool in_thd;
  /* Error reported by the Resource Manager (RM) to the Transaction Manager. */
  uint rm_error;
} XID_STATE;

extern pthread_mutex_t LOCK_xid_cache;
Loading