#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#41183 | Andrei Elkin | 18 Dec |