MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:December 18 2008 12:18pm
Subject:bzr commit into mysql-5.1-bugteam branch (aelkin:2737) Bug#41183
View as plain text  
#At file:///home/andrei/MySQL/BZR/FIXES/5.1-bt-bug41183-circular_rpl_cluster/ based on revid:zhou.li@stripped

 2737 Andrei Elkin	2008-12-18
      Bug #41183  rpl_ndb_circular, rpl_ndb_circular_simplex need maintenance, crash
            
      The bug happened because filtering-out a STMT_END_F-flagged event so that
      the transaction COMMIT finds traces of incomplete statement commit.
      Such situation is only possible with ndb circular replication. The filtered-out
      rows event is one that immediately preceeds the COMMIT query event.
      
      Fixed with deploying an the rows-log-event statement commit at executing
      of the transaction COMMIT event. 
      Resources that were allocated by other than STMT_END_F-flagged event of the last statement are clean up prior execution of the commit logics.
modified:
  mysql-test/suite/rpl_ndb/t/disabled.def
  sql/log_event.cc

per-file messages:
  mysql-test/suite/rpl_ndb/t/disabled.def
    re-enabling two tests.
  sql/log_event.cc
    Adding the statement cleanup to execute at the transaction commit time.
    The statement might not be ended with execution of STMT_END_F-flagged event because of
    the event was filtered out by SERVER_ID rules.
    Small refactoring for Rows_log_event::do_update_pos() to be split on two parts:
    the statement commit that releases its execution time allocated resources, and
    the relay log update.
=== modified file 'mysql-test/suite/rpl_ndb/t/disabled.def'
--- a/mysql-test/suite/rpl_ndb/t/disabled.def	2008-12-08 14:36:42 +0000
+++ b/mysql-test/suite/rpl_ndb/t/disabled.def	2008-12-18 12:18:22 +0000
@@ -10,7 +10,4 @@
 #
 ##############################################################################
 
-rpl_ndb_circular         : Bug#41183 rpl_ndb_circular, rpl_ndb_circular_simplex need maintenance, crash
-rpl_ndb_circular_simplex : Bug#41183 rpl_ndb_circular, rpl_ndb_circular_simplex need maintenance, crash
-
 # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2008-10-20 18:50:08 +0000
+++ b/sql/log_event.cc	2008-12-18 12:18:22 +0000
@@ -51,6 +51,7 @@
 */
 #define FMT_G_BUFSIZE(PREC) (3 + (PREC) + 5 + 1)
 
