Merge lp:~laurynas-biveinis/percona-server/fake-changes-binlog-5.1 into lp:percona-server/5.1

Proposed by Laurynas Biveinis
Status: Superseded
Proposed branch: lp:~laurynas-biveinis/percona-server/fake-changes-binlog-5.1
Merge into: lp:percona-server/5.1
Diff against target: 309 lines (+238/-2)
5 files modified
Percona-Server/mysql-test/suite/binlog/r/binlog_percona_fake_changes.result (+72/-0)
Percona-Server/mysql-test/suite/binlog/t/binlog_percona_fake_changes.test (+106/-0)
Percona-Server/sql/handler.cc (+20/-1)
Percona-Server/sql/handler.h (+1/-0)
Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc (+39/-1)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/fake-changes-binlog-5.1
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Fixing
Vlad Lesin (community) g2 Approve
Review via email: mp+170779@code.launchpad.net

This proposal has been superseded by a proposal from 2013-08-23.

Description of the change

No BT or ST, but prerequisite for BT 20439, as well as being quite critical bug for the fake changes feature.

Fix

- bug 1190580 (Fake changes transactions are binlogged) and
- bug 1188162 (Verify in MTR that fake changes transactions are not
  binlogged).

Fixed bug 1188162 by adding a testcase
binlog_percona_fake_changes.test that executes a fake changes workload
and checks that no binlog events have resulted from this. The
testcase is adopted from a similar testcase in Facebook patch
rpl_percona_fake_changes.test with the difference that we check the
binlog only instead of setting up replication.

This testcase then immediatelly fails showing that fake changes
transactions are binlogged (bug 1190580). This is fixed by the
following.
- Adjusting innobase_xa_prepare() to return early with
  HA_ERR_WRONG_COMMAND instead of 0 (success) if fake changes are
  enabled and the function was called for a COMMIT statement or a DML
  statement with autocommit=1. Also clear the diagnostic area. Keep
  on returning success if innobase_xa_prepare() is called for
  individual statements in a multi-statement tranaction. This causes
  ha_commit_trans() not to write the transaction to binlog if fake
  changes are enabled and 2PC between the storage engines and binlog
  is used.
- Instead of skipping the 2PC prepare step for handlertons that are
  not marked as read-write, skip it only for handlertons that are not
  marked as read-write and have not fake changes enabled. The fake
  changes handlertons are never marked as read-write, which causes
  prepare to be skipped for them, making it impossible for its
  non-success return to do anything.
- Related to above, 2PC is only used if the total number of read-write
  handlertons in the transaction is at least two. Since fake changes
  handlertons do not contribute to this number, add a loop in
  ha_commit_trans() to bump rw_ha_count for each fake changes
  transaction, which will then force 2PC to be used.
- To support the above, add a new function pointer is_fake_change to
  the handlerton struct. This is also done by the Facebook patch.

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

To post a comment you must log in.
Revision history for this message
Vlad Lesin (vlad-lesin) :
review: Approve (g2)
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Laurynas,

Are there any reasons to implement a separate a loop over trans->ha_list to bump rw_ha_count instead of embedding it into the existing loop in ha_check_and_coalesce_trx_read_only()? I guess that would result in a cleaner and a bit more efficient code.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

