Merge romeo.(none):/home/bkroot/mysql-5.1-new-rpl
into romeo.(none):/home/bk/b25688-mysql-5.1-rpl sql/item_func.cc: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/mysqld.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/rpl_mi.h: Auto merged sql/set_var.cc: Auto merged sql/slave.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_repl.cc: Auto merged
This commit is contained in:
commit
955cbc3ade
61
mysql-test/r/rpl_ndb_circular_simplex.result
Normal file
61
mysql-test/r/rpl_ndb_circular_simplex.result
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
stop slave;
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
reset master;
|
||||||
|
reset slave;
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
start slave;
|
||||||
|
CREATE TABLE t1 (a int key, b int) ENGINE=NDB;
|
||||||
|
SHOW TABLES;
|
||||||
|
Tables_in_test
|
||||||
|
t1
|
||||||
|
RESET MASTER;
|
||||||
|
INSERT INTO t1 VALUES (1,2);
|
||||||
|
INSERT INTO t1 VALUES (2,3);
|
||||||
|
STOP SLAVE;
|
||||||
|
CHANGE MASTER TO MASTER_HOST="127.0.0.1",MASTER_PORT=SLAVE_PORT,MASTER_USER="root";
|
||||||
|
RESET MASTER;
|
||||||
|
START SLAVE;
|
||||||
|
SHOW SLAVE STATUS;
|
||||||
|
Slave_IO_State #
|
||||||
|
Master_Host 127.0.0.1
|
||||||
|
Master_User root
|
||||||
|
Master_Port 9308
|
||||||
|
Connect_Retry 60
|
||||||
|
Master_Log_File slave-bin.000001
|
||||||
|
Read_Master_Log_Pos 468
|
||||||
|
Relay_Log_File #
|
||||||
|
Relay_Log_Pos #
|
||||||
|
Relay_Master_Log_File slave-bin.000001
|
||||||
|
Slave_IO_Running Yes
|
||||||
|
Slave_SQL_Running Yes
|
||||||
|
Replicate_Do_DB
|
||||||
|
Replicate_Ignore_DB
|
||||||
|
Replicate_Do_Table
|
||||||
|
Replicate_Ignore_Table
|
||||||
|
Replicate_Wild_Do_Table
|
||||||
|
Replicate_Wild_Ignore_Table
|
||||||
|
Last_Errno 0
|
||||||
|
Last_Error
|
||||||
|
Skip_Counter 0
|
||||||
|
Exec_Master_Log_Pos 468
|
||||||
|
Relay_Log_Space #
|
||||||
|
Until_Condition None
|
||||||
|
Until_Log_File
|
||||||
|
Until_Log_Pos 0
|
||||||
|
Master_SSL_Allowed No
|
||||||
|
Master_SSL_CA_File
|
||||||
|
Master_SSL_CA_Path
|
||||||
|
Master_SSL_Cert
|
||||||
|
Master_SSL_Cipher
|
||||||
|
Master_SSL_Key
|
||||||
|
Seconds_Behind_Master #
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a b
|
||||||
|
1 2
|
||||||
|
2 3
|
||||||
|
STOP SLAVE;
|
||||||
|
START SLAVE;
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
a b
|
||||||
|
1 2
|
||||||
|
2 3
|
77
mysql-test/t/rpl_ndb_circular_simplex.test
Normal file
77
mysql-test/t/rpl_ndb_circular_simplex.test
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
--source include/have_ndb.inc
|
||||||
|
--source include/have_binlog_format_row.inc
|
||||||
|
--source include/master-slave.inc
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
CREATE TABLE t1 (a int key, b int) ENGINE=NDB;
|
||||||
|
sync_slave_with_master;
|
||||||
|
SHOW TABLES;
|
||||||
|
|
||||||
|
# Lose the events from the slave binary log: there is no
|
||||||
|
# need to re-create the table on the master.
|
||||||
|
connection slave;
|
||||||
|
RESET MASTER;
|
||||||
|
|
||||||
|
# Insert some values on the slave and master
|
||||||
|
connection master;
|
||||||
|
INSERT INTO t1 VALUES (1,2);
|
||||||
|
# Switch to slave once event is applied and insert a row
|
||||||
|
sync_slave_with_master;
|
||||||
|
connection slave;
|
||||||
|
INSERT INTO t1 VALUES (2,3);
|
||||||
|
|
||||||
|
# ... it is now very probable that we have a mixed event in the binary
|
||||||
|
# log. If we don't, the test should still pass, but will not test the
|
||||||
|
# mixed event situation.
|
||||||
|
|
||||||
|
# The statement is disabled since it cannot reliably show the same
|
||||||
|
# info all the time. Use it for debug purposes.
|
||||||
|
|
||||||
|
#SHOW BINLOG EVENTS;
|
||||||
|
|
||||||
|
# Replicate back to the master to test this mixed event on the master
|
||||||
|
STOP SLAVE;
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||||
|
eval CHANGE MASTER TO MASTER_HOST="127.0.0.1",MASTER_PORT=$SLAVE_MYPORT,MASTER_USER="root";
|
||||||
|
|
||||||
|
RESET MASTER;
|
||||||
|
START SLAVE;
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
save_master_pos;
|
||||||
|
connection master;
|
||||||
|
sync_with_master;
|
||||||
|
|
||||||
|
# The statement is disabled since it cannot reliably show the same
|
||||||
|
# info all the time. Use it for debug purposes.
|
||||||
|
|
||||||
|
#SHOW BINLOG EVENTS;
|
||||||
|
|
||||||
|
# Check that there is no error in replication
|
||||||
|
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||||
|
--replace_column 1 # 8 # 9 # 23 # 33 #
|
||||||
|
query_vertical SHOW SLAVE STATUS;
|
||||||
|
|
||||||
|
# Check that we have the data on the master
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
|
||||||
|
# We should now have another mixed event, likely with "slave" server
|
||||||
|
# id last, and with the STMT_END_F flag set.
|
||||||
|
|
||||||
|
# The statement is disabled since it cannot reliably show the same
|
||||||
|
# info all the time. Use it for debug purposes.
|
||||||
|
|
||||||
|
#SHOW BINLOG EVENTS;
|
||||||
|
|
||||||
|
# now lets see that this data is applied correctly on the slave
|
||||||
|
STOP SLAVE;
|
||||||
|
save_master_pos;
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
START SLAVE;
|
||||||
|
|
||||||
|
# check that we have the data on the slave
|
||||||
|
sync_with_master;
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include "slave.h" // for wait_for_master_pos
|
#include "slave.h" // for wait_for_master_pos
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include "sql_repl.h"
|
#include "sql_repl.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
|
#include "rpl_rli.h"
|
||||||
|
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
250
sql/log_event.cc
250
sql/log_event.cc
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "rpl_rli.h"
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
#include "rpl_utility.h"
|
#include "rpl_utility.h"
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
@ -31,6 +33,8 @@
|
|||||||
|
|
||||||
#define log_cs &my_charset_latin1
|
#define log_cs &my_charset_latin1
|
||||||
|
|
||||||
|
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cache that will automatically be written to a dedicated file on
|
Cache that will automatically be written to a dedicated file on
|
||||||
destruction.
|
destruction.
|
||||||
@ -547,49 +551,7 @@ int Log_event::do_update_pos(RELAY_LOG_INFO *rli)
|
|||||||
Matz: I don't think we will need this check with this refactoring.
|
Matz: I don't think we will need this check with this refactoring.
|
||||||
*/
|
*/
|
||||||
if (rli)
|
if (rli)
|
||||||
{
|
rli->stmt_done(log_pos, when);
|
||||||
/*
|
|
||||||
If in a transaction, and if the slave supports transactions, just
|
|
||||||
inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
|
|
||||||
(not OPTION_NOT_AUTOCOMMIT) as transactions are logged with
|
|
||||||
BEGIN/COMMIT, not with SET AUTOCOMMIT= .
|
|
||||||
|
|
||||||
CAUTION: opt_using_transactions means
|
|
||||||
innodb || bdb ; suppose the master supports InnoDB and BDB,
|
|
||||||
but the slave supports only BDB, problems
|
|
||||||
will arise:
|
|
||||||
- suppose an InnoDB table is created on the master,
|
|
||||||
- then it will be MyISAM on the slave
|
|
||||||
- but as opt_using_transactions is true, the slave will believe he
|
|
||||||
is transactional with the MyISAM table. And problems will come
|
|
||||||
when one does START SLAVE; STOP SLAVE; START SLAVE; (the slave
|
|
||||||
will resume at BEGIN whereas there has not been any rollback).
|
|
||||||
This is the problem of using opt_using_transactions instead of a
|
|
||||||
finer "does the slave support
|
|
||||||
_the_transactional_handler_used_on_the_master_".
|
|
||||||
|
|
||||||
More generally, we'll have problems when a query mixes a
|
|
||||||
transactional handler and MyISAM and STOP SLAVE is issued in the
|
|
||||||
middle of the "transaction". START SLAVE will resume at BEGIN
|
|
||||||
while the MyISAM table has already been updated.
|
|
||||||
*/
|
|
||||||
if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
|
|
||||||
rli->inc_event_relay_log_pos();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rli->inc_group_relay_log_pos(log_pos);
|
|
||||||
flush_relay_log_info(rli);
|
|
||||||
/*
|
|
||||||
Note that Rotate_log_event::do_apply_event() does not call
|
|
||||||
this function, so there is no chance that a fake rotate event
|
|
||||||
resets last_master_timestamp. Note that we update without
|
|
||||||
mutex (probably ok - except in some very rare cases, only
|
|
||||||
consequence is that value may take some time to display in
|
|
||||||
Seconds_Behind_Master - not critical).
|
|
||||||
*/
|
|
||||||
rli->last_master_timestamp= when;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; // Cannot fail currently
|
return 0; // Cannot fail currently
|
||||||
}
|
}
|
||||||
@ -1039,6 +1001,10 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBUG_PRINT("read_event", ("%s(type_code: %d; event_len: %d)",
|
||||||
|
ev ? ev->get_type_str() : "<unknown>",
|
||||||
|
buf[EVENT_TYPE_OFFSET],
|
||||||
|
event_len));
|
||||||
/*
|
/*
|
||||||
is_valid() are small event-specific sanity tests which are
|
is_valid() are small event-specific sanity tests which are
|
||||||
important; for example there are some my_malloc() in constructors
|
important; for example there are some my_malloc() in constructors
|
||||||
@ -3593,17 +3559,6 @@ bool Rotate_log_event::write(IO_CACHE* file)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
Helper function to detect if the event is inside a group.
|
|
||||||
*/
|
|
||||||
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
|
||||||
static bool is_in_group(THD *const thd, RELAY_LOG_INFO *const rli)
|
|
||||||
{
|
|
||||||
return (thd->options & OPTION_BEGIN) != 0 ||
|
|
||||||
(rli->last_event_start_time > 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Rotate_log_event::do_apply_event()
|
Rotate_log_event::do_apply_event()
|
||||||
@ -3654,7 +3609,7 @@ int Rotate_log_event::do_update_pos(RELAY_LOG_INFO *rli)
|
|||||||
relay log, which shall not change the group positions.
|
relay log, which shall not change the group positions.
|
||||||
*/
|
*/
|
||||||
if ((server_id != ::server_id || rli->replicate_same_server_id) &&
|
if ((server_id != ::server_id || rli->replicate_same_server_id) &&
|
||||||
!is_in_group(thd, rli))
|
!rli->is_in_group())
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info", ("old group_master_log_name: '%s' "
|
DBUG_PRINT("info", ("old group_master_log_name: '%s' "
|
||||||
"old group_master_log_pos: %lu",
|
"old group_master_log_pos: %lu",
|
||||||
@ -3821,6 +3776,12 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
|||||||
#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
|
#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
|
||||||
int Intvar_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
int Intvar_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
We are now in a statement until the associated query log event has
|
||||||
|
been processed.
|
||||||
|
*/
|
||||||
|
const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LAST_INSERT_ID_EVENT:
|
case LAST_INSERT_ID_EVENT:
|
||||||
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
|
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
|
||||||
@ -3921,6 +3882,12 @@ void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
|||||||
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
||||||
int Rand_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
int Rand_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
We are now in a statement until the associated query log event has
|
||||||
|
been processed.
|
||||||
|
*/
|
||||||
|
const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
|
||||||
|
|
||||||
thd->rand.seed1= (ulong) seed1;
|
thd->rand.seed1= (ulong) seed1;
|
||||||
thd->rand.seed2= (ulong) seed2;
|
thd->rand.seed2= (ulong) seed2;
|
||||||
return 0;
|
return 0;
|
||||||
@ -4315,6 +4282,12 @@ int User_var_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
|||||||
double real_val;
|
double real_val;
|
||||||
longlong int_val;
|
longlong int_val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
We are now in a statement until the associated query log event has
|
||||||
|
been processed.
|
||||||
|
*/
|
||||||
|
const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
|
||||||
|
|
||||||
if (is_null)
|
if (is_null)
|
||||||
{
|
{
|
||||||
it= new Item_null();
|
it= new Item_null();
|
||||||
@ -6189,6 +6162,17 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
|||||||
/* A small test to verify that objects have consistent types */
|
/* A small test to verify that objects have consistent types */
|
||||||
DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
|
DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Now we are in a statement and will stay in a statement until we
|
||||||
|
see a STMT_END_F.
|
||||||
|
|
||||||
|
We set this flag here, before actually applying any rows, in
|
||||||
|
case the SQL thread is stopped and we need to detect that we're
|
||||||
|
inside a statement and halting abruptly might cause problems
|
||||||
|
when restarting.
|
||||||
|
*/
|
||||||
|
const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
|
||||||
|
|
||||||
error= do_before_row_operations(table);
|
error= do_before_row_operations(table);
|
||||||
while (error == 0 && row_start < (const char*) m_rows_end)
|
while (error == 0 && row_start < (const char*) m_rows_end)
|
||||||
{
|
{
|
||||||
@ -6261,69 +6245,13 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
|||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_flags(STMT_END_F))
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
This is the end of a statement or transaction, so close (and
|
This code would ideally be placed in do_update_pos() instead, but
|
||||||
unlock) the tables we opened when processing the
|
since we have no access to table there, we do the setting of
|
||||||
Table_map_log_event starting the statement.
|
last_event_start_time here instead.
|
||||||
|
|
||||||
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 (table && (table->s->primary_key == MAX_KEY) &&
|
||||||
/*
|
!cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
|
||||||
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);
|
|
||||||
|
|
||||||
if (error == 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
those errors (e.g. when executing a Delete_rows_log_event of a
|
|
||||||
non-existing row, like in rpl_row_mystery22.test,
|
|
||||||
thd->net.last_error = "Can't find record in 't1'" and last_errno=1032)
|
|
||||||
do not become visible. We still prefer to wipe them out.
|
|
||||||
*/
|
|
||||||
thd->clear_error();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
slave_print_msg(ERROR_LEVEL, rli, error,
|
|
||||||
"Error in %s event: commit of row events failed, "
|
|
||||||
"table `%s`.`%s`",
|
|
||||||
get_type_str(), table->s->db.str,
|
|
||||||
table->s->table_name.str);
|
|
||||||
DBUG_RETURN(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (table && (table->s->primary_key == MAX_KEY) && !cache_stmt)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
------------ Temporary fix until WL#2975 is implemented ---------
|
------------ Temporary fix until WL#2975 is implemented ---------
|
||||||
@ -6344,12 +6272,92 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
|||||||
const_cast<RELAY_LOG_INFO*>(rli)->last_event_start_time= time(0);
|
const_cast<RELAY_LOG_INFO*>(rli)->last_event_start_time= time(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_ASSERT(error == 0);
|
|
||||||
thd->clear_error();
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Rows_log_event::do_update_pos(RELAY_LOG_INFO *rli)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("Rows_log_event::do_update_pos");
|
||||||
|
int error= 0;
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("flags: %s",
|
||||||
|
get_flags(STMT_END_F) ? "STMT_END_F " : ""));
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
those errors (e.g. when executing a Delete_rows_log_event of a
|
||||||
|
non-existing row, like in rpl_row_mystery22.test,
|
||||||
|
thd->net.last_error = "Can't find record in 't1'" and last_errno=1032)
|
||||||
|
do not become visible. We still prefer to wipe them out.
|
||||||
|
*/
|
||||||
|
thd->clear_error();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
slave_print_msg(ERROR_LEVEL, rli, error,
|
||||||
|
"Error in %s event: commit of row events failed",
|
||||||
|
get_type_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rli->inc_event_relay_log_pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
||||||
|
|
||||||
#ifndef MYSQL_CLIENT
|
#ifndef MYSQL_CLIENT
|
||||||
@ -6431,7 +6439,9 @@ void Rows_log_event::print_helper(FILE *file,
|
|||||||
{
|
{
|
||||||
bool const last_stmt_event= get_flags(STMT_END_F);
|
bool const last_stmt_event= get_flags(STMT_END_F);
|
||||||
print_header(head, print_event_info, !last_stmt_event);
|
print_header(head, print_event_info, !last_stmt_event);
|
||||||
my_b_printf(head, "\t%s: table id %lu\n", name, m_table_id);
|
my_b_printf(head, "\t%s: table id %lu%s\n",
|
||||||
|
name, m_table_id,
|
||||||
|
last_stmt_event ? " flags: STMT_END_F" : "");
|
||||||
print_base64(body, print_event_info, !last_stmt_event);
|
print_base64(body, print_event_info, !last_stmt_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,6 +841,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Primitive to apply an event to the database.
|
Primitive to apply an event to the database.
|
||||||
|
|
||||||
@ -2242,6 +2243,7 @@ private:
|
|||||||
|
|
||||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||||
virtual int do_apply_event(RELAY_LOG_INFO const *rli);
|
virtual int do_apply_event(RELAY_LOG_INFO const *rli);
|
||||||
|
virtual int do_update_pos(RELAY_LOG_INFO *rli);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Primitive to prepare for a sequence of row executions.
|
Primitive to prepare for a sequence of row executions.
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include "sql_repl.h"
|
#include "sql_repl.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
#include "repl_failsafe.h"
|
#include "repl_failsafe.h"
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "repl_failsafe.h"
|
#include "repl_failsafe.h"
|
||||||
#include "sql_repl.h"
|
#include "sql_repl.h"
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
#include "log_event.h"
|
#include "log_event.h"
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
#ifdef HAVE_REPLICATION
|
#ifdef HAVE_REPLICATION
|
||||||
|
|
||||||
|
#include "rpl_rli.h"
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Replication IO Thread
|
Replication IO Thread
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include "rpl_rli.h"
|
#include "rpl_rli.h"
|
||||||
#include <my_dir.h> // For MY_STAT
|
#include <my_dir.h> // For MY_STAT
|
||||||
#include "sql_repl.h" // For check_binlog_magic
|
#include "sql_repl.h" // For check_binlog_magic
|
||||||
@ -37,7 +38,7 @@ st_relay_log_info::st_relay_log_info()
|
|||||||
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
|
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
|
||||||
until_log_pos(0), retried_trans(0),
|
until_log_pos(0), retried_trans(0),
|
||||||
tables_to_lock(0), tables_to_lock_count(0),
|
tables_to_lock(0), tables_to_lock_count(0),
|
||||||
last_event_start_time(0)
|
last_event_start_time(0), m_flags(0)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("st_relay_log_info::st_relay_log_info");
|
DBUG_ENTER("st_relay_log_info::st_relay_log_info");
|
||||||
|
|
||||||
@ -1086,6 +1087,52 @@ bool st_relay_log_info::cached_charset_compare(char *charset) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void st_relay_log_info::stmt_done(my_off_t const event_master_log_pos,
|
||||||
|
time_t event_creation_time)
|
||||||
|
{
|
||||||
|
clear_flag(IN_STMT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
If in a transaction, and if the slave supports transactions, just
|
||||||
|
inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
|
||||||
|
(not OPTION_NOT_AUTOCOMMIT) as transactions are logged with
|
||||||
|
BEGIN/COMMIT, not with SET AUTOCOMMIT= .
|
||||||
|
|
||||||
|
CAUTION: opt_using_transactions means innodb || bdb ; suppose the
|
||||||
|
master supports InnoDB and BDB, but the slave supports only BDB,
|
||||||
|
problems will arise: - suppose an InnoDB table is created on the
|
||||||
|
master, - then it will be MyISAM on the slave - but as
|
||||||
|
opt_using_transactions is true, the slave will believe he is
|
||||||
|
transactional with the MyISAM table. And problems will come when
|
||||||
|
one does START SLAVE; STOP SLAVE; START SLAVE; (the slave will
|
||||||
|
resume at BEGIN whereas there has not been any rollback). This is
|
||||||
|
the problem of using opt_using_transactions instead of a finer
|
||||||
|
"does the slave support _transactional handler used on the
|
||||||
|
master_".
|
||||||
|
|
||||||
|
More generally, we'll have problems when a query mixes a
|
||||||
|
transactional handler and MyISAM and STOP SLAVE is issued in the
|
||||||
|
middle of the "transaction". START SLAVE will resume at BEGIN
|
||||||
|
while the MyISAM table has already been updated.
|
||||||
|
*/
|
||||||
|
if ((sql_thd->options & OPTION_BEGIN) && opt_using_transactions)
|
||||||
|
inc_event_relay_log_pos();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inc_group_relay_log_pos(event_master_log_pos);
|
||||||
|
flush_relay_log_info(this);
|
||||||
|
/*
|
||||||
|
Note that Rotate_log_event::do_apply_event() does not call this
|
||||||
|
function, so there is no chance that a fake rotate event resets
|
||||||
|
last_master_timestamp. Note that we update without mutex
|
||||||
|
(probably ok - except in some very rare cases, only consequence
|
||||||
|
is that value may take some time to display in
|
||||||
|
Seconds_Behind_Master - not critical).
|
||||||
|
*/
|
||||||
|
last_master_timestamp= event_creation_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||||
void st_relay_log_info::cleanup_context(THD *thd, bool error)
|
void st_relay_log_info::cleanup_context(THD *thd, bool error)
|
||||||
{
|
{
|
||||||
@ -1112,6 +1159,7 @@ void st_relay_log_info::cleanup_context(THD *thd, bool error)
|
|||||||
m_table_map.clear_tables();
|
m_table_map.clear_tables();
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
clear_tables_to_lock();
|
clear_tables_to_lock();
|
||||||
|
clear_flag(IN_STMT);
|
||||||
last_event_start_time= 0;
|
last_event_start_time= 0;
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,17 @@ struct RPL_TABLE_LIST;
|
|||||||
|
|
||||||
typedef struct st_relay_log_info
|
typedef struct st_relay_log_info
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
Flags for the state of the replication.
|
||||||
|
*/
|
||||||
|
enum enum_state_flag {
|
||||||
|
/** The replication thread is inside a statement */
|
||||||
|
IN_STMT,
|
||||||
|
|
||||||
|
/** Flag counter. Should always be last */
|
||||||
|
STATE_FLAGS_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If flag set, then rli does not store its state in any info file.
|
If flag set, then rli does not store its state in any info file.
|
||||||
This is the case only when we execute BINLOG SQL commands inside
|
This is the case only when we execute BINLOG SQL commands inside
|
||||||
@ -314,6 +325,66 @@ typedef struct st_relay_log_info
|
|||||||
transaction).
|
transaction).
|
||||||
*/
|
*/
|
||||||
time_t last_event_start_time;
|
time_t last_event_start_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper function to do after statement completion.
|
||||||
|
|
||||||
|
This function is called from an event to complete the group by
|
||||||
|
either stepping the group position, if the "statement" is not
|
||||||
|
inside a transaction; or increase the event position, if the
|
||||||
|
"statement" is inside a transaction.
|
||||||
|
|
||||||
|
@param event_log_pos
|
||||||
|
Master log position of the event. The position is recorded in the
|
||||||
|
relay log info and used to produce information for <code>SHOW
|
||||||
|
SLAVE STATUS</code>.
|
||||||
|
|
||||||
|
@param event_creation_time
|
||||||
|
Timestamp for the creation of the event on the master side. The
|
||||||
|
time stamp is recorded in the relay log info and used to compute
|
||||||
|
the <code>Seconds_behind_master</code> field.
|
||||||
|
*/
|
||||||
|
void stmt_done(my_off_t event_log_pos,
|
||||||
|
time_t event_creation_time);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the value of a replication state flag.
|
||||||
|
|
||||||
|
@param flag Flag to set
|
||||||
|
*/
|
||||||
|
void set_flag(enum_state_flag flag)
|
||||||
|
{
|
||||||
|
m_flags |= (1UL << flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clear the value of a replication state flag.
|
||||||
|
|
||||||
|
@param flag Flag to clear
|
||||||
|
*/
|
||||||
|
void clear_flag(enum_state_flag flag)
|
||||||
|
{
|
||||||
|
m_flags &= ~(1UL << flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Is the replication inside a group?
|
||||||
|
|
||||||
|
Replication is inside a group if either:
|
||||||
|
- The OPTION_BEGIN flag is set, meaning we're inside a transaction
|
||||||
|
- The RLI_IN_STMT flag is set, meaning we're inside a statement
|
||||||
|
|
||||||
|
@retval true Replication thread is currently inside a group
|
||||||
|
@retval false Replication thread is currently not inside a group
|
||||||
|
*/
|
||||||
|
bool is_in_group() const {
|
||||||
|
return (sql_thd->options & OPTION_BEGIN) ||
|
||||||
|
(m_flags & (1UL << IN_STMT));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 m_flags;
|
||||||
} RELAY_LOG_INFO;
|
} RELAY_LOG_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include <my_getopt.h>
|
#include <my_getopt.h>
|
||||||
#include <thr_alarm.h>
|
#include <thr_alarm.h>
|
||||||
#include <myisam.h>
|
#include <myisam.h>
|
||||||
|
26
sql/slave.cc
26
sql/slave.cc
@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#include <myisam.h>
|
#include <myisam.h>
|
||||||
#include "rpl_rli.h"
|
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "rpl_mi.h"
|
||||||
|
#include "rpl_rli.h"
|
||||||
#include "sql_repl.h"
|
#include "sql_repl.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
#include "repl_failsafe.h"
|
#include "repl_failsafe.h"
|
||||||
@ -1736,11 +1737,12 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
|
|||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DBUG_PRINT("info",("type_code=%d (%s), server_id=%d",
|
DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
|
||||||
type_code, ev->get_type_str(), ev->server_id));
|
ev->get_type_str(), type_code, ev->server_id));
|
||||||
DBUG_PRINT("info", ("thd->options={ %s%s}",
|
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
|
||||||
FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
|
FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
|
||||||
FLAGSTR(thd->options, OPTION_BEGIN)));
|
FLAGSTR(thd->options, OPTION_BEGIN),
|
||||||
|
rli->last_event_start_time));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1782,21 +1784,21 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
|
|||||||
if (reason == Log_event::EVENT_SKIP_NOT)
|
if (reason == Log_event::EVENT_SKIP_NOT)
|
||||||
exec_res= ev->apply_event(rli);
|
exec_res= ev->apply_event(rli);
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
This only prints information to the debug trace.
|
This only prints information to the debug trace.
|
||||||
|
|
||||||
TODO: Print an informational message to the error log?
|
TODO: Print an informational message to the error log?
|
||||||
*/
|
*/
|
||||||
static const char *const explain[] = {
|
static const char *const explain[] = {
|
||||||
"event was not skipped", // EVENT_SKIP_NOT,
|
// EVENT_SKIP_NOT,
|
||||||
"event originated from this server", // EVENT_SKIP_IGNORE,
|
"not skipped",
|
||||||
"event skip counter was non-zero" // EVENT_SKIP_COUNT
|
// EVENT_SKIP_IGNORE,
|
||||||
|
"skipped because event originated from this server",
|
||||||
|
// EVENT_SKIP_COUNT
|
||||||
|
"skipped because event skip counter was non-zero"
|
||||||
};
|
};
|
||||||
DBUG_PRINT("info", ("%s was skipped because %s",
|
DBUG_PRINT("skip_event", ("%s event was %s",
|
||||||
ev->get_type_str(), explain[reason]));
|
ev->get_type_str(), explain[reason]));
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DBUG_PRINT("info", ("apply_event error = %d", exec_res));
|
DBUG_PRINT("info", ("apply_event error = %d", exec_res));
|
||||||
|
@ -22,13 +22,18 @@
|
|||||||
#include "my_list.h"
|
#include "my_list.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
#include "rpl_tblmap.h"
|
#include "rpl_tblmap.h"
|
||||||
#include "rpl_rli.h"
|
|
||||||
#include "rpl_mi.h"
|
|
||||||
|
|
||||||
#define SLAVE_NET_TIMEOUT 3600
|
#define SLAVE_NET_TIMEOUT 3600
|
||||||
|
|
||||||
#define MAX_SLAVE_ERROR 2000
|
#define MAX_SLAVE_ERROR 2000
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
struct st_relay_log_info;
|
||||||
|
typedef st_relay_log_info RELAY_LOG_INFO;
|
||||||
|
|
||||||
|
class MASTER_INFO;
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
MySQL Replication
|
MySQL Replication
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
#include "rpl_rli.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
#include "rpl_rli.h"
|
||||||
#include <my_bitmap.h>
|
#include <my_bitmap.h>
|
||||||
#include "log_event.h"
|
#include "log_event.h"
|
||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "rpl_rli.h"
|
|
||||||
#include "rpl_tblmap.h"
|
#include "rpl_tblmap.h"
|
||||||
|
|
||||||
|
struct st_relay_log_info;
|
||||||
|
typedef st_relay_log_info RELAY_LOG_INFO;
|
||||||
|
|
||||||
class Query_log_event;
|
class Query_log_event;
|
||||||
class Load_log_event;
|
class Load_log_event;
|
||||||
class Slave_log_event;
|
class Slave_log_event;
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#include "sql_select.h"
|
#include "sql_select.h"
|
||||||
#include "sql_show.h"
|
#include "sql_show.h"
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "rpl_mi.h"
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
|
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#ifdef HAVE_REPLICATION
|
#ifdef HAVE_REPLICATION
|
||||||
|
|
||||||
|
#include "rpl_mi.h"
|
||||||
#include "sql_repl.h"
|
#include "sql_repl.h"
|
||||||
#include "log_event.h"
|
#include "log_event.h"
|
||||||
#include "rpl_filter.h"
|
#include "rpl_filter.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user