+static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD* thd);
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 static const char *HA_ERR(int i)
@@ -2893,7 +2894,29 @@ int Query_log_event::do_apply_event(Rela
   DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
 
   clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
-  const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+  if (strcmp("COMMIT", query) == 0 && rli->tables_to_lock)
+  {
+    /*
+      Cleaning-up the last statement context:
+      the terminal event of the current statement flagged with
+      STMT_END_F got filtered out in ndb circular replication.
+    */
+    int error;
+    char llbuff[22];
+    if ((error= rows_event_stmt_cleanup(const_cast<Relay_log_info*>(rli), thd)))
+    {
+      const_cast<Relay_log_info*>(rli)->report(ERROR_LEVEL, error,
+                  "Error in cleaning up after an event preceeding the commit; "
+                  "the group log file/position: %s %s",
+                  const_cast<Relay_log_info*>(rli)->group_master_log_name,
+                  llstr(const_cast<Relay_log_info*>(rli)->group_master_log_pos,
+                        llbuff));
+    }
+  }
+  else
+  {
+    const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
+  }
 
   /*
     Note:   We do not need to execute reset_one_shot_variables() if this
@@ -2905,6 +2928,7 @@ int Query_log_event::do_apply_event(Rela
             ::do_apply_event(), then the companion SET also have so
             we don't need to reset_one_shot_variables().
   */
+
   if (rpl_filter->db_ok(thd->db))
   {
     thd->set_time((time_t)when);
@@ -7358,6 +7382,74 @@ Rows_log_event::do_shall_skip(Relay_log_
     return Log_event::do_shall_skip(rli);
 }
 
+/**
+   The function is called at Rows_log_event statement commit time,
+   normally from Rows_log_event::do_update_pos() and possibly from
+   Query_log_event::do_apply_event() of the COMMIT.
+   The function commits the last statement for engines, binlog and
+   releases resources have been allocated for the statement.
+  
+   @retval  0         Ok.
+   @retval  non-zero  Error at the commit.
+ */
+
+static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
+{
+  int error;
+  /*
+    This is the end of a statement or transaction, so close (and
+    unlock) the tables we opened when processing the
+    Table_map_log_event starting the statement.
+    
+    OBSERVER.  This will clear *all* mappings, not only those that
+    are open for the table. There is not good handle for on-close
+    actions for tables.
+    
+    NOTE. Even if we have no table ('table' == 0) we still need to be
+    here, so that we increase the group relay log position. If we didn't, we
+    could have a group relay log position which lags behind "forever"
+    (assume the last master's transaction is ignored by the slave because of
+    replicate-ignore rules).
+  */
+  thd->binlog_flush_pending_rows_event(true);
+  
+  /*
+    If this event is not in a transaction, the call below will, if some
+    transactional storage engines are involved, commit the statement into
+    them and flush the pending event to binlog.
+    If this event is in a transaction, the call will do nothing, but a
+    Xid_log_event will come next which will, if some transactional engines
+    are involved, commit the transaction and flush the pending event to the
+    binlog.
+  */
+  error= ha_autocommit_or_rollback(thd, 0);
+  
+  /*
+    Now what if this is not a transactional engine? we still need to
+    flush the pending event to the binlog; we did it with
+    thd->binlog_flush_pending_rows_event(). Note that we imitate
+    what is done for real queries: a call to
+    ha_autocommit_or_rollback() (sometimes only if involves a
+    transactional engine), and a call to be sure to have the pending
+    event flushed.
+  */
+  
+  thd->reset_current_stmt_binlog_row_based();
+  
+  const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0);
+  return error;
+}
+
+/**
+   The method either increments the relay log position or
+   commits the current statement and increments the master group 
+   possition if the event is STMT_END_F flagged and
+   the statement corresponds to the autocommit query (i.e replicated
+   without wrapping in BEGIN/COMMIT)
+
+   @retval 0         Success
+   @retval non-zero  Error in the statement commit
+ */
 int
 Rows_log_event::do_update_pos(Relay_log_info *rli)
 {
@@ -7369,56 +7461,23 @@ Rows_log_event::do_update_pos(Relay_log_
 
   if (get_flags(STMT_END_F))
   {
-    /*
-      This is the end of a statement or transaction, so close (and
-      unlock) the tables we opened when processing the
-      Table_map_log_event starting the statement.
-
-      OBSERVER.  This will clear *all* mappings, not only those that
-      are open for the table. There is not good handle for on-close
-      actions for tables.
-
-      NOTE. Even if we have no table ('table' == 0) we still need to be
-      here, so that we increase the group relay log position. If we didn't, we
-      could have a group relay log position which lags behind "forever"
-      (assume the last master's transaction is ignored by the slave because of
-      replicate-ignore rules).
-    */
-    thd->binlog_flush_pending_rows_event(true);
-
-    /*
-      If this event is not in a transaction, the call below will, if some
-      transactional storage engines are involved, commit the statement into
-      them and flush the pending event to binlog.
-      If this event is in a transaction, the call will do nothing, but a
-      Xid_log_event will come next which will, if some transactional engines
-      are involved, commit the transaction and flush the pending event to the
-      binlog.
-    */
-    error= ha_autocommit_or_rollback(thd, 0);
-
-    /*
-      Now what if this is not a transactional engine? we still need to
-      flush the pending event to the binlog; we did it with
-      thd->binlog_flush_pending_rows_event(). Note that we imitate
-      what is done for real queries: a call to
-      ha_autocommit_or_rollback() (sometimes only if involves a
-      transactional engine), and a call to be sure to have the pending
-      event flushed.
-    */
-
-    thd->reset_current_stmt_binlog_row_based();
-
-    rli->cleanup_context(thd, 0);
-    if (error == 0)
+    if ((error= rows_event_stmt_cleanup(rli, thd)))
+    {
+      rli->report(ERROR_LEVEL, error,
+                  "Error in %s event: commit of row events failed, "
+                  "table `%s`.`%s`",
+                  get_type_str(), m_table->s->db.str,
+                  m_table->s->table_name.str);
+    }
+    else
     {
       /*
         Indicate that a statement is finished.
         Step the group log position if we are not in a transaction,
         otherwise increase the event log position.
-       */
+      */
       rli->stmt_done(log_pos, when);
-
+      
       /*
         Clear any errors pushed in thd->net.last_err* if for example "no key
         found" (as this is allowed). This is a safety measure; apparently
@@ -7429,12 +7488,6 @@ Rows_log_event::do_update_pos(Relay_log_
       */
       thd->clear_error();
     }
-    else
-      rli->report(ERROR_LEVEL, error,
-                  "Error in %s event: commit of row events failed, "
-                  "table `%s`.`%s`",
-                  get_type_str(), m_table->s->db.str,
-                  m_table->s->table_name.str);
   }
   else
   {

Thread
bzr commit into mysql-5.1-bugteam branch (aelkin:2737) Bug#41183Andrei Elkin18 Dec