List:Commits« Previous MessageNext Message »
From:Luis Soares Date:April 21 2010 12:54am
Subject:bzr commit into mysql-5.1-rpl-wl5092 branch (luis.soares:3187)
Bug#49100
View as plain text  
#At file:///home/lsoares/Workspace/bzr/work/bugfixing/49100/mysql-5.1-rpl-wl5092/ based on revid:luis.soares@stripped

 3187 Luis Soares	2010-04-21
      BUG#49100: RBR: Unexpected behavior when AI contains no usable
                 data for slave columns
            
      RBR was not fully compliant with empty before and after
      images (BI and AI) in row events. Several faulty scenarios
      surfaced during WL#5092 implementation, especially when MINIMAL
      images were used:
            
        S1. Inserting an empty row on the master would cause slave to
            skip the event (empty AI);
            
            Problem: Master and slave would become out of sync.
      
            Expected: slave(s) shall apply the insert and fill its
            table with default values as master did.
            
        S2. Master inserts values just for columns that slave doesn't
            have (unusable AI at the slave).
            
            Problem: In a chained replication scenario (m -> s1 -> s2),
            m and s1 would be in sync, but s2 would not.
      
            Expected: slave(s) shall apply the insert and fill its
            table with default values as master did for columns that
            user did not provide data.
             
        S3. Master updates columns that only it knows about (unusable
            AI at the slave) but references columns that it shares with
            the slave (usable BI at the slave). This would trigger an
            assertion on a third slave in chained replication: m -> s1
            -> s2, s2 would abort.
      
            Problem: in chained replication scenario (m -> s1 -> s2),
            s2 would trigger an assertion while unpacking the row
            logged by s1.
            
            Expected: slave s1 shall not update any row and slave s2
            shall not assert.
            
        S4. Master updates and references columns that only it knows
            about (unusable AI and BI at the slave).
      
            Problem: although AI does not contain any data for updating
            the slave (update becomes no-op), the slave stops with
            error, because BI does not also contain relevant data for
            finding the record.
            
            Expected: slave(s) shall skip the event, thence not even
            trying to update its tables with any value.
            
        S5. Master references columns that only it knows
            about (unusable BI at the slave) and updates columns shared
            with the slave (usable AI at the slave). Slave must stop.
            
            Problem: none really. Just adding the test case for
            coverage purposes.
      
            Expected: slave(s) shall fail with HA_ERR_END_OF_FILE.
            
      We fix S1 to S3 by relaxing some asserts that were triggered on
      when processing empty images and by doing some changes to
      accomodate the fact that some images might be empty. 
      
      For S4, we deploy a check in Update_rows_log_event::do_exec_row
      that verifies if there is any value in the AI. If there is not,
      then the event is skipped (neither BI nor AI is are processed).
      
      As for S5, we just add the test case.
            
      For mysqlbinlog --verbose --base64=decode-rows we print out an
      INSERT INTO t VALUES () when a write rows event contains an empty
      AI.
     @ mysql-test/suite/rpl/r/rpl_row_img.result
        Updates to result files.
     @ mysql-test/suite/rpl/t/rpl_row_img.test
        Added test cases.
     @ sql/log_event.cc
        1. Added printout for INSERT INTO ... VALUES () when AI is empty for
           Write_rows_log_events.
        2. Changed assertion from 'm_curr_row < ...' to 'm_curr_row <= ...'
        3. Calculation of estimated rows for bulk insert is now conditional,
           and dependent of whether m_curr_row < m_rows_end or not.
        4. In the Update_rows_log_event, changed it to take into consideration
           if there are any values in AI. If there are not, then skip event.
     @ sql/log_event.h
        Changed assertion to from 'm_curr_row < ...' to ' m_curr_row <= ...'.
     @ sql/rpl_record.cc
        Do not unpack if master did not send any bit set in the write_set.

    modified:
      mysql-test/suite/rpl/r/rpl_row_img.result
      mysql-test/suite/rpl/t/rpl_row_img.test
      sql/log_event.cc
      sql/log_event.h
      sql/rpl_record.cc
=== modified file 'mysql-test/suite/rpl/r/rpl_row_img.result'
--- a/mysql-test/suite/rpl/r/rpl_row_img.result	2010-03-30 16:06:36 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_img.result	2010-04-21 00:54:25 +0000
@@ -24179,3 +24179,259 @@ FLUSH TABLES;
 SHOW VARIABLES LIKE 'binlog_row_image';
 Variable_name	Value
 binlog_row_image	FULL
