List:Commits« Previous MessageNext Message »
From:Mats Kindahl Date:August 20 2008 8:52pm
Subject:bzr commit into mysql-5.1 branch (mats:2658) Bug#32709
View as plain text  
#At file:///home/bzr/bugs/b32709-5.1-rpl/

 2658 Mats Kindahl	2008-08-20
      Bug #32709: Assertion failed: trx_data->empty(), file log.cc
      
      The assertion indicates that some data was left in the transaction
      cache when the server was shut down, which means that a previous
      statement did not commit or rollback correctly.
      
      What happened was that a bug in the rollback of a transactional
      table caused the transaction cache to be emptied, but not reset.
      The error can be triggered by having a failing UPDATE or INSERT,
      on a transactional table, causing an implicit rollback.
      
      Fixed by always flushing the pending event to reset the state
      properly.
modified:
  mysql-test/extra/rpl_tests/rpl_row_basic.test
  mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
  mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
  sql/log.cc
  sql/log.h
  sql/sql_class.cc
  sql/sql_class.h

per-file messages:
  mysql-test/extra/rpl_tests/rpl_row_basic.test
    Testing that a failed update (that writes some rows to the
    transaction cache) does not cause the transaction cache to
    hold on to the data or forget to reset the transaction cache.
  mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
    Result file change.
  mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
    Result file change.
  sql/log.cc
    Added call to remove pending event when the transaction cache
    is emptied instead of written to binary log. The call will also
    clear the outstanding table map count so that the cache is not
    left it in a state of "empty but not reset".
    
    Added function MYSQL_BIN_LOG::remove_pending_rows_event().
  sql/log.h
    Added function MYSQL_BIN_LOG::remove_pending_rows_event().
  sql/sql_class.cc
    Adding function THD::binlog_remove_pending_rows_event().
  sql/sql_class.h
    Adding function THD::binlog_remove_pending_rows_event().
=== modified file 'mysql-test/extra/rpl_tests/rpl_row_basic.test'
--- a/mysql-test/extra/rpl_tests/rpl_row_basic.test	2008-07-11 18:51:10 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test	2008-08-20 20:52:18 +0000
@@ -435,3 +435,23 @@ connection master;
 drop table t1, t2, t3, t4, t5, t6, t7;
 sync_slave_with_master;
 
+#
+# BUG#32709: Assertion failed: trx_data->empty(), file .\log.cc, line 1293
+#
+
+connection master;
+eval CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=$type;
+
+INSERT INTO t1 VALUES (1), (2), (3);
+--error ER_DUP_ENTRY
+UPDATE t1 SET a = 10;
+INSERT INTO t1 VALUES (4);
+sync_slave_with_master;
+
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+connection master;
+drop table t1;
+sync_slave_with_master;

=== modified file 'mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result'
--- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result	2008-08-04 05:04:47 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result	2008-08-20 20:52:18 +0000
@@ -514,3 +514,10 @@ INSERT INTO t7 VALUES (1, "", 1);
 INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
 Comparing tables master:test.t7 and slave:test.t7
 drop table t1, t2, t3, t4, t5, t6, t7;
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE='MYISAM' ;
+INSERT INTO t1 VALUES (1), (2), (3);
+UPDATE t1 SET a = 10;
+ERROR 23000: Duplicate entry '10' for key 'PRIMARY'
+INSERT INTO t1 VALUES (4);
+Comparing tables master:test.t1 and slave:test.t1
+drop table t1;

=== modified file 'mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result	2008-08-04 05:04:47 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result	2008-08-20 20:52:18 +0000
@@ -514,3 +514,10 @@ INSERT INTO t7 VALUES (1, "", 1);
 INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
 Comparing tables master:test.t7 and slave:test.t7
 drop table t1, t2, t3, t4, t5, t6, t7;
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE='INNODB' ;
+INSERT INTO t1 VALUES (1), (2), (3);
+UPDATE t1 SET a = 10;
+ERROR 23000: Duplicate entry '10' for key 'PRIMARY'
+INSERT INTO t1 VALUES (4);
+Comparing tables master:test.t1 and slave:test.t1
+drop table t1;

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2008-07-22 10:41:55 +0000
+++ b/sql/log.cc	2008-08-20 20:52:18 +0000
@@ -1421,6 +1421,7 @@ binlog_end_trans(THD *thd, binlog_trx_da
       If rolling back a statement in a transaction, we truncate the
       transaction cache to remove the statement.
      */
+    thd->binlog_remove_pending_rows_event(TRUE);
     if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
       trx_data->reset();
     else                                        // ...statement
@@ -3769,6 +3770,31 @@ THD::binlog_set_pending_rows_event(Rows_
 }
 
 
+/**
+  Remove the pending rows event, discarding any outstanding rows.
+
+  If there is no pending rows event available, this is effectively a
+  no-op.
+ */
+int
+MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd)
+{
+  DBUG_ENTER(__FUNCTION__);
+
+  binlog_trx_data *const trx_data=
+    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+
+  DBUG_ASSERT(trx_data);
+
+  if (Rows_log_event* pending= trx_data->pending())
+  {
+    delete pending;
+    trx_data->set_pending(NULL);
+  }
+
+  DBUG_RETURN(0);
+}
+
 /*
   Moves the last bunch of rows from the pending Rows event to the binlog
   (either cached binlog if transaction, or disk binlog). Sets a new pending

=== modified file 'sql/log.h'
--- a/sql/log.h	2007-10-30 08:03:34 +0000
+++ b/sql/log.h	2008-08-20 20:52:18 +0000
@@ -307,6 +307,7 @@ public:
   void update_table_map_version() { ++m_table_map_version; }
 
   int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event);
+  int remove_pending_rows_event(THD *thd);
 
 #endif /* !defined(MYSQL_CLIENT) */
   void reset_bytes_written()

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2008-08-07 01:33:01 +0000
+++ b/sql/sql_class.cc	2008-08-20 20:52:18 +0000
@@ -3496,6 +3496,21 @@ int THD::binlog_delete_row(TABLE* table,
 }
 
 
+int THD::binlog_remove_pending_rows_event(bool clear_maps)
+{
+  DBUG_ENTER(__FUNCTION__);
+
+  if (!mysql_bin_log.is_open())
+    DBUG_RETURN(0);
+
+  mysql_bin_log.remove_pending_rows_event(this);
+
+  if (clear_maps)
+    binlog_table_maps= 0;
+
+  DBUG_RETURN(0);
+}
+
 int THD::binlog_flush_pending_rows_event(bool stmt_end)
 {
   DBUG_ENTER("THD::binlog_flush_pending_rows_event");

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-08-06 10:41:27 +0000
+++ b/sql/sql_class.h	2008-08-20 20:52:18 +0000
@@ -1360,6 +1360,7 @@ public:
   Rows_log_event* binlog_get_pending_rows_event() const;
   void            binlog_set_pending_rows_event(Rows_log_event* ev);
   int binlog_flush_pending_rows_event(bool stmt_end);
+  int binlog_remove_pending_rows_event(bool clear_maps);
 
 private:
   uint binlog_table_maps; // Number of table maps currently in the binlog

Thread
bzr commit into mysql-5.1 branch (mats:2658) Bug#32709Mats Kindahl20 Aug