Merge lp:~laurynas-biveinis/percona-server/bug1012715-5.1 into lp:percona-server/5.1

Proposed by Laurynas Biveinis
Status: Superseded
Proposed branch: lp:~laurynas-biveinis/percona-server/bug1012715-5.1
Merge into: lp:percona-server/5.1
Diff against target: 281 lines (+186/-38)
5 files modified
Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result (+42/-0)
Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt (+1/-0)
Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test (+95/-0)
Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc (+31/-20)
Percona-Server/storage/innodb_plugin/trx/trx0trx.c (+17/-18)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/bug1012715-5.1
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Needs Fixing
Review via email: mp+112346@code.launchpad.net

This proposal has been superseded by a proposal from 2012-06-29.

Description of the change

Fix bug 1012715 (Crash resistant replication breaks with binlog XA
transaction recovery). The cause is that slave position is recorded
to InnoDB transaction system header at the XA COMMIT stage. If a
crash happens between XA PREPARE and COMMIT stages, the prepared
InnoDB transaction will not have the slave position recorded and thus
will fail to update it once it is replayed during binlog crash
recovery. The slave log position update is inherent part of changes
made by transaction, thus the correct place is the XA PREPARE stage.

- Store the slave log positions to the current InnoDB transaction in
  innobase_xa_prepare(), not innobase_commit_low().
- Write the slave log positions in the current InnoDB transaction to
  the transaction system header page in trx_prepare_off_kernel()
  instead of trx_commit_off_kernel().
- New crash injection site "crash_innodb_before_commit" at
  innobase_commit() that triggers just before the "real" transaction
  commits.
- New test case rpl_percona_crash_resistant_rpl to test both this bug
  fix and the feature in general.

Jenkins: http://jenkins.percona.com/job/percona-server-5.1-param/333/

Issue #22478

To post a comment you must log in.
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

Found one issue myself.