+include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+RESET MASTER;
+RESET SLAVE;
+include/start_slave.inc
+include/start_slave.inc
+DROP TABLE IF EXISTS t1;
+CON: 'mysqld_a', IMG: 'MINIMAL', RESTART SLAVE: 'N'
+SET SESSION binlog_row_image= 'MINIMAL';
+SET GLOBAL binlog_row_image= 'MINIMAL';
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name	Value
+binlog_row_image	MINIMAL
+CON: 'mysqld_b', IMG: 'MINIMAL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'MINIMAL';
+SET GLOBAL binlog_row_image= 'MINIMAL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name	Value
+binlog_row_image	MINIMAL
+CON: 'mysqld_c', IMG: 'MINIMAL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'MINIMAL';
+SET GLOBAL binlog_row_image= 'MINIMAL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name	Value
+binlog_row_image	MINIMAL
+#### case #1: AI: no values logged
+CREATE TABLE t1 (c1 int DEFAULT 100);
+INSERT INTO t1 VALUES ();
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1
+100
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+100
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+100
+DROP TABLE t1;
+#### case #2: AI: not empty but slave does not have usable data for its columns (INSERT)
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int, primary key(c2));
+SET SQL_LOG_BIN=1;
+INSERT INTO t1(c2) VALUES (1);
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2
+100	1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+100
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+100
+DROP TABLE t1;
+#### case #3: BI: usable columns on the slave, AI: no usable columns on the slave
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int);
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES (1,1);
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2
+1	1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+1
+UPDATE t1 SET c2=2 WHERE c1=1 AND c2=1;
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2
+1	2
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+1
+DROP TABLE t1;
+#### case #4: AI, BI: no usable columns on the slave (NOOP UPDATE).
+####          
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int, c3 int, primary key(c2));
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES (1,1,1);
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2	c3
+1	1	1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+1
+UPDATE t1 SET c3=300 WHERE c2=1;
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2	c3
+1	1	300
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+1
+DROP TABLE t1;
+#### case #5: BI: no usable columns on the slave, AI: usable columns on the slave (slave must stop).
+####          
+CREATE TABLE t1 (c1 INT DEFAULT 100);
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 INT DEFAULT 100);
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 INT DEFAULT 100, c2 INT PRIMARY KEY);
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES (1,1);
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2
+1	1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	3
+SELECT * FROM t1;
+c1
+1
+UPDATE t1 SET c1=300 WHERE c2=1;
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SELECT * FROM t1;
+c1	c2
+300	1
+SET SQL_LOG_BIN=0;
+call mtr.add_suppression("Slave: Can\'t find record in \'t1\' Error_code: 1032");
+SET SQL_LOG_BIN=1;
+### SLAVE STOPPED HAS EXPECTED!
+include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+RESET MASTER;
+RESET SLAVE;
+include/start_slave.inc
+include/start_slave.inc
+DROP TABLE IF EXISTS t1;
+CON: 'mysqld_a', IMG: 'FULL', RESTART SLAVE: 'N'
+SET SESSION binlog_row_image= 'FULL';
+SET GLOBAL binlog_row_image= 'FULL';
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name	Value
+binlog_row_image	FULL
+CON: 'mysqld_b', IMG: 'FULL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'FULL';
+SET GLOBAL binlog_row_image= 'FULL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name	Value
+binlog_row_image	FULL
+CON: 'mysqld_c', IMG: 'FULL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'FULL';
+SET GLOBAL binlog_row_image= 'FULL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name	Value
+binlog_row_image	FULL

=== modified file 'mysql-test/suite/rpl/t/rpl_row_img.test'
--- a/mysql-test/suite/rpl/t/rpl_row_img.test	2010-03-30 16:06:36 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_img.test	2010-04-21 00:54:25 +0000
@@ -1,12 +1,7 @@
 #
-# Test Description
-# ================
-#  
-#   In this file we will run tests that mix engines, indexes
-#   and blobs.
-#  
-#   See WL#5096 for details.
+# This file contains tests for WL#5096 and bug fixes. 
 #
+
 -- source include/rpl_chained_3_hosts.inc
 -- source include/have_binlog_format_row.inc
 
@@ -18,6 +13,18 @@
 -- source include/have_innodb.inc
 -- connection mysqld_a
 
+#
+# WL#5096
+#
+#   Test Description
+#   ================
+# 
+#   WL#5096 Tests.
+# 
+#   In this file we will run tests that mix engines, indexes
+#   and blobs.
+#
+
 -- echo ###################################################################
 -- echo ###################################################################
 -- echo # engines and binlog-row-image mixes                              #
@@ -41,3 +48,247 @@
 -- echo ###################################################################
 -- let $row_img_test_script= extra/rpl_tests/rpl_row_img_blobs.test
 -- source include/rpl_row_img_general_loop.inc
