#At file:///home/frazer/bzr/mysql-5.1-telco-7.0-reflect/ based on revid:msabaratnam@stripped
3953 Frazer Clement 2010-11-08
WL5353 Reflecting Gci
Implement propagation of applied epochs via ndb_apply_status table.
A new MySQLD option --ndb-log-apply-status is added which causes a
MySQLD acting as a Slave to log mysql.ndb_apply_status updates
received from its immediate Master in its Binlog with its own Server Id.
This allows them to propagate into the mysql.ndb_apply_status table(s) of
downstream slaves. In a circular configuration they propagate back to the
originating Cluster.
In chained-slave replication scenarios, this gives downstream slaves
visibility of their position relative to all their upstream contributors.
In circular replication scenarios, this gives a Master visibility of when
its changes (epochs) have been applied to other Clusters in a replication
circle.
New testcase rpl_ndb_break_3_chain added.
New testcase ndb_binlog_log_apply_status added.
Testcase rpl_ndb_circular extended.
This functionality is a basis for WL5353.
added:
mysql-test/suite/ndb_binlog/r/ndb_binlog_log_apply_status.result
mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc
mysql-test/suite/ndb_binlog/t/ndb_binlog_log_apply_status.test
mysql-test/suite/rpl_ndb/r/rpl_ndb_break_3_chain.result
mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.cnf
mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.test
modified:
mysql-test/suite/ndb/r/ndb_basic.result
mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc
mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result
mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test
sql/ha_ndbcluster.cc
sql/ha_ndbcluster_binlog.cc
=== modified file 'mysql-test/suite/ndb/r/ndb_basic.result'
--- a/mysql-test/suite/ndb/r/ndb_basic.result 2010-11-01 09:13:06 +0000
+++ b/mysql-test/suite/ndb/r/ndb_basic.result 2010-11-08 12:19:51 +0000
@@ -34,6 +34,7 @@ ndb_force_send #
ndb_index_stat_cache_entries #
ndb_index_stat_enable #
ndb_index_stat_update_freq #
+ndb_log_apply_status #
ndb_log_bin #
ndb_log_binlog_index #
ndb_log_empty_epochs #
=== added file 'mysql-test/suite/ndb_binlog/r/ndb_binlog_log_apply_status.result'
--- a/mysql-test/suite/ndb_binlog/r/ndb_binlog_log_apply_status.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb_binlog/r/ndb_binlog_log_apply_status.result 2010-11-08 12:19:51 +0000
@@ -0,0 +1,41 @@
+create table test.t1(a int primary key) engine=ndb;
+set global ndb_log_apply_status=Off;
+show variables like '%ndb_log_apply_status%';
+Variable_name Value
+ndb_log_apply_status OFF
+reset slave;
+reset master;
+Should have empty apply status table
+select * from mysql.ndb_apply_status;
+server_id epoch log_name start_pos end_pos
+Dummy incoming ndb_apply_status updates, should not be logged
+begin;
+insert into mysql.ndb_apply_status values (555, 12345, 'binlog.000001', 20, 30);
+insert into mysql.ndb_apply_status values (666, 67890, 'binlog.000001', 50, 60);
+replace into test.t1 values (1);
+commit;
+Should not see ndb_apply_status updates in the Binlog
+show binlog events;
+select txt from binlog_stmts where txt like '%binlog.000001%' order by txt;
+txt
+set global ndb_log_apply_status=On;
+show variables like '%ndb_log_apply_status%';
+Variable_name Value
+ndb_log_apply_status ON
+reset slave;
+reset master;
+Should have empty apply status table
+select * from mysql.ndb_apply_status;
+server_id epoch log_name start_pos end_pos
+Dummy incoming ndb_apply_status updates, should be logged
+begin;
+insert into mysql.ndb_apply_status values (555, 12345, 'binlog.000001', 20, 30);
+insert into mysql.ndb_apply_status values (666, 67890, 'binlog.000001', 50, 60);
+replace into test.t1 values (1);
+commit;
+Should see ndb_apply_status updates in the Binlog
+show binlog events;
+select txt from binlog_stmts where txt like '%binlog.000001%' order by txt;
+txt
+set global ndb_log_apply_status=Off;
+drop table test.t1;
=== modified file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc'
--- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc 2009-09-30 10:17:20 +0000
+++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc 2010-11-08 12:19:51 +0000
@@ -1,91 +1,3 @@
-#
-# Get the mysqlbinlog tool --verbose mode to dump the Binlog contents with
-# 'SQL' statements in triple-comments over multiple lines, e.g. :
-#
-### INSERT
-### SET
-### @1=1
-### @2=2
-#
-# Then munch this output into single-line statements
-# e.g. :
-# INSERT SET @1=1 @2=2
-#
-# Then filter + sort to get deterministic order independent of Ndb table
-# fragmentation, epoch in ndb_apply_status etc.
-#
+let $Binlog_condition = not like '%ndb_apply_status%';
---disable_query_log
-let $MYSQLD_DATADIR= `select @@datadir;`;
---exec $MYSQL_BINLOG --verbose $MYSQLD_DATADIR/mysqld-bin.000001 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql
-
-create table raw_binlog_rows (txt varchar(1000));
-
---eval load data local infile '$MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql' into table raw_binlog_rows columns terminated by '\n';
-
-create table binlog_stmt_parts_unassoc (txt varchar(1000), line_count int, stmt_boundary int);
-
-set @line_count=0;
-set @stmt_boundary=0;
-
-# Use replace() here to get rid of any unwanted Windows
-# CRs
-insert into binlog_stmt_parts_unassoc
- select replace(txt, '\r', ''),
- @line_count:= @line_count + 1, # So we can preserve order later
- (txt like '%INSERT%' or # Identify statement boundaries
- txt like '%UPDATE%' or
- txt like '%DELETE%')
- from raw_binlog_rows
- where
- txt like '###%'; # Discard non verbose output
-
-#select * from binlog_stmt_parts_unassoc;
-
-create table binlog_stmt_parts_assoc (txt varchar(1000), line_count int, stmt_num int);
-
-set @stmt_count = 0;
-
-insert into binlog_stmt_parts_assoc
- select txt,
- line_count,
- @stmt_count:= @stmt_count + stmt_boundary # All rows from same stmt will
- # have same stmt_num
- from binlog_stmt_parts_unassoc order by line_count;
-
-
-#select * from binlog_stmt_parts_assoc;
-
-create table binlog_stmts (txt varchar(1000), stmt_num int);
-
-insert into binlog_stmts
- select group_concat(right(txt, # Combine rows in statment into 1
- length(txt) - 4) # Trim ### from line start
- order by line_count
- separator ' '), stmt_num
- from binlog_stmt_parts_assoc
- group by stmt_num;
-
-#select * from binlog_stmts;
-
-# Drop ndb_apply_status entries and sort by the statment
-# text to get a deterministic order.
-#
-# Reasonable order would be sort by (PK-cols, stmt_num)
-# - Sorting by PK-cols would give determinism between events from different
-# fragments
-# - Multiple ops on same pk would be in order of application
-#
-# However, as that's harder, and unnecessary given that we just want
-# deterministic output, not applicable SQL, we will just sort by
-# the statement text
-#
---enable_query_log
-select txt from binlog_stmts where txt not like '%ndb_apply_status%' order by txt;
-
---disable_query_log
-drop table raw_binlog_rows;
-drop table binlog_stmt_parts_unassoc;
-drop table binlog_stmt_parts_assoc;
-drop table binlog_stmts;
---enable_query_log
\ No newline at end of file
+--source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc
=== added file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc'
--- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc 2010-11-08 12:19:51 +0000
@@ -0,0 +1,91 @@
+#
+# Get the mysqlbinlog tool --verbose mode to dump the Binlog contents with
+# 'SQL' statements in triple-comments over multiple lines, e.g. :
+#
+### INSERT
+### SET
+### @1=1
+### @2=2
+#
+# Then munch this output into single-line statements
+# e.g. :
+# INSERT SET @1=1 @2=2
+#
+# Then filter + sort to get deterministic order independent of Ndb table
+# fragmentation, epoch in ndb_apply_status etc.
+#
+
+--disable_query_log
+let $MYSQLD_DATADIR= `select @@datadir;`;
+--exec $MYSQL_BINLOG --verbose $MYSQLD_DATADIR/mysqld-bin.000001 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql
+
+create table raw_binlog_rows (txt varchar(1000));
+
+--eval load data local infile '$MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql' into table raw_binlog_rows columns terminated by '\n';
+
+create table binlog_stmt_parts_unassoc (txt varchar(1000), line_count int, stmt_boundary int);
+
+set @line_count=0;
+set @stmt_boundary=0;
+
+# Use replace() here to get rid of any unwanted Windows
+# CRs
+insert into binlog_stmt_parts_unassoc
+ select replace(txt, '\r', ''),
+ @line_count:= @line_count + 1, # So we can preserve order later
+ (txt like '%INSERT%' or # Identify statement boundaries
+ txt like '%UPDATE%' or
+ txt like '%DELETE%')
+ from raw_binlog_rows
+ where
+ txt like '###%'; # Discard non verbose output
+
+#select * from binlog_stmt_parts_unassoc;
+
+create table binlog_stmt_parts_assoc (txt varchar(1000), line_count int, stmt_num int);
+
+set @stmt_count = 0;
+
+insert into binlog_stmt_parts_assoc
+ select txt,
+ line_count,
+ @stmt_count:= @stmt_count + stmt_boundary # All rows from same stmt will
+ # have same stmt_num
+ from binlog_stmt_parts_unassoc order by line_count;
+
+
+#select * from binlog_stmt_parts_assoc;
+
+create table binlog_stmts (txt varchar(1000), stmt_num int);
+
+insert into binlog_stmts
+ select group_concat(right(txt, # Combine rows in statment into 1
+ length(txt) - 4) # Trim ### from line start
+ order by line_count
+ separator ' '), stmt_num
+ from binlog_stmt_parts_assoc
+ group by stmt_num;
+
+#select * from binlog_stmts;
+
+# Drop ndb_apply_status entries and sort by the statment
+# text to get a deterministic order.
+#
+# Reasonable order would be sort by (PK-cols, stmt_num)
+# - Sorting by PK-cols would give determinism between events from different
+# fragments
+# - Multiple ops on same pk would be in order of application
+#
+# However, as that's harder, and unnecessary given that we just want
+# deterministic output, not applicable SQL, we will just sort by
+# the statement text
+#
+--enable_query_log
+--eval select txt from binlog_stmts where txt $binlog_condition order by txt
+
+--disable_query_log
+drop table raw_binlog_rows;
+drop table binlog_stmt_parts_unassoc;
+drop table binlog_stmt_parts_assoc;
+drop table binlog_stmts;
+--enable_query_log
\ No newline at end of file
=== added file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_log_apply_status.test'
--- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_log_apply_status.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_log_apply_status.test 2010-11-08 12:19:51 +0000
@@ -0,0 +1,57 @@
+-- source include/have_ndb.inc
+-- source include/have_binlog_format_mixed_or_row.inc
+
+create table test.t1(a int primary key) engine=ndb;
+
+set global ndb_log_apply_status=Off;
+show variables like '%ndb_log_apply_status%';
+
+reset slave;
+reset master;
+--echo Should have empty apply status table
+select * from mysql.ndb_apply_status;
+
+--echo Dummy incoming ndb_apply_status updates, should not be logged
+begin;
+insert into mysql.ndb_apply_status values (555, 12345, 'binlog.000001', 20, 30);
+insert into mysql.ndb_apply_status values (666, 67890, 'binlog.000001', 50, 60);
+replace into test.t1 values (1); # So that epoch is non-empty
+commit;
+
+--echo Should not see ndb_apply_status updates in the Binlog
+
+# Synchronise with Binlog
+--disable_result_log
+show binlog events;
+--enable_result_log
+
+let $Binlog_condition= like '%binlog.000001%';
+--source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc
+
+set global ndb_log_apply_status=On;
+show variables like '%ndb_log_apply_status%';
+
+reset slave;
+reset master;
+--echo Should have empty apply status table
+select * from mysql.ndb_apply_status;
+
+--echo Dummy incoming ndb_apply_status updates, should be logged
+begin;
+insert into mysql.ndb_apply_status values (555, 12345, 'binlog.000001', 20, 30);
+insert into mysql.ndb_apply_status values (666, 67890, 'binlog.000001', 50, 60);
+replace into test.t1 values (1); # So that epoch is non-empty
+commit;
+
+--echo Should see ndb_apply_status updates in the Binlog
+
+# Synchronise with Binlog
+--disable_result_log
+show binlog events;
+--enable_result_log
+
+let $Binlog_condition= like '%binlog.000001%';
+--source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts_basic.inc
+
+set global ndb_log_apply_status=Off;
+drop table test.t1;
\ No newline at end of file
=== added file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_break_3_chain.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_break_3_chain.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_break_3_chain.result 2010-11-08 12:19:51 +0000
@@ -0,0 +1,85 @@
+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;
+show variables like 'server_id';
+Variable_name Value
+server_id 1
+reset master;
+select @cluster1_server_id:=(variable_value+0)
+from information_schema.global_variables
+where variable_name like 'server_id';
+@cluster1_server_id:=(variable_value+0)
+1
+show variables like 'server_id';
+Variable_name Value
+server_id 2
+stop slave;
+reset master;
+reset slave;
+start slave;
+show variables like 'server_id';
+Variable_name Value
+server_id 3
+stop slave;
+Warnings:
+Note 1255 Slave already has been stopped
+reset master;
+reset slave;
+start slave;
+First show replication 1->2->3
+use test;
+create table t1(a int primary key, b varchar(50)) engine=ndb;
+insert into t1 values (1,'Summertime');
+Cluster2 has insert and apply_status from Cluster1
+show variables like 'server_id';
+Variable_name Value
+server_id 2
+select * from mysql.ndb_apply_status order by server_id;
+server_id epoch log_name start_pos end_pos
+1 # # # #
+select * from test.t1;
+a b
+1 Summertime
+Cluster3 has insert and apply_status from Cluster1+2
+show variables like 'server_id';
+Variable_name Value
+server_id 3
+select * from mysql.ndb_apply_status order by server_id;
+server_id epoch log_name start_pos end_pos
+1 # # # #
+2 # # # #
+select * from test.t1;
+a b
+1 Summertime
+Break Cluster3's link with Cluster2
+stop slave;
+Make further changes on Cluster1
+insert into test.t1 values (2, "The cotton is high");
+insert into test.t1 values (3, "Daddys rich");
+Show changes exist on Cluster2
+select * from test.t1 order by a;
+a b
+1 Summertime
+2 The cotton is high
+3 Daddys rich
+Check data on Cluster3
+select * from test.t1 order by a;
+a b
+1 Summertime
+Now change Cluster3 to skip-over Cluster2 and get binlog direct from Cluster1
+select * from mysql.ndb_apply_status order by server_id;
+server_id epoch log_name start_pos end_pos
+1 # # # #
+2 # # # #
+start slave;
+Now show that cluster 3 is successfully replicating from Cluster1
+select * from test.t1 order by a;
+a b
+1 Summertime
+2 The cotton is high
+3 Daddys rich
+Clean up
+drop table test.t1;
=== modified file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result 2010-10-12 14:53:28 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result 2010-11-08 12:19:51 +0000
@@ -110,3 +110,70 @@ master-bin.000001 # Write_rows 1 # table
master-bin.000001 # Query 1 # COMMIT
STOP SLAVE;
DROP TABLE t1;
+start slave;
+create table t1 (a int primary key, b int) engine=ndb;
+show variables like '%log_orig%';
+Variable_name Value
+ndb_log_orig ON
+'Master' has only slave's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+2 slave-bin.000001
+set global ndb_log_apply_status=On;
+show variables like 'ndb_log_apply_status';
+Variable_name Value
+ndb_log_apply_status ON
+'Slave' has only Master's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+1 master-bin.000001
+'Slave' has following ndb_binlog_index entries
+select inserts, updates, deletes, schemaops, orig_server_id from mysql.ndb_binlog_index order by position;
+inserts updates deletes schemaops orig_server_id
+1 0 0 0 1
+1 0 0 0 2
+set global ndb_log_apply_status=On;
+show variables like 'ndb_log_apply_status';
+Variable_name Value
+ndb_log_apply_status ON
+stop slave;
+insert into t1 values (1,1);
+'Slave' still has only Master's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+1 master-bin.000001
+show binlog events;
+'Slave' has following ndb_binlog_index entries
+select inserts, updates, deletes, schemaops, orig_server_id from mysql.ndb_binlog_index order by position;
+inserts updates deletes schemaops orig_server_id
+1 0 0 0 1
+1 0 0 0 2
+0 0 0 0 2
+1 0 0 0 1
+'Master' still has only Slave's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+2 slave-bin.000001
+start slave;
+'Master' now has own serverid entry as well.
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+1 master-bin.000001
+2 slave-bin.000001
+'Slave' still only has 'Master''s serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+1 master-bin.000001
+Now create event originating at Slave
+insert into t1 values (2,2);
+'Slave' now also has its own serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+server_id log_name
+1 master-bin.000001
+2 slave-bin.000001
+stop slave;
+set global ndb_log_apply_status=off;
+set global ndb_log_apply_status=off;
+stop slave;
+drop table t1;
+drop table t1;
=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.cnf'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.cnf 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.cnf 2010-11-08 12:19:51 +0000
@@ -0,0 +1,118 @@
+!include include/default_mysqld.cnf
+!include include/default_ndbd.cnf
+
+[cluster_config.cluster1]
+NoOfReplicas= 1
+ndbd=
+ndb_mgmd=
+mysqld=,
+ndbapi=,,,,,,,,,
+
+[cluster_config.cluster2]
+NoOfReplicas= 1
+ndbd=
+ndb_mgmd=
+mysqld=
+ndbapi=,,,,
+
+[cluster_config.cluster3]
+NoOfReplicas= 1
+ndbd=
+ndb_mgmd=
+mysqld=
+ndbapi=,,,,
+
+[mysqld]
+# Make all mysqlds use cluster
+ndbcluster
+ndb-wait-connected=20
+ndb-wait-setup=60
+ndb-cluster-connection-pool=3
+slave-allow-batching
+ndb-log-orig
+# Turn on bin logging
+log-bin= cluster1-bin
+# for performance reasons
+ndb-table-temporary=1
+ndb-log-apply-status
+ndb-extra-logging=99
+
+[mysqld.1.cluster1]
+
+[mysqld.1.cluster2]
+
+# Connect mysqld in the second cluster as save to first mysqld
+# Hardcode the host to 127.0.0.1 until running on more
+# than one host and it probably need to be masked anyway
+# master-host= @mysqld.1.#host
+master-host= 127.0.0.1
+master-port= @mysqld.1.cluster1.port
+master-password= @mysqld.1.cluster1.#password
+master-user= @mysqld.1.cluster1.#user
+master-connect-retry= 1
+
+log-bin= cluster2-bin
+relay-log= cluster2-relay-bin
+
+init-rpl-role= slave
+log-slave-updates
+master-retry-count= 10
+ndb-log-apply-status
+
+# Values reported by slave when it connect to master
+# and shows up in SHOW SLAVE STATUS;
+report-host= 127.0.0.1
+report-port= @mysqld.1.cluster2.port
+report-user= root
+
+loose-skip-innodb
+skip-slave-start
+
+# Directory where slaves find the dumps generated by "load data"
+# on the server. The path need to have constant length otherwise
+# test results will vary, thus a relative path is used.
+slave-load-tmpdir= ../../../tmp
+
+rpl-recovery-rank= @mysqld.1.cluster2.server-id
+
+[mysqld.1.cluster3]
+master-host= 127.0.0.1
+master-port= @mysqld.1.cluster2.port
+master-password= @mysqld.1.cluster2.#password
+master-user= @mysqld.1.cluster2.#user
+master-connect-retry= 1
+
+log-bin= cluster3-bin
+relay-log= cluster3-relay-bin
+
+init-rpl-role= slave
+log-slave-updates
+master-retry-count= 10
+ndb-log-apply-status
+
+loose-skip-innodb
+skip-slave-start
+
+# Directory where slaves find the dumps generated by "load data"
+# on the server. The path need to have constant length otherwise
+# test results will vary, thus a relative path is used.
+slave-load-tmpdir= ../../../tmp
+
+rpl-recovery-rank= @mysqld.1.cluster3.server-id
+
+[ENV]
+NDB_CONNECTSTRING= @mysql_cluster.cluster1.ndb_connectstring
+MASTER_MYPORT= @mysqld.1.cluster1.port
+MASTER_MYPORT1= @mysqld.2.cluster1.port
+CLUSTER1_HOST= 127.0.0.1
+CLUSTER1_MYPORT= @mysqld.1.cluster1.port
+CLUSTER1_USER= @mysqld.1.cluster1.#user
+
+NDB_CONNECTSTRING_SLAVE= @mysql_cluster.cluster2.ndb_connectstring
+SLAVE_MYPORT= @mysqld.1.cluster2.port
+SLAVE_MYSOCK= @mysqld.1.cluster2.socket
+CLUSTER2_MYPORT= @mysqld.1.cluster2.port
+
+CLUSTER3_MYPORT= @mysqld.1.cluster3.port
+
+NDB_BACKUP_DIR= @cluster_config.ndbd.1.cluster1.BackupDataDir
=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.test'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_break_3_chain.test 2010-11-08 12:19:51 +0000
@@ -0,0 +1,113 @@
+--source include/have_ndb.inc
+--source suite/rpl_ndb/ndb_master-slave.inc
+
+connect (cluster1, 127.0.0.1,root,,test,$CLUSTER1_MYPORT);
+connect (cluster2, 127.0.0.1,root,,test,$CLUSTER2_MYPORT);
+connect (cluster3, 127.0.0.1,root,,test,$CLUSTER3_MYPORT);
+
+
+# set up replication 1->2->3
+--connection cluster1
+show variables like 'server_id';
+reset master;
+select @cluster1_server_id:=(variable_value+0)
+ from information_schema.global_variables
+ where variable_name like 'server_id';
+
+let $CLUSTER1_SERVER_ID= query_get_value('select @cluster1_server_id as v',v,1);
+
+--connection cluster2
+show variables like 'server_id';
+stop slave;
+reset master;
+reset slave;
+start slave;
+
+--connection cluster3
+show variables like 'server_id';
+stop slave;
+reset master;
+reset slave;
+start slave;
+
+--echo First show replication 1->2->3
+--connection cluster1
+use test;
+create table t1(a int primary key, b varchar(50)) engine=ndb;
+
+insert into t1 values (1,'Summertime');
+
+--sync_slave_with_master cluster2
+--echo Cluster2 has insert and apply_status from Cluster1
+show variables like 'server_id';
+--replace_column 2 # 3 # 4 # 5 #
+select * from mysql.ndb_apply_status order by server_id;
+select * from test.t1;
+
+--sync_slave_with_master cluster3
+--echo Cluster3 has insert and apply_status from Cluster1+2
+show variables like 'server_id';
+--replace_column 2 # 3 # 4 # 5 #
+select * from mysql.ndb_apply_status order by server_id;
+select * from test.t1;
+
+--echo Break Cluster3's link with Cluster2
+--connection cluster3
+stop slave;
+
+--echo Make further changes on Cluster1
+--connection cluster1
+insert into test.t1 values (2, "The cotton is high");
+insert into test.t1 values (3, "Daddys rich");
+
+--sync_slave_with_master cluster2
+--echo Show changes exist on Cluster2
+select * from test.t1 order by a;
+
+--echo Check data on Cluster3
+--connection cluster3
+select * from test.t1 order by a;
+
+--echo Now change Cluster3 to skip-over Cluster2 and get binlog direct from Cluster1
+
+--replace_column 2 # 3 # 4 # 5 #
+select * from mysql.ndb_apply_status order by server_id;
+
+--disable_query_log
+--disable_result_log
+eval select @binlog_file_name:=log_name from mysql.ndb_apply_status
+ where server_id = $CLUSTER1_SERVER_ID;
+eval select @binlog_file_pos:=end_pos from mysql.ndb_apply_status
+ where server_id = $CLUSTER1_SERVER_ID;
+
+let $CLUSTER1_LOG_FILE= query_get_value('select @binlog_file_name as v', v, 1);
+let $CLUSTER1_LOG_POS= query_get_value('select @binlog_file_pos as v', v, 1);
+
+eval change master to master_host='$CLUSTER1_HOST',
+ master_port=$CLUSTER1_MYPORT,
+ master_user='$CLUSTER1_USER',
+ master_log_file='$CLUSTER1_LOG_FILE',
+ master_log_pos=$CLUSTER1_LOG_POS;
+--enable_query_log
+--enable_result_log
+
+start slave;
+
+--connection cluster1
+--sync_slave_with_master cluster3
+
+--echo Now show that cluster 3 is successfully replicating from Cluster1
+--connection cluster3
+select * from test.t1 order by a;
+
+
+--echo Clean up
+--connection cluster1
+drop table test.t1;
+
+--sync_slave_with_master cluster2
+--connection cluster1
+--sync_slave_with_master cluster3
+
+
+
=== modified file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test 2010-10-22 15:16:26 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test 2010-11-08 12:19:51 +0000
@@ -69,3 +69,82 @@ STOP SLAVE;
--connection master
DROP TABLE t1;
-- sync_slave_with_master
+
+# Test ndb_log_apply_status option
+
+--connection master
+start slave;
+create table t1 (a int primary key, b int) engine=ndb;
+show variables like '%log_orig%';
+
+--echo 'Master' has only slave's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+
+set global ndb_log_apply_status=On;
+show variables like 'ndb_log_apply_status';
+
+--connection slave
+--echo 'Slave' has only Master's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+--echo 'Slave' has following ndb_binlog_index entries
+select inserts, updates, deletes, schemaops, orig_server_id from mysql.ndb_binlog_index order by position;
+
+set global ndb_log_apply_status=On;
+show variables like 'ndb_log_apply_status';
+
+--connection master
+
+stop slave;
+insert into t1 values (1,1);
+--sync_slave_with_master
+
+--connection slave
+--echo 'Slave' still has only Master's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+
+--disable_result_log
+show binlog events;
+--enable_result_log
+--echo 'Slave' has following ndb_binlog_index entries
+select inserts, updates, deletes, schemaops, orig_server_id from mysql.ndb_binlog_index order by position;
+
+--connection master
+--echo 'Master' still has only Slave's serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+
+start slave;
+--connection slave
+--sync_slave_with_master master
+
+--connection master
+--echo 'Master' now has own serverid entry as well.
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+
+--connection slave
+--echo 'Slave' still only has 'Master''s serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+--echo Now create event originating at Slave
+insert into t1 values (2,2);
+--sync_slave_with_master master
+
+--connection master
+--sync_slave_with_master slave
+
+--connection slave
+--echo 'Slave' now also has its own serverid entry
+select server_id, log_name from mysql.ndb_apply_status order by server_id;
+
+
+--connection master
+stop slave;
+set global ndb_log_apply_status=off;
+
+--connection slave
+set global ndb_log_apply_status=off;
+stop slave;
+
+drop table t1;
+
+--connection master
+
+drop table t1;
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2010-11-08 10:41:09 +0000
+++ b/sql/ha_ndbcluster.cc 2010-11-08 12:19:51 +0000
@@ -14545,6 +14545,17 @@ static MYSQL_SYSVAR_BOOL(
0 /* default */
);
+my_bool opt_ndb_log_apply_status;
+static MYSQL_SYSVAR_BOOL(
+ log_apply_status, /* name */
+ opt_ndb_log_apply_status, /* var */
+ PLUGIN_VAR_OPCMDARG,
+ "Log ndb_apply_status updates from Master in the Binlog",
+ NULL, /* check func. */
+ NULL, /* update func. */
+ 0 /* default */
+);
+
static MYSQL_SYSVAR_STR(
connectstring, /* name */
@@ -14611,6 +14622,7 @@ static struct st_mysql_sys_var* system_v
MYSQL_SYSVAR(log_bin),
MYSQL_SYSVAR(log_binlog_index),
MYSQL_SYSVAR(log_empty_epochs),
+ MYSQL_SYSVAR(log_apply_status),
MYSQL_SYSVAR(connectstring),
MYSQL_SYSVAR(mgmd_host),
MYSQL_SYSVAR(nodeid),
=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc 2010-10-22 12:35:05 +0000
+++ b/sql/ha_ndbcluster_binlog.cc 2010-11-08 12:19:51 +0000
@@ -42,6 +42,7 @@ extern my_bool opt_ndb_log_empty_epochs;
extern my_bool opt_ndb_log_update_as_write;
extern my_bool opt_ndb_log_updated_only;
extern my_bool opt_ndb_log_binlog_index;
+extern my_bool opt_ndb_log_apply_status;
extern ulong opt_ndb_extra_logging;
extern ulong opt_server_id_mask;
@@ -3992,6 +3993,30 @@ ndbcluster_read_binlog_replication(THD *
int error= 0;
const char *error_str= "<none>";
+ /* Override for ndb_apply_status when logging */
+ if (opt_ndb_log_apply_status &&
+ do_set_binlog_flags)
+ {
+ if (strcmp(db, NDB_REP_DB) == 0 &&
+ strcmp(table_name, NDB_APPLY_TABLE) == 0)
+ {
+ /*
+ Ensure that we get all columns from ndb_apply_status updates
+ by forcing FULL event type
+ Also, ensure that ndb_apply_status events are always logged as
+ WRITES.
+ This is needed so that received ndb_apply_status WRITES can be
+ cleanly propagated.
+ */
+ DBUG_PRINT("info", ("ndb_apply_status defaulting to FULL, USE_WRITE"));
+ sql_print_information("NDB : ndb-log-apply-status forcing "
+ "%s.%s to FULL USE_WRITE",
+ NDB_REP_DB, NDB_APPLY_TABLE);
+ set_binlog_flags(share, NBT_FULL);
+ DBUG_RETURN(0);
+ }
+ }
+
ndb->setDatabaseName(ndb_rep_db);
NDBDICT *dict= ndb->getDictionary();
Ndb_table_guard ndbtab_g(dict, ndb_replication_table);
@@ -5372,7 +5397,8 @@ static int
ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
ndb_binlog_index_row **rows,
injector::transaction &trans,
- unsigned &trans_row_count)
+ unsigned &trans_row_count,
+ unsigned &trans_slave_row_count)
{
Ndb_event_data *event_data= (Ndb_event_data *) pOp->getCustomData();
TABLE *table= event_data->table;
@@ -5381,15 +5407,49 @@ ndb_binlog_thread_handle_data_event(Ndb
{
return 0;
}
+
+ uint32 anyValue= pOp->getAnyValue();
+ if (ndbcluster_anyvalue_is_reserved(anyValue))
+ {
+ if (!ndbcluster_anyvalue_is_nologging(anyValue))
+ sql_print_warning("NDB: unknown value for binlog signalling 0x%X, "
+ "event not logged",
+ anyValue);
+ return 0;
+ }
+ uint32 originating_server_id= ndbcluster_anyvalue_get_serverid(anyValue);
+ bool log_this_slave_update = g_ndb_log_slave_updates;
+ bool count_this_event = true;
+
if (share == ndb_apply_status_share)
{
- if (opt_ndb_log_orig)
+ /*
+ Note that option values are read without synchronisation w.r.t.
+ thread setting option variable or epoch boundaries.
+ */
+ if (opt_ndb_log_apply_status ||
+ opt_ndb_log_orig)
{
+ Uint32 ndb_apply_status_logging_server_id= originating_server_id;
+ Uint32 ndb_apply_status_server_id= 0;
+ Uint64 ndb_apply_status_epoch= 0;
+ bool event_has_data = false;
+
switch(pOp->getEventType())
{
case NDBEVENT::TE_INSERT:
// fall through
case NDBEVENT::TE_UPDATE:
+ event_has_data = true;
+ break;
+ case NDBEVENT::TE_DELETE:
+ break;
+ default:
+ /* We should REALLY never get here */
+ abort();
+ }
+
+ if (likely( event_has_data ))
{
/* unpack data to fetch orig_server_id and orig_epoch */
uint n_fields= table->s->fields;
@@ -5398,43 +5458,77 @@ ndb_binlog_thread_handle_data_event(Ndb
bitmap_init(&b, bitbuf, n_fields, FALSE);
bitmap_set_all(&b);
ndb_unpack_record(table, event_data->ndb_value[0], &b, table->record[0]);
- /* store */
- ndb_binlog_index_row *row= ndb_find_binlog_index_row
- (rows, (uint)((Field_long *)table->field[0])->val_int(), 1);
- row->orig_epoch= ((Field_longlong *)table->field[1])->val_int();
- break;
- }
- case NDBEVENT::TE_DELETE:
- break;
- default:
- /* We should REALLY never get here */
- abort();
+ ndb_apply_status_server_id= (uint)((Field_long *)table->field[0])->val_int();
+ ndb_apply_status_epoch= ((Field_longlong *)table->field[1])->val_int();
+
+ if (opt_ndb_log_apply_status)
+ {
+ /*
+ Determine if event came from our immediate Master server
+ Ignore locally manually sourced and reserved events
+ */
+ if ((ndb_apply_status_logging_server_id != 0) &&
+ (! ndbcluster_anyvalue_is_reserved(ndb_apply_status_logging_server_id)))
+ {
+ bool isFromImmediateMaster = (ndb_apply_status_server_id ==
+ ndb_apply_status_logging_server_id);
+
+ if (isFromImmediateMaster)
+ {
+ /*
+ We log this event with our server-id so that it
+ propagates back to the originating Master (our
+ immediate Master)
+ */
+ assert(ndb_apply_status_logging_server_id != ::server_id);
+
+ originating_server_id= 0; /* Will be set to our ::serverid below */
+ }
+ }
+ }
+
+ if (opt_ndb_log_orig)
+ {
+ /* store */
+ ndb_binlog_index_row *row= ndb_find_binlog_index_row
+ (rows, ndb_apply_status_server_id, 1);
+ row->orig_epoch= ndb_apply_status_epoch;
+ }
}
- }
- return 0;
- }
+ } // opt_ndb_log_apply_status || opt_ndb_log_orig)
- uint32 anyValue= pOp->getAnyValue();
- if (ndbcluster_anyvalue_is_reserved(anyValue))
- {
- if (!ndbcluster_anyvalue_is_nologging(anyValue))
- sql_print_warning("NDB: unknown value for binlog signalling 0x%X, "
- "event not logged",
- anyValue);
- return 0;
+ if (opt_ndb_log_apply_status)
+ {
+ /* We are logging ndb_apply_status changes
+ * Don't count this event as making an epoch non-empty
+ * Log this event in the Binlog
+ */
+ count_this_event = false;
+ log_this_slave_update = true;
+ }
+ else
+ {
+ /* Not logging ndb_apply_status updates, discard this event now */
+ return 0;
+ }
}
- uint32 originating_server_id= ndbcluster_anyvalue_get_serverid(anyValue);
-
if (originating_server_id == 0)
originating_server_id= ::server_id;
- else if (!g_ndb_log_slave_updates)
+ else
{
- /*
- This event comes from a slave applier since it has an originating
- server id set. Since option to log slave updates is not set, skip it.
- */
- return 0;
+ /* Track that we received a replicated row event */
+ if (likely( count_this_event ))
+ trans_slave_row_count++;
+
+ if (!log_this_slave_update)
+ {
+ /*
+ This event comes from a slave applier since it has an originating
+ server id set. Since option to log slave updates is not set, skip it.
+ */
+ return 0;
+ }
}
/*
@@ -5481,8 +5575,11 @@ ndb_binlog_thread_handle_data_event(Ndb
switch(pOp->getEventType())
{
case NDBEVENT::TE_INSERT:
- row->n_inserts++;
- trans_row_count++;
+ if (likely( count_this_event ))
+ {
+ row->n_inserts++;
+ trans_row_count++;
+ }
DBUG_PRINT("info", ("INSERT INTO %s.%s",
table->s->db.str, table->s->table_name.str));
{
@@ -5504,8 +5601,11 @@ ndb_binlog_thread_handle_data_event(Ndb
}
break;
case NDBEVENT::TE_DELETE:
- row->n_deletes++;
- trans_row_count++;
+ if (likely( count_this_event ))
+ {
+ row->n_deletes++;
+ trans_row_count++;
+ }
DBUG_PRINT("info",("DELETE FROM %s.%s",
table->s->db.str, table->s->table_name.str));
{
@@ -5545,8 +5645,11 @@ ndb_binlog_thread_handle_data_event(Ndb
}
break;
case NDBEVENT::TE_UPDATE:
- row->n_updates++;
- trans_row_count++;
+ if (likely( count_this_event ))
+ {
+ row->n_updates++;
+ trans_row_count++;
+ }
DBUG_PRINT("info", ("UPDATE %s.%s",
table->s->db.str, table->s->table_name.str));
{
@@ -6275,6 +6378,7 @@ restart_cluster_failure:
ndb_binlog_index_row *rows= &_row;
injector::transaction trans;
unsigned trans_row_count= 0;
+ unsigned trans_slave_row_count= 0;
if (!pOp)
{
/*
@@ -6320,6 +6424,7 @@ restart_cluster_failure:
DBUG_PRINT("info", ("Initializing transaction"));
inj->new_trans(thd, &trans);
trans_row_count= 0;
+ trans_slave_row_count= 0;
// pass table map before epoch
{
Uint32 iter= 0;
@@ -6473,7 +6578,7 @@ restart_cluster_failure:
#endif
if ((unsigned) pOp->getEventType() <
(unsigned) NDBEVENT::TE_FIRST_NON_DATA_EVENT)
- ndb_binlog_thread_handle_data_event(i_ndb, pOp, &rows, trans, trans_row_count);
+ ndb_binlog_thread_handle_data_event(i_ndb, pOp, &rows, trans, trans_row_count, trans_slave_row_count);
else
{
ndb_binlog_thread_handle_non_data_event(thd, pOp, *rows);
@@ -6512,17 +6617,34 @@ restart_cluster_failure:
while (trans.good())
{
- if ((trans_row_count == 0) && !opt_ndb_log_empty_epochs)
+ if (!opt_ndb_log_empty_epochs)
{
- /* nothing to commit, rollback instead */
- if (int r= trans.rollback())
+ /*
+ If
+ - We did not add any 'real' rows to the Binlog AND
+ - We did not apply any slave row updates, only
+ ndb_apply_status updates
+ THEN
+ Don't write the Binlog transaction which just
+ contains ndb_apply_status updates.
+ (For cicular rep with log_apply_status, ndb_apply_status
+ updates will propagate while some related, real update
+ is propagating)
+ */
+ if ((trans_row_count == 0) &&
+ (! (opt_ndb_log_apply_status &&
+ trans_slave_row_count) ))
{
- sql_print_error("NDB Binlog: "
- "Error during ROLLBACK of GCI %u/%u. Error: %d",
- uint(gci >> 32), uint(gci), r);
- /* TODO: Further handling? */
+ /* nothing to commit, rollback instead */
+ if (int r= trans.rollback())
+ {
+ sql_print_error("NDB Binlog: "
+ "Error during ROLLBACK of GCI %u/%u. Error: %d",
+ uint(gci >> 32), uint(gci), r);
+ /* TODO: Further handling? */
+ }
+ break;
}
- break;
}
commit_to_binlog:
thd->proc_info= "Committing events to binlog";
Attachment: [text/bzr-bundle] bzr/frazer@mysql.com-20101108121951-k5q7r574eq6o87lc.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0 branch (frazer:3953) | Frazer Clement | 8 Nov |