Commit d04e1d4b authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-15029 XA COMMIT and XA ROLLBACK operate on freed transaction object

innobase_commit_by_xid(), innobase_rollback_by_xid(): Decrement
the reference count before freeing the transaction object to the pool.
Failure to do so might corrupt the transaction bookkeeping
if trx_create_low() returns the same object to another thread
before we are done with it.

trx_sys_close(): Detach the recovered XA PREPARE transactions from
trx_sys->rw_trx_list before freeing them.
parent 9b4dfdaa
......@@ -17881,12 +17881,14 @@ innobase_commit_by_xid(
}
if (trx_t* trx = trx_get_trx_by_xid(xid)) {
TrxInInnoDB trx_in_innodb(trx);
innobase_commit_low(trx);
ut_ad(trx->mysql_thd == NULL);
ut_ad(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE);
/* use cases are: disconnected xa, slave xa, recovery */
trx_deregister_from_2pc(trx);
{
TrxInInnoDB trx_in_innodb(trx);
innobase_commit_low(trx);
ut_ad(trx->mysql_thd == NULL);
trx_deregister_from_2pc(trx);
}
ut_ad(!trx->will_lock); /* trx cache requirement */
trx_free_for_background(trx);
......@@ -17915,12 +17917,14 @@ innobase_rollback_by_xid(
}
if (trx_t* trx = trx_get_trx_by_xid(xid)) {
TrxInInnoDB trx_in_innodb(trx);
int ret = innobase_rollback_trx(trx);
trx_deregister_from_2pc(trx);
ut_ad(!trx->will_lock);
int ret;
ut_ad(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE);
{
TrxInInnoDB trx_in_innodb(trx);
ret = innobase_rollback_trx(trx);
trx_deregister_from_2pc(trx);
ut_ad(!trx->will_lock);
}
trx_free_for_background(trx);
return(ret);
......
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
Copyright (c) 2017, 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -939,13 +939,9 @@ trx_sys_close(void)
|| srv_read_only_mode
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
for (trx_t* trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
trx != NULL;
trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) {
trx_free_prepared(trx);
while (trx_t* trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) {
UT_LIST_REMOVE(trx_sys->rw_trx_list, trx);
trx_free_prepared(trx);
}
/* There can't be any active transactions. */
......
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