+
+#
+# BUG#49100: RBR: Unexpected behavior when AI contains no usable data 
+#            for slave columns
+#
+
+-- connection mysqld_c
+-- source include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_b
+-- source include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_a
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_c
+-- source include/start_slave.inc
+
+-- connection mysqld_b
+-- source include/start_slave.inc
+
+-- disable_warnings
+DROP TABLE IF EXISTS t1;
+-- enable_warnings
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_a
+
+-- let $row_img_set=mysqld_a:MINIMAL:N,mysqld_b:MINIMAL:Y,mysqld_c:MINIMAL:Y
+-- source include/rpl_row_img_set.inc
+
+-- echo #### case #1: AI: no values logged
+
+CREATE TABLE t1 (c1 int DEFAULT 100);
+INSERT INTO t1 VALUES ();
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+
+-- echo #### case #2: AI: not empty but slave does not have usable data for its columns (INSERT)
+
+-- connection mysqld_c
+CREATE TABLE t1 (c1 int DEFAULT 100);
+
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+
+-- connection mysqld_a
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int, primary key(c2));
+SET SQL_LOG_BIN=1;
+
+INSERT INTO t1(c2) VALUES (1);
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+
+-- echo #### case #3: BI: usable columns on the slave, AI: no usable columns on the slave
+
+-- connection mysqld_c
+CREATE TABLE t1 (c1 int DEFAULT 100);
+
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+
+-- connection mysqld_a
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int);
+SET SQL_LOG_BIN=1;
+
+INSERT INTO t1 VALUES (1,1);
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+UPDATE t1 SET c2=2 WHERE c1=1 AND c2=1;
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+
+-- echo #### case #4: AI, BI: no usable columns on the slave (NOOP UPDATE).
+-- echo ####          
+
+-- connection mysqld_c
+CREATE TABLE t1 (c1 int DEFAULT 100);
+
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+
+-- connection mysqld_a
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int, c3 int, primary key(c2));
+SET SQL_LOG_BIN=1;
+
+INSERT INTO t1 VALUES (1,1,1);
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+UPDATE t1 SET c3=300 WHERE c2=1;
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+
+-- echo #### case #5: BI: no usable columns on the slave, AI: usable columns on the slave (slave must stop).
+-- echo ####          
+
+-- connection mysqld_c
+CREATE TABLE t1 (c1 INT DEFAULT 100);
+
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 INT DEFAULT 100);
+SET SQL_LOG_BIN=1;
+
+-- connection mysqld_a
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 INT DEFAULT 100, c2 INT PRIMARY KEY);
+SET SQL_LOG_BIN=1;
+
+INSERT INTO t1 VALUES (1,1);
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+UPDATE t1 SET c1=300 WHERE c2=1;
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+call mtr.add_suppression("Slave: Can\'t find record in \'t1\' Error_code: 1032");
+SET SQL_LOG_BIN=1;
+-- source include/wait_for_slave_sql_to_stop.inc
+-- let $errno=query_get_value("show slave status", Last_SQL_Errno, 1)
+if (`SELECT $errno <> 1032`)
+{
+  -- echo ### UNEXPECTED ERROR AT THE SLAVE: $errno
+  SHOW SLAVE STATUS;
+  -- die
+}
+-- echo ### SLAVE STOPPED HAS EXPECTED!
+
+## CLEAN UP
+
+-- connection mysqld_c
+-- source include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_b
+-- source include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_a
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_c
+-- source include/start_slave.inc
+
+-- connection mysqld_b
+-- source include/start_slave.inc
+
+-- connection mysqld_a
+-- disable_warnings
+DROP TABLE IF EXISTS t1;
+-- enable_warnings
+-- source include/rpl_chained_3_hosts_sync.inc
+
+-- let $row_img_set=mysqld_a:FULL:N,mysqld_b:FULL:Y,mysqld_c:FULL:Y
+-- source include/rpl_row_img_set.inc
+

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2010-03-04 17:00:32 +0000
+++ b/sql/log_event.cc	2010-04-21 00:54:25 +0000
@@ -1953,6 +1953,14 @@ void Rows_log_event::print_verbose(IO_CA
     return;
   }
 
