From b8b3ba632b8596bb483420dc6da46925f1c9b094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 23 Aug 2017 13:03:13 +0300 Subject: [PATCH] MDEV-13606 XA PREPARE transactions should survive innodb_force_recovery=1 or 2 When MySQL 5.0.3 introduced InnoDB support for two-phase commit, it also introduced the questionable logic to roll back XA PREPARE transactions on startup when innodb_force_recovery is 1 or 2. Remove this logic in order to avoid unwanted side effects when innodb_force_recovery is being set for other reasons. That is, XA PREPARE transactions will always remain in that state until InnoDB receives an explicit XA ROLLBACK or XA COMMIT request from the upper layer. At the time the logic was introduced in MySQL 5.0.3, there already was a startup parameter that is the preferred way of achieving the behaviour: --tc-heuristic-recover=ROLLBACK. --- mysql-test/suite/innodb/r/xa_recovery.result | 2 +- mysql-test/suite/innodb/t/xa_recovery.test | 5 +++ storage/innobase/trx/trx0trx.cc | 36 ++++++-------------- storage/xtradb/trx/trx0trx.cc | 36 ++++++-------------- 4 files changed, 26 insertions(+), 53 deletions(-) diff --git a/mysql-test/suite/innodb/r/xa_recovery.result b/mysql-test/suite/innodb/r/xa_recovery.result index 4441701f961..3b560b79657 100644 --- a/mysql-test/suite/innodb/r/xa_recovery.result +++ b/mysql-test/suite/innodb/r/xa_recovery.result @@ -4,7 +4,7 @@ XA START 'x'; UPDATE t1 set a=2; XA END 'x'; XA PREPARE 'x'; -# Kill and restart +# Kill and restart: --innodb-force-recovery=2 SELECT * FROM t1 LOCK IN SHARE MODE; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t1; diff --git a/mysql-test/suite/innodb/t/xa_recovery.test b/mysql-test/suite/innodb/t/xa_recovery.test index f5c2b655545..d4f957c7bf4 100644 --- a/mysql-test/suite/innodb/t/xa_recovery.test +++ b/mysql-test/suite/innodb/t/xa_recovery.test @@ -15,7 +15,12 @@ connect (con1,localhost,root); XA START 'x'; UPDATE t1 set a=2; XA END 'x'; XA PREPARE 'x'; connection default; +# innodb_force_recovery=2 prevents the purge and tests that the fix of +# MDEV-13606 XA PREPARE transactions should survive innodb_force_recovery=1 or 2 +# is present. +--let $restart_parameters= --innodb-force-recovery=2 --source include/kill_and_restart_mysqld.inc +--let $restart_parameters= disconnect con1; connect (con1,localhost,root); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index f06d8c33183..c38c9bf7188 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 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 @@ -536,18 +537,9 @@ trx_resurrect_insert( "InnoDB: Transaction " TRX_ID_FMT " was in the" " XA prepared state.\n", trx->id); - if (srv_force_recovery == 0) { - - trx->state = TRX_STATE_PREPARED; - trx_sys->n_prepared_trx++; - trx_sys->n_prepared_recovered_trx++; - } else { - fprintf(stderr, - "InnoDB: Since innodb_force_recovery" - " > 0, we will rollback it anyway.\n"); - - trx->state = TRX_STATE_ACTIVE; - } + trx->state = TRX_STATE_PREPARED; + trx_sys->n_prepared_trx++; + trx_sys->n_prepared_recovered_trx++; } else { trx->state = TRX_STATE_COMMITTED_IN_MEMORY; } @@ -605,22 +597,14 @@ trx_resurrect_update_in_prepared_state( "InnoDB: Transaction " TRX_ID_FMT " was in the XA prepared state.\n", trx->id); - if (srv_force_recovery == 0) { - if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { - trx_sys->n_prepared_trx++; - trx_sys->n_prepared_recovered_trx++; - } else { - ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED)); - } - - trx->state = TRX_STATE_PREPARED; + if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { + trx_sys->n_prepared_trx++; + trx_sys->n_prepared_recovered_trx++; } else { - fprintf(stderr, - "InnoDB: Since innodb_force_recovery" - " > 0, we will rollback it anyway.\n"); - - trx->state = TRX_STATE_ACTIVE; + ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED)); } + + trx->state = TRX_STATE_PREPARED; } else { trx->state = TRX_STATE_COMMITTED_IN_MEMORY; } diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index fd620ae6659..d3b1f1da054 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 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 @@ -714,18 +715,9 @@ trx_resurrect_insert( "InnoDB: Transaction " TRX_ID_FMT " was in the" " XA prepared state.\n", trx->id); - if (srv_force_recovery == 0) { - - trx->state = TRX_STATE_PREPARED; - trx_sys->n_prepared_trx++; - trx_sys->n_prepared_recovered_trx++; - } else { - fprintf(stderr, - "InnoDB: Since innodb_force_recovery" - " > 0, we will rollback it anyway.\n"); - - trx->state = TRX_STATE_ACTIVE; - } + trx->state = TRX_STATE_PREPARED; + trx_sys->n_prepared_trx++; + trx_sys->n_prepared_recovered_trx++; } else { trx->state = TRX_STATE_COMMITTED_IN_MEMORY; } @@ -783,22 +775,14 @@ trx_resurrect_update_in_prepared_state( "InnoDB: Transaction " TRX_ID_FMT " was in the XA prepared state.\n", trx->id); - if (srv_force_recovery == 0) { - if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { - trx_sys->n_prepared_trx++; - trx_sys->n_prepared_recovered_trx++; - } else { - ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED)); - } - - trx->state = TRX_STATE_PREPARED; + if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { + trx_sys->n_prepared_trx++; + trx_sys->n_prepared_recovered_trx++; } else { - fprintf(stderr, - "InnoDB: Since innodb_force_recovery" - " > 0, we will rollback it anyway.\n"); - - trx->state = TRX_STATE_ACTIVE; + ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED)); } + + trx->state = TRX_STATE_PREPARED; } else { trx->state = TRX_STATE_COMMITTED_IN_MEMORY; }