This is a good suggestion, I will implement this.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'Percona-Server/mysql-test/suite/binlog/r/binlog_percona_fake_changes.result'
--- Percona-Server/mysql-test/suite/binlog/r/binlog_percona_fake_changes.result 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/binlog/r/binlog_percona_fake_changes.result 2013-08-22 12:56:44 +0000
@@ -0,0 +1,72 @@
1DROP TABLE IF EXISTS t1;
2DROP TABLE IF EXISTS t2;
3DROP TABLE IF EXISTS t3;
4CREATE TABLE t1 (a INT PRIMARY KEY, b int) ENGINE=InnoDB;
5INSERT INTO t1 VALUES (1,1);
6CREATE TABLE t2 (a INT PRIMARY KEY, b int) ENGINE=InnoDB;
7CREATE INDEX bx ON t2(b);
8INSERT INTO t2 VALUES (1,1);
9CREATE TABLE t3 (a INT PRIMARY KEY, b text) ENGINE=InnoDB;
10INSERT INTO t3 VALUES (1,'');
11RESET MASTER;
12SET innodb_fake_changes=1;
13SELECT * FROM t1;
14ERROR HY000: Got error 131 during COMMIT
15SELECT * FROM t2;
16ERROR HY000: Got error 131 during COMMIT
17SELECT * FROM t3;
18ERROR HY000: Got error 131 during COMMIT
19INSERT INTO t1 VALUES (2,2);
20ERROR HY000: Got error 131 during COMMIT
21INSERT INTO t2 VALUES (2,2);
22ERROR HY000: Got error 131 during COMMIT
23INSERT INTO t3 VALUES (2,lpad('a',10000, 'b'));
24ERROR HY000: Got error 131 during COMMIT
25UPDATE t1 SET a=0 where b=1;
26ERROR HY000: Got error 131 during COMMIT
27UPDATE t2 SET a=0 where b=1;
28ERROR HY000: Got error 131 during COMMIT
29UPDATE t3 SET a=0 where a=1;
30ERROR HY000: Got error 131 during COMMIT
31UPDATE t1 SET b=0 where a=1;
32ERROR HY000: Got error 131 during COMMIT
33UPDATE t2 SET b=0 where a=1;
34ERROR HY000: Got error 131 during COMMIT
35UPDATE t2 SET b=lpad('a',10000, 'z') where a=1;
36ERROR HY000: Got error 131 during COMMIT
37UPDATE t1 SET b=0 where a=2;
38ERROR HY000: Got error 131 during COMMIT
39UPDATE t2 SET b=0 where a=2;
40ERROR HY000: Got error 131 during COMMIT
41UPDATE t2 SET b=lpad('a',10000, 'z') where a=2;
42ERROR HY000: Got error 131 during COMMIT
43DELETE FROM t1 where b=2;
44ERROR HY000: Got error 131 during COMMIT
45DELETE FROM t2 where b=2;
46ERROR HY000: Got error 131 during COMMIT
47DELETE FROM t1 where a=2;
48ERROR HY000: Got error 131 during COMMIT
49DELETE FROM t2 where a=2;
50ERROR HY000: Got error 131 during COMMIT
51DELETE FROM t3 where a=2;
52ERROR HY000: Got error 131 during COMMIT
53REPLACE INTO t1 values (2,3);
54ERROR HY000: Got error 131 during COMMIT
55REPLACE INTO t2 values (2,3);
56ERROR HY000: Got error 131 during COMMIT
57REPLACE INTO t3 values (2,lpad('a',9000,'q'));
58ERROR HY000: Got error 131 during COMMIT
59INSERT INTO t1 VALUES (1,1) ON DUPLICATE KEY UPDATE b=2;
60ERROR HY000: Got error 131 during COMMIT
61INSERT INTO t2 VALUES (1,1) ON DUPLICATE KEY UPDATE b=2;
62ERROR HY000: Got error 131 during COMMIT
63INSERT INTO t3 VALUES (1,1) ON DUPLICATE KEY UPDATE b=lpad('b',11000,'c');
64ERROR HY000: Got error 131 during COMMIT
65show binlog events from <binlog_start>;
66Log_name Pos Event_type Server_id End_log_pos Info
67must_be_1
681
69SET innodb_fake_changes=default;
70DROP TABLE t1;
71DROP TABLE t2;
72DROP TABLE t3;
073
=== added file 'Percona-Server/mysql-test/suite/binlog/t/binlog_percona_fake_changes.test'
--- Percona-Server/mysql-test/suite/binlog/t/binlog_percona_fake_changes.test 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/binlog/t/binlog_percona_fake_changes.test 2013-08-22 12:56:44 +0000
@@ -0,0 +1,106 @@
1#
2# Test that fake changes are not written to binlog
3# Based on rpl_percona_fake_changes.test in Facebook patch
4# https://bugs.launchpad.net/percona-server/+bug/1190580
5# https://bugs.launchpad.net/percona-server/+bug/1188162
6#
7
8--source include/have_log_bin.inc
9--source include/have_innodb_plugin.inc
10
11--disable_warnings
12DROP TABLE IF EXISTS t1;
13DROP TABLE IF EXISTS t2;
14DROP TABLE IF EXISTS t3;
15--enable_warnings
16
17CREATE TABLE t1 (a INT PRIMARY KEY, b int) ENGINE=InnoDB;
18INSERT INTO t1 VALUES (1,1);
19
20CREATE TABLE t2 (a INT PRIMARY KEY, b int) ENGINE=InnoDB;
21CREATE INDEX bx ON t2(b);
22INSERT INTO t2 VALUES (1,1);
23
24CREATE TABLE t3 (a INT PRIMARY KEY, b text) ENGINE=InnoDB;
25INSERT INTO t3 VALUES (1,'');
26
27RESET MASTER;
28
29let $binlog_pos_1= query_get_value("SHOW MASTER STATUS", Position, 1);
30
31SET innodb_fake_changes=1;
32
33--error ER_ERROR_DURING_COMMIT
34SELECT * FROM t1;
35--error ER_ERROR_DURING_COMMIT
36SELECT * FROM t2;
37--error ER_ERROR_DURING_COMMIT
38SELECT * FROM t3;
39
40--error ER_ERROR_DURING_COMMIT
41INSERT INTO t1 VALUES (2,2);
42--error ER_ERROR_DURING_COMMIT
43INSERT INTO t2 VALUES (2,2);
44--error ER_ERROR_DURING_COMMIT
45INSERT INTO t3 VALUES (2,lpad('a',10000, 'b'));
46
47--error ER_ERROR_DURING_COMMIT
48UPDATE t1 SET a=0 where b=1;
49--error ER_ERROR_DURING_COMMIT
50UPDATE t2 SET a=0 where b=1;
51--error ER_ERROR_DURING_COMMIT
52UPDATE t3 SET a=0 where a=1;
53
54--error ER_ERROR_DURING_COMMIT
55UPDATE t1 SET b=0 where a=1;
56--error ER_ERROR_DURING_COMMIT
57UPDATE t2 SET b=0 where a=1;
58--error ER_ERROR_DURING_COMMIT
59UPDATE t2 SET b=lpad('a',10000, 'z') where a=1;
60
61--error ER_ERROR_DURING_COMMIT
62UPDATE t1 SET b=0 where a=2;
63--error ER_ERROR_DURING_COMMIT
64UPDATE t2 SET b=0 where a=2;
65--error ER_ERROR_DURING_COMMIT
66UPDATE t2 SET b=lpad('a',10000, 'z') where a=2;
67
68--error ER_ERROR_DURING_COMMIT
69DELETE FROM t1 where b=2;
70--error ER_ERROR_DURING_COMMIT
71DELETE FROM t2 where b=2;
72
73--error ER_ERROR_DURING_COMMIT
74DELETE FROM t1 where a=2;
75--error ER_ERROR_DURING_COMMIT
76DELETE FROM t2 where a=2;
77--error ER_ERROR_DURING_COMMIT
78DELETE FROM t3 where a=2;
79
80--error ER_ERROR_DURING_COMMIT
81REPLACE INTO t1 values (2,3);
82--error ER_ERROR_DURING_COMMIT
83REPLACE INTO t2 values (2,3);
84--error ER_ERROR_DURING_COMMIT
85REPLACE INTO t3 values (2,lpad('a',9000,'q'));
86
87--error ER_ERROR_DURING_COMMIT
88INSERT INTO t1 VALUES (1,1) ON DUPLICATE KEY UPDATE b=2;
89--error ER_ERROR_DURING_COMMIT
90INSERT INTO t2 VALUES (1,1) ON DUPLICATE KEY UPDATE b=2;
91--error ER_ERROR_DURING_COMMIT
92INSERT INTO t3 VALUES (1,1) ON DUPLICATE KEY UPDATE b=lpad('b',11000,'c');
93
94--source include/show_binlog_events.inc
95
96let $binlog_pos_2= query_get_value("SHOW MASTER STATUS", Position, 1);
97
98--disable_query_log
99eval SELECT $binlog_pos_1 = $binlog_pos_2 as must_be_1;
100--enable_query_log
101
102SET innodb_fake_changes=default;
103
104DROP TABLE t1;
105DROP TABLE t2;
106DROP TABLE t3;
0107
=== modified file 'Percona-Server/sql/handler.cc'
--- Percona-Server/sql/handler.cc 2013-06-03 03:53:55 +0000
+++ Percona-Server/sql/handler.cc 2013-08-22 12:56:44 +0000
@@ -1031,6 +1031,18 @@
1031 {1031 {
1032 if (ha_info->is_trx_read_write())1032 if (ha_info->is_trx_read_write())
1033 ++rw_ha_count;1033 ++rw_ha_count;
1034 else
1035 {
1036 /*
1037 If we have any fake changes handlertons, they will not be marked as
1038 read-write, potentially skipping 2PC and causing the fake transaction
1039 to be binlogged. Force using 2PC in this case by bumping rw_ha_count
1040 for each fake changes handlerton.
1041 */
1042 handlerton *ht= ha_info->ht();
1043 if (unlikely(ht->is_fake_change && ht->is_fake_change(ht, thd)))
1044 ++rw_ha_count;
1045 }
10341046
1035 if (! all)1047 if (! all)
1036 {1048 {
@@ -1168,7 +1180,14 @@
1168 transaction is read-only. This allows for simpler1180 transaction is read-only. This allows for simpler
1169 implementation in engines that are always read-only.1181 implementation in engines that are always read-only.
1170 */1182 */
1171 if (! ha_info->is_trx_read_write())1183 /*
1184 But do call two-phase commit if the handlerton has fake changes
1185 enabled even if it's not marked as read-write. This will ensure that
1186 the fake changes handlerton prepare will fail, preventing binlogging
1187 and committing the transaction in other engines.
1188 */
1189 if (! ha_info->is_trx_read_write()
1190 && !(ht->is_fake_change && ht->is_fake_change(ht, thd)))
1172 continue;1191 continue;
1173 /*1192 /*
1174 Sic: we know that prepare() is not NULL since otherwise1193 Sic: we know that prepare() is not NULL since otherwise
11751194
=== modified file 'Percona-Server/sql/handler.h'
--- Percona-Server/sql/handler.h 2013-01-22 16:28:47 +0000
+++ Percona-Server/sql/handler.h 2013-08-22 12:56:44 +0000
@@ -695,6 +695,7 @@
695 class Item *cond);695 class Item *cond);
696 my_bool (*flush_changed_page_bitmaps)(void);696 my_bool (*flush_changed_page_bitmaps)(void);
697 my_bool (*purge_changed_page_bitmaps)(ulonglong lsn);697 my_bool (*purge_changed_page_bitmaps)(ulonglong lsn);
698 my_bool (*is_fake_change)(handlerton *hton, THD *thd);
698 uint32 flags; /* global handler flags */699 uint32 flags; /* global handler flags */
699 /*700 /*
700 Those handlerton functions below are properly initialized at handler701 Those handlerton functions below are properly initialized at handler
701702
=== modified file 'Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc'
--- Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2013-08-05 13:11:52 +0000
+++ Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2013-08-22 12:56:44 +0000
@@ -335,6 +335,19 @@
335/*================================*/335/*================================*/
336 ulonglong lsn); /*!< in: LSN to purge files up to */336 ulonglong lsn); /*!< in: LSN to purge files up to */
337337
338
339/*****************************************************************//**
340Check whether this is a fake change transaction.
341@return TRUE if a fake change transaction */
342static
343my_bool
344innobase_is_fake_change(
345/*====================*/
346 handlerton *hton, /*!< in: InnoDB handlerton */
347 THD* thd); /*!< in: MySQL thread handle of the user for
348 whom the transaction is being committed */
349
350
338static const char innobase_hton_name[]= "InnoDB";351static const char innobase_hton_name[]= "InnoDB";
339352
340/*************************************************************//**353/*************************************************************//**
@@ -2353,6 +2366,7 @@
2353 = innobase_flush_changed_page_bitmaps;2366 = innobase_flush_changed_page_bitmaps;
2354 innobase_hton->purge_changed_page_bitmaps2367 innobase_hton->purge_changed_page_bitmaps
2355 = innobase_purge_changed_page_bitmaps;2368 = innobase_purge_changed_page_bitmaps;
2369 innobase_hton->is_fake_change = innobase_is_fake_change;
23562370
2357 ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);2371 ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
23582372
@@ -2962,6 +2976,23 @@
2962 return (my_bool)log_online_purge_changed_page_bitmaps(lsn);2976 return (my_bool)log_online_purge_changed_page_bitmaps(lsn);
2963}2977}
29642978
2979/*****************************************************************//**
2980Check whether this is a fake change transaction.
2981@return TRUE if a fake change transaction */
2982static
2983my_bool
2984innobase_is_fake_change(
2985/*====================*/
2986 handlerton *hton __attribute__((unused)),
2987 /*!< in: InnoDB handlerton */
2988 THD* thd) /*!< in: MySQL thread handle of the user for
2989 whom the transaction is being committed */
2990{
2991 trx_t* trx = check_trx_exists(thd);
2992 return trx->fake_changes;
2993}
2994
2995
2965/****************************************************************//**2996/****************************************************************//**
2966Copy the current replication position from MySQL to a transaction. */2997Copy the current replication position from MySQL to a transaction. */
2967static2998static
@@ -10867,7 +10898,14 @@
10867 return(0);10898 return(0);
10868 }10899 }
1086910900
10870 if (trx->fake_changes) {10901 if (UNIV_UNLIKELY(trx->fake_changes)) {
10902
10903 if (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT
10904 | OPTION_BEGIN))) {
10905
10906 thd->main_da.reset_diagnostics_area();
10907 return(HA_ERR_WRONG_COMMAND);
10908 }
10871 return(0);10909 return(0);
10872 }10910 }
1087310911

Subscribers

People subscribed via source and target branches