+  /* If the write rows event contained no values for the AI */
+  if ((type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end))
+  {
+    my_b_printf(file, "### INSERT INTO `%s`.`%s` VALUES ()\n", 
+                      map->get_db_name(), map->get_table_name());
+    goto end;
+  }
+
   for (const uchar *value= m_rows_buf; value < m_rows_end; )
   {
     size_t length;
@@ -7636,7 +7644,7 @@ int Rows_log_event::do_apply_event(Relay
 
     // row processing loop
 
-    while (error == 0 && m_curr_row < m_rows_end)
+    while (error == 0)
     {
       /* in_use can have been set to NULL in close_tables_for_reopen */
       THD* old_thd= table->in_use;
@@ -7687,7 +7695,7 @@ int Rows_log_event::do_apply_event(Relay
   
       // at this moment m_curr_row_end should be set
       DBUG_ASSERT(error || m_curr_row_end != NULL); 
-      DBUG_ASSERT(error || m_curr_row < m_curr_row_end);
+      DBUG_ASSERT(error || m_curr_row <= m_curr_row_end);
       DBUG_ASSERT(error || m_curr_row_end <= m_rows_end);
   
       m_curr_row= m_curr_row_end;
@@ -7695,6 +7703,9 @@ int Rows_log_event::do_apply_event(Relay
       if (error == 0 && !transactional_table)
         thd->transaction.all.modified_non_trans_table=
           thd->transaction.stmt.modified_non_trans_table= TRUE;
+
+      if (m_curr_row == m_rows_end)
+        break;
     } // row processing loop
 
     {/**
@@ -8695,7 +8706,13 @@ Rows_log_event::write_row(const Relay_lo
     /* this is the first row to be inserted, we estimate the rows with
        the size of the first row and use that value to initialize
        storage engine for bulk insertion */
-    ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
+    DBUG_ASSERT(!(m_curr_row > m_curr_row_end));
+    ulong estimated_rows;
+    if (m_curr_row < m_curr_row_end)
+      estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
+    else if (m_curr_row = m_curr_row_end)
+      estimated_rows= 1;
+
     m_table->file->ha_start_bulk_insert(estimated_rows);
   }
   
@@ -9665,8 +9682,44 @@ int 
 Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
 {
   DBUG_ASSERT(m_table != NULL);
+  int error= 0;
+
+  /**
+     Check if update contains only values in AI for columns that do 
+     not exist on the slave. If it does, we can just unpack the rows 
+     and return (do nothing on the local table).
+
+     NOTE: We do the following optimization and check only if there 
+     are usable values on the AI and disregard the fact that there 
+     might be usable values in the BI. In practice this means that 
+     the slave will not go through find_row (since we have nothing
+     on the record to update, why go looking for it?).
+
+     If we wanted find_row to run anyway, we could move this
+     check after find_row, but then we would have to face the fact
+     that the slave might stop without finding the proper record 
+     (because it might have incomplete BI), even though there were
+     no values in AI.
+
+     On the other hand, if AI has usable values but BI has not,
+     then find_row will return an error (and the error is then
+     propagated as it was already).
+   */
+  if (!is_any_column_signaled_for_table(m_table, &m_cols_ai))
+  {
+    /* 
+      Read and discard images, because:
+      1. AI does not contain any useful values to replay;
+      2. BI is irrelevant if there is nothing useful in AI.
+    */
+    error = unpack_current_row(rli, &m_cols);
+    m_curr_row= m_curr_row_end;
+    error = error | unpack_current_row(rli, &m_cols_ai);
+
+    return error;
+  }
 
-  int error= find_row(rli); 
+  error= find_row(rli); 
   if (error)
   {
     /*

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2010-03-04 17:00:32 +0000
+++ b/sql/log_event.h	2010-04-21 00:54:25 +0000
@@ -3628,7 +3628,7 @@ protected:
     DBUG_ASSERT(m_table);
 
     bool first_row= (m_curr_row == m_rows_buf);
-    ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
+    ASSERT_OR_RETURN_ERROR(m_curr_row <= m_rows_end, HA_ERR_CORRUPT_EVENT);
     int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, cols,
                                    &m_curr_row_end, &m_master_reclength,
                                    abort_on_warning, first_row);

=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc	2010-03-04 17:00:32 +0000
+++ b/sql/rpl_record.cc	2010-04-21 00:54:25 +0000
@@ -208,6 +208,18 @@ unpack_row(Relay_log_info const *rli,
   uchar const *null_ptr= row_data;
   uchar const *pack_ptr= row_data + master_null_byte_count;
 
+  if (bitmap_is_clear_all(cols))
+  {
+    /**
+       There was no data sent from the master, so there is 
+       nothing to unpack.    
+     */
+    *row_end= pack_ptr;
+    *master_reclength= 0;
+    DBUG_RETURN(error);
+  }
+
+
   Field **const begin_ptr = table->field;
   Field **field_ptr;
   Field **const end_ptr= begin_ptr + colcnt;


Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20100421005425-jwy6406nypzewrcw.bundle
Thread
bzr commit into mysql-5.1-rpl-wl5092 branch (luis.soares:3187)Bug#49100Luis Soares21 Apr
  • Re: bzr commit into mysql-5.1-rpl-wl5092 branch (luis.soares:3187)Bug#49100Mats Kindahl10 May
    • Re: bzr commit into mysql-5.1-rpl-wl5092 branch (luis.soares:3187)Bug#49100Luís Soares11 May