The testcase has one sync bug: lines 88--91 do not sync slave with master first, thus might result in slave shutdown while slave SQL thread is still executing.

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result'
--- Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result 2012-06-28 14:03:20 +0000
@@ -0,0 +1,42 @@
1include/master-slave.inc
2[connection master]
3DROP TABLE IF EXISTS t1;
4CREATE TABLE t1 (id INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)) ENGINE=InnoDB;
5INSERT INTO t1 VALUES ();
6SELECT COUNT(*) FROM t1;
7COUNT(*)
81
9include/rpl_restart_server.inc [server_number=2]
10include/start_slave.inc
11SELECT COUNT(*) FROM t1;
12COUNT(*)
131
14STOP SLAVE;
15include/wait_for_slave_to_stop.inc
16INSERT INTO t1 VALUES();
17SELECT COUNT(*) FROM t1;
18COUNT(*)
192
20SET GLOBAL debug="d,crash_commit_before";
21START SLAVE;
22include/rpl_start_server.inc [server_number=2]
23include/start_slave.inc
24SELECT COUNT(*) FROM t1;
25COUNT(*)
262
27STOP SLAVE;
28include/wait_for_slave_to_stop.inc
29INSERT INTO t1 VALUES();
30SELECT COUNT(*) FROM t1;
31COUNT(*)
323
33SET GLOBAL debug="d,crash_innodb_before_commit";
34START SLAVE;
35include/rpl_start_server.inc [server_number=2]
36include/start_slave.inc
37SELECT COUNT(*) FROM t1;
38COUNT(*)
393
40DROP TABLE t1;
41STOP SLAVE;
42include/wait_for_slave_to_stop.inc
043
=== added file 'Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt'
--- Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt 2012-06-28 14:03:20 +0000
@@ -0,0 +1,1 @@
1--innodb-overwrite-relay-log-info=TRUE --skip-core-file --skip-stack-trace
02
=== added file 'Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test'
--- Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test 2012-06-28 14:03:20 +0000
@@ -0,0 +1,95 @@
1# Tests for Percona crash-resistant replication feature
2--source include/have_innodb_plugin.inc
3--source include/master-slave.inc
4--source include/not_valgrind.inc
5--source include/not_crashrep.inc
6--source include/have_debug.inc
7
8#
9# Setup
10#
11
12--disable_query_log
13call mtr.add_suppression("InnoDB: Warning: innodb_overwrite_relay_log_info is enabled.");
14--enable_query_log
15
16connection master;
17
18--disable_warnings
19DROP TABLE IF EXISTS t1;
20--enable_warnings
21
22CREATE TABLE t1 (id INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)) ENGINE=InnoDB;
23
24#
25# Test the non-crashing case
26#
27
28INSERT INTO t1 VALUES ();
29SELECT COUNT(*) FROM t1;
30
31sync_slave_with_master;
32--let $rpl_server_number= 2
33--source include/rpl_restart_server.inc
34--source include/start_slave.inc
35SELECT COUNT(*) FROM t1;
36
37#
38# Test the crashing case where relay-log.info needs not to be overwritten
39#
40
41STOP SLAVE;
42--source include/wait_for_slave_to_stop.inc
43
44connection master;
45INSERT INTO t1 VALUES();
46SELECT COUNT(*) FROM t1;
47
48connection slave;
49SET GLOBAL debug="d,crash_commit_before";
50--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
51--error 0,2013
52START SLAVE;
53--source include/wait_until_disconnected.inc
54--enable_reconnect
55
56--let $rpl_server_number= 2
57--source include/rpl_start_server.inc
58--source include/start_slave.inc
59connection master;
60sync_slave_with_master;
61SELECT COUNT(*) FROM t1;
62
63#
64# Test crash with XA transaction recovery (bug 1012715)
65#
66STOP SLAVE;
67--source include/wait_for_slave_to_stop.inc
68connection master;
69INSERT INTO t1 VALUES();
70SELECT COUNT(*) FROM t1;
71
72connection slave;
73SET GLOBAL debug="d,crash_innodb_before_commit";
74--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
75--error 0,2013
76START SLAVE;
77--source include/wait_until_disconnected.inc
78--enable_reconnect
79
80--let $rpl_server_number= 2
81--source include/rpl_start_server.inc
82--source include/start_slave.inc
83SELECT COUNT(*) FROM t1;
84
85#
86# Cleanup
87#
88
89connection master;
90DROP TABLE t1;
91
92sync_slave_with_master;
93
94STOP SLAVE;
95--source include/wait_for_slave_to_stop.inc
096
=== modified file 'Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc'
--- Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2012-05-09 04:14:12 +0000
+++ Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2012-06-28 14:03:20 +0000
@@ -2770,26 +2770,6 @@
2770 return;2770 return;
2771 }2771 }
27722772
2773#ifdef HAVE_REPLICATION
2774#ifdef MYSQL_SERVER
2775 THD *thd=current_thd;
2776
2777 if (thd && thd->slave_thread) {
2778 /* Update the replication position info inside InnoDB */
2779 trx->mysql_master_log_file_name
2780 = active_mi->rli.group_master_log_name;
2781 trx->mysql_master_log_pos
2782 = ((ib_int64_t)active_mi->rli.group_master_log_pos +
2783 ((ib_int64_t)active_mi->rli.future_event_relay_log_pos -
2784 (ib_int64_t)active_mi->rli.group_relay_log_pos));
2785 trx->mysql_relay_log_file_name
2786 = active_mi->rli.group_relay_log_name;
2787 trx->mysql_relay_log_pos
2788 = (ib_int64_t)active_mi->rli.future_event_relay_log_pos;
2789 }
2790#endif /* MYSQL_SERVER */
2791#endif /* HAVE_REPLICATION */
2792
2793 trx_commit_for_mysql(trx);2773 trx_commit_for_mysql(trx);
2794}2774}
27952775
@@ -2898,6 +2878,9 @@
2898 if (all2878 if (all
2899 || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {2879 || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
29002880
2881 DBUG_EXECUTE_IF("crash_innodb_before_commit",
2882 DBUG_SUICIDE(););
2883
2901 /* We were instructed to commit the whole transaction, or2884 /* We were instructed to commit the whole transaction, or
2902 this is an SQL statement end and autocommit is on */2885 this is an SQL statement end and autocommit is on */
29032886
@@ -10657,6 +10640,34 @@
1065710640
10658 ut_ad(trx->active_trans);10641 ut_ad(trx->active_trans);
1065910642
10643 /* Update the replication position info inside InnoDB. This is
10644 different from the binlog position update that happens during
10645 XA COMMIT. In contrast to that, the slave position is an
10646 actual part of the changes made by this transaction and thus
10647 must be updated in the XA PREPARE stage. */
10648
10649 /* Since currently there might be only one slave SQL thread, we
10650 don't need to take any precautions (e.g. prepare_commit_mutex)
10651 to ensure position ordering. Revisit this in 5.6 which has
10652 both the multi-threaded replication to cause us problems and
10653 the group commit to solve them. */
10654
10655 if (thd->slave_thread) {
10656 const Relay_log_info* rli = &active_mi->rli;
10657
10658 trx->mysql_master_log_file_name
10659 = rli->group_master_log_name;
10660 trx->mysql_master_log_pos
10661 = ((ib_int64_t)rli->group_master_log_pos
10662 + ((ib_int64_t)
10663 rli->future_event_relay_log_pos
10664 - (ib_int64_t)rli->group_relay_log_pos));
10665 trx->mysql_relay_log_file_name
10666 = rli->group_relay_log_name;
10667 trx->mysql_relay_log_pos
10668 = (ib_int64_t)rli->future_event_relay_log_pos;
10669 }
10670
10660 error = (int) trx_prepare_for_mysql(trx);10671 error = (int) trx_prepare_for_mysql(trx);
10661 } else {10672 } else {
10662 /* We just mark the SQL statement ended and do not do a10673 /* We just mark the SQL statement ended and do not do a
1066310674
=== modified file 'Percona-Server/storage/innodb_plugin/trx/trx0trx.c'
--- Percona-Server/storage/innodb_plugin/trx/trx0trx.c 2012-04-02 02:09:15 +0000
+++ Percona-Server/storage/innodb_plugin/trx/trx0trx.c 2012-06-28 14:03:20 +0000
@@ -895,24 +895,6 @@
895 trx->mysql_log_file_name = NULL;895 trx->mysql_log_file_name = NULL;
896 }896 }
897897
898 if (trx->mysql_master_log_file_name[0] != '\0') {
899 /* This database server is a MySQL replication slave */
900 if (!sys_header) {
901 sys_header = trx_sysf_get(&mtr);
902 }
903 trx_sys_update_mysql_binlog_offset(
904 sys_header,
905 trx->mysql_relay_log_file_name,
906 trx->mysql_relay_log_pos,
907 TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr);
908 trx_sys_update_mysql_binlog_offset(
909 sys_header,
910 trx->mysql_master_log_file_name,
911 trx->mysql_master_log_pos,
912 TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr);
913 trx->mysql_master_log_file_name = "";
914 }
915
916 /* The following call commits the mini-transaction, making the898 /* The following call commits the mini-transaction, making the
917 whole transaction committed in the file-based world, at this899 whole transaction committed in the file-based world, at this
918 log sequence number. The transaction becomes 'durable' when900 log sequence number. The transaction becomes 'durable' when
@@ -2002,6 +1984,23 @@
20021984
2003 mutex_exit(&(rseg->mutex));1985 mutex_exit(&(rseg->mutex));
20041986
1987 if (trx->mysql_master_log_file_name[0] != '\0') {
1988 /* This database server is a MySQL replication slave */
1989 trx_sysf_t* sys_header = trx_sysf_get(&mtr);
1990
1991 trx_sys_update_mysql_binlog_offset(
1992 sys_header,
1993 trx->mysql_relay_log_file_name,
1994 trx->mysql_relay_log_pos,
1995 TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr);
1996 trx_sys_update_mysql_binlog_offset(
1997 sys_header,
1998 trx->mysql_master_log_file_name,
1999 trx->mysql_master_log_pos,
2000 TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr);
2001 trx->mysql_master_log_file_name = "";
2002 }
2003
2005 /*--------------*/2004 /*--------------*/
2006 mtr_commit(&mtr); /* This mtr commit makes the2005 mtr_commit(&mtr); /* This mtr commit makes the
2007 transaction prepared in the file-based2006 transaction prepared in the file-based

Subscribers

People subscribed via source and target branches