#At file:///home/lsoares/Workspace/bzr/work/bugfixing/46554/mysql-next-mr-wl5092/ based on revid:luis.soares@stripped
3151 Luis Soares 2010-06-01
BUG#46554: RBR: pending rows event can be flushed too soon
sometimes.
While packing a record into an rows event, the server performs
several checks to see if a new rows event is needed. Among the
conditions checked, there's one that deals with the pending
event ('p') bitmaps and the table ('t') the server accessed for
the current record. If they are different, then 'p' is flushed
and a new pending event, 'e', is created. If not, then the same
pending event is used. However, the only bitmaps compared are
't'->write_set against 'p'->get_cols(), which in some cases,
means we are comparing write_sets against read_sets! In current
versions of the server this may not be a big of a deal (as both
read and write sets are always fully set).
On the other hand, for the 6.0 codebase this is not the
case. This means that if the table has a PK, only some columns
will be flagged in the read_set. In these cases the write_set and
the read_set will most likely not match causing the pending to be
flushed. Additionally, the write_set is meaningless for delete
events and the read_set is meaningless for write events! So
comparison must take into account the type of the event to choose
what bitmap to take from the table to make the comparison.
As stated, this is the case for 6.0 codebase, but also WL#5092
based tree is affected because the user is given the option to
choose whether to log partial (so not all columns will be flagged
in the read and write set) or full rows, accentuating this
problem.
Finally, This seems to be in fact a regression introduced by
patch for BUG#33055 plus a post-merge fix that is related:
- sp1r-mkindahl@stripped
Since BUG#33055 was backported to WL#5092 tree, this regression
tagged along.
To fix this problem, we deploy a member function in
Rows_log_event that is used to perform the correct comparison of
the pending and table bitmaps.
@ mysql-test/suite/binlog/t/binlog_row_binlog.test
Added test case from the bug report.
@ mysql-test/suite/perfschema/r/binlog_mix.result
Removing spurious events from the result file.
@ mysql-test/suite/perfschema/r/binlog_row.result
Removing spurious events from the result file.
@ sql/log_event.h
1. Added utility member function to compare read and write bitmaps.
2. Added get_cols_ai accessor for m_cols_ai.
@ sql/sql_class.cc
Replaced bitmap check with the proper call to the newly introduced
member function that compares bitmaps according to the event type.
modified:
mysql-test/suite/binlog/r/binlog_row_binlog.result
mysql-test/suite/binlog/t/binlog_row_binlog.test
mysql-test/suite/perfschema/r/binlog_mix.result
mysql-test/suite/perfschema/r/binlog_row.result
sql/log_event.h
sql/sql_class.cc
=== modified file 'mysql-test/suite/binlog/r/binlog_row_binlog.result'
--- a/mysql-test/suite/binlog/r/binlog_row_binlog.result 2010-04-20 09:10:43 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result 2010-06-01 18:21:20 +0000
@@ -1,3 +1,25 @@
+SELECT @@session.binlog_row_image INTO @saved_binlog_row_image;
+SET binlog_row_image= MINIMAL;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image MINIMAL
+RESET MASTER;
+CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(100)) ENGINE=Innodb;
+INSERT INTO t1 VALUES (1,'a'), (2,'b'), (3, 'c');
+DELETE FROM t1;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(100)) ENGINE=Innodb
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Xid # # COMMIT /* XID */
+DROP TABLE t1;
+SET binlog_row_image= @saved_binlog_row_image;
drop table if exists t1, t2;
reset master;
create table t1 (a int) engine=innodb;
=== modified file 'mysql-test/suite/binlog/t/binlog_row_binlog.test'
--- a/mysql-test/suite/binlog/t/binlog_row_binlog.test 2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_binlog.test 2010-06-01 18:21:20 +0000
@@ -1,5 +1,23 @@
+-- source include/have_binlog_format_row.inc
+
+#
+# BUG#46554: Unecessary Delete_rows events in 6.0-codebase may harm replication's performance
+
+SELECT @@session.binlog_row_image INTO @saved_binlog_row_image;
+SET binlog_row_image= MINIMAL;
+SHOW VARIABLES LIKE 'binlog_row_image';
+RESET MASTER;
+CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(100)) ENGINE=Innodb;
+## before the patch there would be 3 write row events
+INSERT INTO t1 VALUES (1,'a'), (2,'b'), (3, 'c');
+## before the patch there would be 3 delete row events
+DELETE FROM t1;
+-- source include/show_binlog_events.inc
+DROP TABLE t1;
+
+SET binlog_row_image= @saved_binlog_row_image;
+
# This is a wrapper for binlog.test so that the same test case can be used
# For both statement and row based bin logs 9/19/2005 [jbm]
--- source include/have_binlog_format_row.inc
-- source extra/binlog_tests/binlog.test
=== modified file 'mysql-test/suite/perfschema/r/binlog_mix.result'
--- a/mysql-test/suite/perfschema/r/binlog_mix.result 2010-05-26 09:29:59 +0000
+++ b/mysql-test/suite/perfschema/r/binlog_mix.result 2010-06-01 18:21:20 +0000
@@ -25,18 +25,6 @@ show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (performance_schema.SETUP_INSTRUMENTS)
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; drop table if exists test.t1
@@ -55,17 +43,5 @@ master-bin.000001 # Query # # use `test`
master-bin.000001 # Query # # use `test`; drop table test.t2
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (performance_schema.SETUP_INSTRUMENTS)
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
=== modified file 'mysql-test/suite/perfschema/r/binlog_row.result'
--- a/mysql-test/suite/perfschema/r/binlog_row.result 2010-05-26 09:29:59 +0000
+++ b/mysql-test/suite/perfschema/r/binlog_row.result 2010-06-01 18:21:20 +0000
@@ -25,18 +25,6 @@ show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (performance_schema.SETUP_INSTRUMENTS)
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; drop table if exists test.t1
@@ -55,17 +43,5 @@ master-bin.000001 # Query # # use `test`
master-bin.000001 # Query # # use `test`; drop table test.t2
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (performance_schema.SETUP_INSTRUMENTS)
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
-master-bin.000001 # Update_rows # # table_id: #
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
=== modified file 'sql/log_event.h'
--- a/sql/log_event.h 2010-05-26 13:36:29 +0000
+++ b/sql/log_event.h 2010-06-01 18:21:20 +0000
@@ -3544,9 +3544,58 @@ public:
virtual int get_data_size();
MY_BITMAP const *get_cols() const { return &m_cols; }
+ MY_BITMAP const *get_cols_ai() const { return &m_cols_ai; }
size_t get_width() const { return m_width; }
ulong get_table_id() const { return m_table_id; }
+#if defined(MYSQL_SERVER)
+ /*
+ This member function compares the table's read/write_set
+ with this event's m_cols and m_cols_ai. Comparison takes
+ into account what type of rows event is this: Delete, Write or
+ Update, therefore it uses the correct m_cols[_ai] according
+ to the event type code.
+
+ Note that this member function should only be called for the
+ following events:
+ - Delete_rows_log_event
+ - Wrirte_rows_log_event
+ - Update_rows_log_event
+
+ @param[IN] table The table to compare this events bitmaps
+ against.
+
+ @return TRUE if sets match, FALSE otherwise. (following
+ bitmap_cmp return logic).
+
+ */
+ virtual bool read_write_bitmaps_cmp(TABLE *table)
+ {
+ bool res= FALSE;
+
+ switch (get_type_code())
+ {
+ case DELETE_ROWS_EVENT:
+ res= bitmap_cmp(get_cols(), table->read_set);
+ break;
+ case UPDATE_ROWS_EVENT:
+ res= (bitmap_cmp(get_cols(), table->read_set) ||
+ bitmap_cmp(get_cols_ai(), table->write_set));
+ break;
+ case WRITE_ROWS_EVENT:
+ res= bitmap_cmp(get_cols(), table->write_set);
+ break;
+ default:
+ /*
+ We should just compare bitmaps for Delete, Write
+ or Update rows events.
+ */
+ DBUG_ASSERT(0);
+ }
+ return res;
+ }
+#endif
+
#ifdef MYSQL_SERVER
virtual bool write_data_header(IO_CACHE *file);
virtual bool write_data_body(IO_CACHE *file);
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2010-05-19 21:35:03 +0000
+++ b/sql/sql_class.cc 2010-06-01 18:21:20 +0000
@@ -4034,7 +4034,7 @@ THD::binlog_prepare_pending_rows_event(T
pending->get_table_id() != table->s->table_map_id ||
pending->get_type_code() != type_code ||
pending->get_data_size() + needed > opt_binlog_rows_event_max_size ||
- !bitmap_cmp(pending->get_cols(), table->write_set))
+ pending->read_write_bitmaps_cmp(table) == FALSE)
{
/* Create a new RowsEventT... */
Rows_log_event* const
Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20100601182120-a67ma5ixgfdg7nni.bundle