#At file:///home/frazer/bzr/mysql-5.1-telco-7.0-reflect/ based on revid:jonas@stripped
3773 Frazer Clement 2010-09-22
WL5353 Reflected GCI
Test commit for CluB build/test cycle
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/r/rpl_ndb_conflict_epoch.result
mysql-test/suite/rpl_ndb/r/rpl_ndb_init_rep_status.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
mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.cnf
mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.test
mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc
mysql-test/suite/rpl_ndb/t/rpl_ndb_init_rep_status.test
modified:
mysql-test/include/ndb_conflict_info.inc
mysql-test/include/ndb_conflict_info_init.inc
mysql-test/suite/ndb/r/ndb_basic.result
mysql-test/suite/ndb/r/ndb_native_default_support.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/r/rpl_ndb_conflict_max.result
mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max_delete_win.result
mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_old.result
mysql-test/suite/rpl_ndb/r/rpl_ndb_rep_error.result
mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test
mysql-test/suite/rpl_ndb/t/rpl_ndb_rep_error.test
sql/ha_ndbcluster.cc
sql/ha_ndbcluster.h
sql/ha_ndbcluster_binlog.cc
sql/ha_ndbcluster_binlog.h
storage/ndb/include/kernel/AttributeHeader.hpp
storage/ndb/include/kernel/kernel_types.h
storage/ndb/include/kernel/signaldata/CreateTab.hpp
storage/ndb/include/kernel/signaldata/CreateTable.hpp
storage/ndb/include/kernel/signaldata/DictTabInfo.hpp
storage/ndb/include/ndb_version.h.in
storage/ndb/include/ndbapi/NdbDictionary.hpp
storage/ndb/include/ndbapi/NdbOperation.hpp
storage/ndb/include/ndbapi/NdbTransaction.hpp
storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
storage/ndb/src/kernel/vm/LongSignal.cpp
storage/ndb/src/kernel/vm/LongSignalImpl.hpp
storage/ndb/src/kernel/vm/SimulatedBlock.cpp
storage/ndb/src/kernel/vm/SimulatedBlock.hpp
storage/ndb/src/ndbapi/NdbDictionary.cpp
storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
storage/ndb/src/ndbapi/NdbOperationExec.cpp
storage/ndb/src/ndbapi/NdbTransaction.cpp
storage/ndb/test/include/HugoOperations.hpp
storage/ndb/test/include/HugoTransactions.hpp
storage/ndb/test/ndbapi/testRestartGci.cpp
storage/ndb/test/src/HugoOperations.cpp
storage/ndb/test/src/HugoTransactions.cpp
storage/ndb/test/src/NDBT_Table.cpp
storage/ndb/test/tools/hugoPkUpdate.cpp
storage/ndb/tools/select_all.cpp
=== modified file 'mysql-test/include/ndb_conflict_info.inc'
--- a/mysql-test/include/ndb_conflict_info.inc 2009-02-16 15:54:40 +0000
+++ b/mysql-test/include/ndb_conflict_info.inc 2010-09-22 10:49:11 +0000
@@ -1,5 +1,7 @@
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
--replace_column 3 # 5 # 6 #
--error 0,1146
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
=== modified file 'mysql-test/include/ndb_conflict_info_init.inc'
--- a/mysql-test/include/ndb_conflict_info_init.inc 2009-02-16 15:54:40 +0000
+++ b/mysql-test/include/ndb_conflict_info_init.inc 2010-09-22 10:49:11 +0000
@@ -2,6 +2,8 @@
--disable_result_log
SELECT @init_ndb_conflict_fn_max:=(VARIABLE_VALUE+0) FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
SELECT @init_ndb_conflict_fn_old:=(VARIABLE_VALUE+0) FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+SELECT @init_ndb_conflict_fn_max_del_win:=(VARIABLE_VALUE+0) FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+SELECT @init_ndb_conflict_fn_epoch:=(VARIABLE_VALUE+0) FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
--error 0,1146
DELETE FROM `t1$EX`;
--enable_query_log
=== modified file 'mysql-test/suite/ndb/r/ndb_basic.result'
--- a/mysql-test/suite/ndb/r/ndb_basic.result 2010-06-16 20:49:05 +0000
+++ b/mysql-test/suite/ndb/r/ndb_basic.result 2010-09-22 10:49:11 +0000
@@ -21,12 +21,16 @@ Ndb_pruned_scan_count #
Ndb_cluster_connection_pool #
Ndb_conflict_fn_max #
Ndb_conflict_fn_old #
+Ndb_conflict_fn_max_del_win #
+Ndb_conflict_fn_epoch #
+Ndb_slave_max_replicated_epoch #
SHOW GLOBAL VARIABLES LIKE 'ndb\_%';
Variable_name Value
ndb_autoincrement_prefetch_sz #
ndb_batch_size #
ndb_cache_check_time #
ndb_cluster_connection_pool #
+ndb_cluster_server_ids #
ndb_connectstring #
ndb_distribution #
ndb_extra_logging #
@@ -34,6 +38,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 #
=== modified file 'mysql-test/suite/ndb/r/ndb_native_default_support.result'
--- a/mysql-test/suite/ndb/r/ndb_native_default_support.result 2010-08-19 13:35:45 +0000
+++ b/mysql-test/suite/ndb/r/ndb_native_default_support.result 2010-09-22 10:49:11 +0000
@@ -140,6 +140,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -178,6 +180,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
pk Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -246,6 +250,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -283,6 +289,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
pk Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -360,6 +368,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -450,6 +460,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -497,6 +509,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -538,6 +552,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -587,6 +603,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -630,6 +648,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -672,6 +692,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -714,6 +736,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -758,6 +782,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -805,6 +831,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -847,6 +875,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -891,6 +921,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -936,6 +968,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -985,6 +1019,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1028,6 +1064,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1070,6 +1108,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1112,6 +1152,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1154,6 +1196,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1198,6 +1242,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1245,6 +1291,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1333,6 +1381,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
=== 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-09-22 10:49:11 +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-09-22 10:49:11 +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-09-22 10:49:11 +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-09-22 10:49:11 +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-09-22 10:49:11 +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;
+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 2009-12-16 14:19:40 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result 2010-09-22 10:49:11 +0000
@@ -150,3 +150,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 File, inserts, updates, deletes, schemaops, orig_server_id from mysql.ndb_binlog_index order by position;
+File inserts updates deletes schemaops orig_server_id
+./slave-bin.000001 1 0 0 0 1
+./slave-bin.000001 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 File, inserts, updates, deletes, schemaops, orig_server_id from mysql.ndb_binlog_index order by position;
+File inserts updates deletes schemaops orig_server_id
+./slave-bin.000001 1 0 0 0 1
+./slave-bin.000001 1 0 0 0 2
+./slave-bin.000001 0 0 0 0 2
+./slave-bin.000001 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/r/rpl_ndb_conflict_epoch.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_epoch.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_epoch.result 2010-09-22 10:49:11 +0000
@@ -0,0 +1,2550 @@
+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;
+Setup circular replication
+RESET MASTER;
+select @slave_server_id:=(variable_value+0)
+from information_schema.global_variables
+where variable_name like 'server_id';
+@slave_server_id:=(variable_value+0)
+3
+CHANGE MASTER TO master_host="127.0.0.1",master_port=SLAVE_PORT,master_user="root";
+START SLAVE;
+select @master_server_id:=(variable_value+0)
+from information_schema.global_variables
+where variable_name like 'server_id';
+@master_server_id:=(variable_value+0)
+1
+Setup ndb_replication and t1 exceptions table
+Populate ndb_replication table as necessary
+-- 0 extra gci bits
+replace into mysql.ndb_replication values
+("test", "t1", 3, 7, NULL),
+("test", "t1", 1, 7, "NDB$EPOCH(0)");
+create table `test`.`t1$EX`
+ (server_id int unsigned,
+master_server_id int unsigned,
+master_epoch bigint unsigned,
+count int unsigned,
+a int not null,
+d int,
+primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+Create table
+create table test.t1(a int primary key, b varchar(255)) engine = ndb;
+Create other table
+create table test.t2(a int primary key, b int) engine = ndb;
+----------------------------------
+Test 1 : Basic two-way replication
+----------------------------------
+insert into test.t1 values (1, "Metropole");
+-- Give time for a new epoch on the Master
+-- Insert something to ensure the new epoch is noticed
+replace into test.t2 values (2, 1);
+-- Flushed to slave
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Flushed back to Master
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Now update data on slave
+update test.t1 set b="Favorit" where a=1;
+-- Now check data on master
+select * from test.t1 order by a;
+a b
+1 Favorit
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Now perform multiple consecutive updates on the slave
+update test.t1 set b="Elephant house" where a=1;
+update test.t1 set b="Beach house" where a=1;
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Now check they've applied on the master
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+--------------------------------------------
+Test 2 : Normal Insert from Secondary Master
+--------------------------------------------
+-- Insert a new row on the Slave
+insert into test.t1 values (2, "Forrest");
+-- Check it exists on the Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Forrest
+-- Update from the slave
+update test.t1 set b="Reds" where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Reds
+delete from test.t1 where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-------------------------------
+Test 3 : Insert-Insert conflict
+-------------------------------
+stop slave;
+-- Insert a row on the Primary Master
+insert into test.t1 values (2, "Loopy Lornas");
+-- Insert a row on the secondary Master
+insert into test.t1 values (2, "Cloisters");
+-- Examine data on Primary Master (should be unaffected)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-- Examine conflict indicators on Primary Master
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on isolated secondary Master (should be as-set)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Cloisters
+-- Restart secondary Masters slave
+start slave;
+-- Reexamine secondary Master's data (should be same as Primary Masters)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-------------------------------
+Test 4 : Update-Update conflict
+-------------------------------
+-- Stop replication to secondary master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Peters Yard" where a=2;
+-- Show data on Primary Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Update row on Secondary Master
+update test.t1 set b="Toast" where a=2;
+-- Examine data on Primary Master - should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+2
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on secondary - should be as set
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Toast
+-- Now restart slave, will re-align row
+start slave;
+-- Check that Secondary is re-aligned
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+-------------------------------
+Test 5 : Update-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Update on Primary Master
+update test.t1 set b="Pear tree" where a = 2;
+-- Delete on Secondary Master
+delete from test.t1 where a = 2;
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+3
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, still missing
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+-------------------------------
+Test 6 : Delete-Update conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=2;
+-- Update on Secondary Master
+update test.t1 set b="Black pig" where a=2;
+-- Examine data on Primary Master, should be unaffected (no row)
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+4
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, should be as inserted
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Black pig
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master (deleted)
+select * from test.t1 order by a;
+a b
+1 Beach house
+-------------------------------
+Test 7 : Delete-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=1;
+-- Delete on Secondary Master
+delete from test.t1 where a=1;
+-- Examine data on Primary Master, no row
+select * from test.t1 order by a;
+a b
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+5
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, no row
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, no row
+select * from test.t1 order by a;
+a b
+------------------------------------------------
+Test 8 : Delete-Delete, Insert conflict exposure
+------------------------------------------------
+-- Insert a row on Secondary Master
+insert into test.t1 values (3, "Espy");
+-- Check it's present on Primary Master
+select * from test.t1 order by a;
+a b
+3 Espy
+-- Stop replication in both directions
+stop slave;
+stop slave;
+-- Delete row from both clusters
+delete from test.t1 where a=3;
+delete from test.t1 where a=3;
+-- Follow up with Insert from Secondary master
+insert into test.t1 values (3, "Dalriada");
+-- Restart replication in both directions
+start slave;
+start slave;
+-- Check data on both sites - diverged
+-- Secondary master :
+select * from test.t1 order by a;
+a b
+-- Primary master :
+select * from test.t1 order by a;
+a b
+3 Dalriada
+--Remove extra row
+delete from test.t1 where a=3;
+-- Note that Delete-Delete conflict detected below
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+6
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+------------------------------------------------
+Test 9 : Insert, Insert-Update-Delete conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Insert row on Primary Master
+insert into test.t1 values (4, "Haymarket");
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Outhouse");
+-- Update row on Secondary Master
+update test.t1 set b="Mathers" where a = 4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Examine data (none) on Secondary Master
+select * from test.t1 order by a;
+a b
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Haymarket
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+9
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master (none)
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master's slave
+start slave;
+-- Check data on Secondary Master, should be same as Primary Master
+select * from test.t1;
+a b
+4 Haymarket
+------------------------------------------------
+Test 10 : Update, Delete-Insert-Update conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Blind poet" where a=4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Drouthy Neebors");
+-- Update row on Secondary Master
+update test.t1 set b="The Tankard" where a=4;
+-- Check data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on Secondary Master, as set
+select * from test.t1 order by a;
+a b
+4 The Tankard
+-- Restart Secondary Master slave
+start slave;
+-- Check data on Secondary Master - should be as Primary
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+drop table test.t1;
+drop table test.t2;
+drop table test.t1$EX;
+Populate ndb_replication table as necessary
+-- 1 extra gci bits
+replace into mysql.ndb_replication values
+("test", "t1", 3, 7, NULL),
+("test", "t1", 1, 7, "NDB$EPOCH(1)");
+create table `test`.`t1$EX`
+ (server_id int unsigned,
+master_server_id int unsigned,
+master_epoch bigint unsigned,
+count int unsigned,
+a int not null,
+d int,
+primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+Create table
+create table test.t1(a int primary key, b varchar(255)) engine = ndb;
+Create other table
+create table test.t2(a int primary key, b int) engine = ndb;
+----------------------------------
+Test 1 : Basic two-way replication
+----------------------------------
+insert into test.t1 values (1, "Metropole");
+-- Give time for a new epoch on the Master
+-- Insert something to ensure the new epoch is noticed
+replace into test.t2 values (2, 1);
+-- Flushed to slave
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Flushed back to Master
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Now update data on slave
+update test.t1 set b="Favorit" where a=1;
+-- Now check data on master
+select * from test.t1 order by a;
+a b
+1 Favorit
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Now perform multiple consecutive updates on the slave
+update test.t1 set b="Elephant house" where a=1;
+update test.t1 set b="Beach house" where a=1;
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Now check they've applied on the master
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+--------------------------------------------
+Test 2 : Normal Insert from Secondary Master
+--------------------------------------------
+-- Insert a new row on the Slave
+insert into test.t1 values (2, "Forrest");
+-- Check it exists on the Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Forrest
+-- Update from the slave
+update test.t1 set b="Reds" where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Reds
+delete from test.t1 where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-------------------------------
+Test 3 : Insert-Insert conflict
+-------------------------------
+stop slave;
+-- Insert a row on the Primary Master
+insert into test.t1 values (2, "Loopy Lornas");
+-- Insert a row on the secondary Master
+insert into test.t1 values (2, "Cloisters");
+-- Examine data on Primary Master (should be unaffected)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-- Examine conflict indicators on Primary Master
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on isolated secondary Master (should be as-set)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Cloisters
+-- Restart secondary Masters slave
+start slave;
+-- Reexamine secondary Master's data (should be same as Primary Masters)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-------------------------------
+Test 4 : Update-Update conflict
+-------------------------------
+-- Stop replication to secondary master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Peters Yard" where a=2;
+-- Show data on Primary Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Update row on Secondary Master
+update test.t1 set b="Toast" where a=2;
+-- Examine data on Primary Master - should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+2
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on secondary - should be as set
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Toast
+-- Now restart slave, will re-align row
+start slave;
+-- Check that Secondary is re-aligned
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+-------------------------------
+Test 5 : Update-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Update on Primary Master
+update test.t1 set b="Pear tree" where a = 2;
+-- Delete on Secondary Master
+delete from test.t1 where a = 2;
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+3
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, still missing
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+-------------------------------
+Test 6 : Delete-Update conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=2;
+-- Update on Secondary Master
+update test.t1 set b="Black pig" where a=2;
+-- Examine data on Primary Master, should be unaffected (no row)
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+4
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, should be as inserted
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Black pig
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master (deleted)
+select * from test.t1 order by a;
+a b
+1 Beach house
+-------------------------------
+Test 7 : Delete-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=1;
+-- Delete on Secondary Master
+delete from test.t1 where a=1;
+-- Examine data on Primary Master, no row
+select * from test.t1 order by a;
+a b
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+5
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, no row
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, no row
+select * from test.t1 order by a;
+a b
+------------------------------------------------
+Test 8 : Delete-Delete, Insert conflict exposure
+------------------------------------------------
+-- Insert a row on Secondary Master
+insert into test.t1 values (3, "Espy");
+-- Check it's present on Primary Master
+select * from test.t1 order by a;
+a b
+3 Espy
+-- Stop replication in both directions
+stop slave;
+stop slave;
+-- Delete row from both clusters
+delete from test.t1 where a=3;
+delete from test.t1 where a=3;
+-- Follow up with Insert from Secondary master
+insert into test.t1 values (3, "Dalriada");
+-- Restart replication in both directions
+start slave;
+start slave;
+-- Check data on both sites - diverged
+-- Secondary master :
+select * from test.t1 order by a;
+a b
+-- Primary master :
+select * from test.t1 order by a;
+a b
+3 Dalriada
+--Remove extra row
+delete from test.t1 where a=3;
+-- Note that Delete-Delete conflict detected below
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+6
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+------------------------------------------------
+Test 9 : Insert, Insert-Update-Delete conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Insert row on Primary Master
+insert into test.t1 values (4, "Haymarket");
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Outhouse");
+-- Update row on Secondary Master
+update test.t1 set b="Mathers" where a = 4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Examine data (none) on Secondary Master
+select * from test.t1 order by a;
+a b
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Haymarket
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+9
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master (none)
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master's slave
+start slave;
+-- Check data on Secondary Master, should be same as Primary Master
+select * from test.t1;
+a b
+4 Haymarket
+------------------------------------------------
+Test 10 : Update, Delete-Insert-Update conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Blind poet" where a=4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Drouthy Neebors");
+-- Update row on Secondary Master
+update test.t1 set b="The Tankard" where a=4;
+-- Check data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on Secondary Master, as set
+select * from test.t1 order by a;
+a b
+4 The Tankard
+-- Restart Secondary Master slave
+start slave;
+-- Check data on Secondary Master - should be as Primary
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+drop table test.t1;
+drop table test.t2;
+drop table test.t1$EX;
+Populate ndb_replication table as necessary
+-- 31 extra gci bits
+replace into mysql.ndb_replication values
+("test", "t1", 3, 7, NULL),
+("test", "t1", 1, 7, "NDB$EPOCH(31)");
+create table `test`.`t1$EX`
+ (server_id int unsigned,
+master_server_id int unsigned,
+master_epoch bigint unsigned,
+count int unsigned,
+a int not null,
+d int,
+primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+Create table
+create table test.t1(a int primary key, b varchar(255)) engine = ndb;
+Create other table
+create table test.t2(a int primary key, b int) engine = ndb;
+----------------------------------
+Test 1 : Basic two-way replication
+----------------------------------
+insert into test.t1 values (1, "Metropole");
+-- Give time for a new epoch on the Master
+-- Insert something to ensure the new epoch is noticed
+replace into test.t2 values (2, 1);
+-- Flushed to slave
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Flushed back to Master
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Now update data on slave
+update test.t1 set b="Favorit" where a=1;
+-- Now check data on master
+select * from test.t1 order by a;
+a b
+1 Favorit
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Now perform multiple consecutive updates on the slave
+update test.t1 set b="Elephant house" where a=1;
+update test.t1 set b="Beach house" where a=1;
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Now check they've applied on the master
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+--------------------------------------------
+Test 2 : Normal Insert from Secondary Master
+--------------------------------------------
+-- Insert a new row on the Slave
+insert into test.t1 values (2, "Forrest");
+-- Check it exists on the Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Forrest
+-- Update from the slave
+update test.t1 set b="Reds" where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Reds
+delete from test.t1 where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-------------------------------
+Test 3 : Insert-Insert conflict
+-------------------------------
+stop slave;
+-- Insert a row on the Primary Master
+insert into test.t1 values (2, "Loopy Lornas");
+-- Insert a row on the secondary Master
+insert into test.t1 values (2, "Cloisters");
+-- Examine data on Primary Master (should be unaffected)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-- Examine conflict indicators on Primary Master
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on isolated secondary Master (should be as-set)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Cloisters
+-- Restart secondary Masters slave
+start slave;
+-- Reexamine secondary Master's data (should be same as Primary Masters)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-------------------------------
+Test 4 : Update-Update conflict
+-------------------------------
+-- Stop replication to secondary master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Peters Yard" where a=2;
+-- Show data on Primary Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Update row on Secondary Master
+update test.t1 set b="Toast" where a=2;
+-- Examine data on Primary Master - should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+2
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on secondary - should be as set
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Toast
+-- Now restart slave, will re-align row
+start slave;
+-- Check that Secondary is re-aligned
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+-------------------------------
+Test 5 : Update-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Update on Primary Master
+update test.t1 set b="Pear tree" where a = 2;
+-- Delete on Secondary Master
+delete from test.t1 where a = 2;
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+3
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, still missing
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+-------------------------------
+Test 6 : Delete-Update conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=2;
+-- Update on Secondary Master
+update test.t1 set b="Black pig" where a=2;
+-- Examine data on Primary Master, should be unaffected (no row)
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+4
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, should be as inserted
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Black pig
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master (deleted)
+select * from test.t1 order by a;
+a b
+1 Beach house
+-------------------------------
+Test 7 : Delete-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=1;
+-- Delete on Secondary Master
+delete from test.t1 where a=1;
+-- Examine data on Primary Master, no row
+select * from test.t1 order by a;
+a b
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+5
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, no row
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, no row
+select * from test.t1 order by a;
+a b
+------------------------------------------------
+Test 8 : Delete-Delete, Insert conflict exposure
+------------------------------------------------
+-- Insert a row on Secondary Master
+insert into test.t1 values (3, "Espy");
+-- Check it's present on Primary Master
+select * from test.t1 order by a;
+a b
+3 Espy
+-- Stop replication in both directions
+stop slave;
+stop slave;
+-- Delete row from both clusters
+delete from test.t1 where a=3;
+delete from test.t1 where a=3;
+-- Follow up with Insert from Secondary master
+insert into test.t1 values (3, "Dalriada");
+-- Restart replication in both directions
+start slave;
+start slave;
+-- Check data on both sites - diverged
+-- Secondary master :
+select * from test.t1 order by a;
+a b
+-- Primary master :
+select * from test.t1 order by a;
+a b
+3 Dalriada
+--Remove extra row
+delete from test.t1 where a=3;
+-- Note that Delete-Delete conflict detected below
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+6
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+------------------------------------------------
+Test 9 : Insert, Insert-Update-Delete conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Insert row on Primary Master
+insert into test.t1 values (4, "Haymarket");
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Outhouse");
+-- Update row on Secondary Master
+update test.t1 set b="Mathers" where a = 4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Examine data (none) on Secondary Master
+select * from test.t1 order by a;
+a b
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Haymarket
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+9
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master (none)
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master's slave
+start slave;
+-- Check data on Secondary Master, should be same as Primary Master
+select * from test.t1;
+a b
+4 Haymarket
+------------------------------------------------
+Test 10 : Update, Delete-Insert-Update conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Blind poet" where a=4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Drouthy Neebors");
+-- Update row on Secondary Master
+update test.t1 set b="The Tankard" where a=4;
+-- Check data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on Secondary Master, as set
+select * from test.t1 order by a;
+a b
+4 The Tankard
+-- Restart Secondary Master slave
+start slave;
+-- Check data on Secondary Master - should be as Primary
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+drop table test.t1;
+drop table test.t2;
+drop table test.t1$EX;
+Populate ndb_replication table as necessary
+-- Default extra Gci bits
+replace into mysql.ndb_replication values
+("test", "t1", 3, 7, NULL),
+("test", "t1", 1, 7, "NDB$EPOCH()");
+create table `test`.`t1$EX`
+ (server_id int unsigned,
+master_server_id int unsigned,
+master_epoch bigint unsigned,
+count int unsigned,
+a int not null,
+d int,
+primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+Create table
+create table test.t1(a int primary key, b varchar(255)) engine = ndb;
+Create other table
+create table test.t2(a int primary key, b int) engine = ndb;
+----------------------------------
+Test 1 : Basic two-way replication
+----------------------------------
+insert into test.t1 values (1, "Metropole");
+-- Give time for a new epoch on the Master
+-- Insert something to ensure the new epoch is noticed
+replace into test.t2 values (2, 1);
+-- Flushed to slave
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Flushed back to Master
+select * from test.t1 order by a;
+a b
+1 Metropole
+-- Now update data on slave
+update test.t1 set b="Favorit" where a=1;
+-- Now check data on master
+select * from test.t1 order by a;
+a b
+1 Favorit
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Now perform multiple consecutive updates on the slave
+update test.t1 set b="Elephant house" where a=1;
+update test.t1 set b="Beach house" where a=1;
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Now check they've applied on the master
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+--------------------------------------------
+Test 2 : Normal Insert from Secondary Master
+--------------------------------------------
+-- Insert a new row on the Slave
+insert into test.t1 values (2, "Forrest");
+-- Check it exists on the Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Forrest
+-- Update from the slave
+update test.t1 set b="Reds" where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Reds
+delete from test.t1 where a=2;
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-------------------------------
+Test 3 : Insert-Insert conflict
+-------------------------------
+stop slave;
+-- Insert a row on the Primary Master
+insert into test.t1 values (2, "Loopy Lornas");
+-- Insert a row on the secondary Master
+insert into test.t1 values (2, "Cloisters");
+-- Examine data on Primary Master (should be unaffected)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-- Examine conflict indicators on Primary Master
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on isolated secondary Master (should be as-set)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Cloisters
+-- Restart secondary Masters slave
+start slave;
+-- Reexamine secondary Master's data (should be same as Primary Masters)
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Loopy Lornas
+-------------------------------
+Test 4 : Update-Update conflict
+-------------------------------
+-- Stop replication to secondary master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Peters Yard" where a=2;
+-- Show data on Primary Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+1
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Update row on Secondary Master
+update test.t1 set b="Toast" where a=2;
+-- Examine data on Primary Master - should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+2
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on secondary - should be as set
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Toast
+-- Now restart slave, will re-align row
+start slave;
+-- Check that Secondary is re-aligned
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Peters Yard
+-------------------------------
+Test 5 : Update-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Update on Primary Master
+update test.t1 set b="Pear tree" where a = 2;
+-- Delete on Secondary Master
+delete from test.t1 where a = 2;
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+3
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, still missing
+select * from test.t1 order by a;
+a b
+1 Beach house
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Pear tree
+-------------------------------
+Test 6 : Delete-Update conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=2;
+-- Update on Secondary Master
+update test.t1 set b="Black pig" where a=2;
+-- Examine data on Primary Master, should be unaffected (no row)
+select * from test.t1 order by a;
+a b
+1 Beach house
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+4
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, should be as inserted
+select * from test.t1 order by a;
+a b
+1 Beach house
+2 Black pig
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, aligned with Master (deleted)
+select * from test.t1 order by a;
+a b
+1 Beach house
+-------------------------------
+Test 7 : Delete-Delete conflict
+-------------------------------
+-- Stop Secondary slave
+stop slave;
+-- Delete on Primary Master
+delete from test.t1 where a=1;
+-- Delete on Secondary Master
+delete from test.t1 where a=1;
+-- Examine data on Primary Master, no row
+select * from test.t1 order by a;
+a b
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+5
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master before slave restart, no row
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master slave
+start slave;
+-- Examine data on Secondary Master after slave restart, no row
+select * from test.t1 order by a;
+a b
+------------------------------------------------
+Test 8 : Delete-Delete, Insert conflict exposure
+------------------------------------------------
+-- Insert a row on Secondary Master
+insert into test.t1 values (3, "Espy");
+-- Check it's present on Primary Master
+select * from test.t1 order by a;
+a b
+3 Espy
+-- Stop replication in both directions
+stop slave;
+stop slave;
+-- Delete row from both clusters
+delete from test.t1 where a=3;
+delete from test.t1 where a=3;
+-- Follow up with Insert from Secondary master
+insert into test.t1 values (3, "Dalriada");
+-- Restart replication in both directions
+start slave;
+start slave;
+-- Check data on both sites - diverged
+-- Secondary master :
+select * from test.t1 order by a;
+a b
+-- Primary master :
+select * from test.t1 order by a;
+a b
+3 Dalriada
+--Remove extra row
+delete from test.t1 where a=3;
+-- Note that Delete-Delete conflict detected below
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+6
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+------------------------------------------------
+Test 9 : Insert, Insert-Update-Delete conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Insert row on Primary Master
+insert into test.t1 values (4, "Haymarket");
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Outhouse");
+-- Update row on Secondary Master
+update test.t1 set b="Mathers" where a = 4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Examine data (none) on Secondary Master
+select * from test.t1 order by a;
+a b
+-- Examine data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Haymarket
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+9
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Examine data on Secondary Master (none)
+select * from test.t1 order by a;
+a b
+-- Restart Secondary Master's slave
+start slave;
+-- Check data on Secondary Master, should be same as Primary Master
+select * from test.t1;
+a b
+4 Haymarket
+------------------------------------------------
+Test 10 : Update, Delete-Insert-Update conflict
+------------------------------------------------
+-- Stop replication on Secondary Master
+stop slave;
+-- Update row on Primary Master
+update test.t1 set b="Blind poet" where a=4;
+-- Delete row on Secondary Master
+delete from test.t1 where a=4;
+-- Insert row on Secondary Master
+insert into test.t1 values (4, "Drouthy Neebors");
+-- Update row on Secondary Master
+update test.t1 set b="The Tankard" where a=4;
+-- Check data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+-- Check data on Secondary Master, as set
+select * from test.t1 order by a;
+a b
+4 The Tankard
+-- Restart Secondary Master slave
+start slave;
+-- Check data on Secondary Master - should be as Primary
+select * from test.t1 order by a;
+a b
+4 Blind poet
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
+VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+12
+SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+1 3 # 1 # #
+1 3 # 2 # #
+1 3 # 3 # #
+1 3 # 4 # #
+1 3 # 5 # #
+1 3 # 6 # #
+1 3 # 7 # #
+1 3 # 8 # #
+1 3 # 9 # #
+1 3 # 10 # #
+1 3 # 11 # #
+1 3 # 12 # #
+SELECT * FROM `t1$EX` ORDER BY a, d;
+server_id master_server_id master_epoch count a d
+1 3 # # 1 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 2 NULL
+1 3 # # 3 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+1 3 # # 4 NULL
+SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
+SELECT * FROM `t2$EX` ORDER BY a, d;
+drop table test.t1;
+drop table test.t2;
+drop table test.t1$EX;
+delete from mysql.ndb_replication;
+insert into mysql.ndb_replication values
+("test", "t3", 0, 7, "NDB\$EPOCH(32)"),
+("test", "t4", 0, 7, "NDB\$EPOCH(-1)");
+create table test.t3 (a int primary key) engine=ndb;
+ERROR HY000: Can't create table 'test.t3' (errno: 1626)
+show warnings;
+Level Code Message
+Error 1627 Error in parsing conflict function. Message: NDB$EPOCH(32), Too many extra Gci bits at ')'
+Error 1005 Can't create table 'test.t3' (errno: 1626)
+create table test.t4 (a int primary key) engine=ndb;
+ERROR HY000: Can't create table 'test.t4' (errno: 1626)
+show warnings;
+Level Code Message
+Error 1627 Error in parsing conflict function. Message: NDB$EPOCH(-1), Too many extra Gci bits at ')'
+Error 1005 Can't create table 'test.t4' (errno: 1626)
+drop table mysql.ndb_replication;
=== modified file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max.result 2010-01-27 09:29:10 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max.result 2010-09-22 10:49:11 +0000
@@ -45,6 +45,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -71,6 +77,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -91,6 +103,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -118,6 +136,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -166,10 +190,22 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check update some data that causes conflicts
@@ -202,10 +238,22 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check higer timestamp
@@ -263,6 +311,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -289,6 +343,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -309,6 +369,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -336,6 +402,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -384,10 +456,22 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check update some data that causes conflicts
@@ -420,10 +504,22 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check higer timestamp
@@ -477,10 +573,16 @@ a b c d
3 Master t2 c=2 2 123
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-0
+3
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-3
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -509,10 +611,16 @@ a b c d
3 Master t2 a=3 at c=3 3 123
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-0
+4
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-4
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -537,10 +645,16 @@ select * from t2 order by a, d;
a b c d
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-0
+4
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-4
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -576,6 +690,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -620,15 +740,21 @@ commit;
*** slave - check conflict info, there should be some
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-0
+3
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-3
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
-2 1 # 1 # #
-2 1 # 2 # #
-2 1 # 3 # #
+2 1 # 5 # #
+2 1 # 6 # #
+2 1 # 7 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
2 1 # # 1 111
@@ -662,18 +788,24 @@ commit;
*** slave - check conflict info, change depends on calling test
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-0
+6
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-6
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
-2 1 # 1 # #
-2 1 # 2 # #
-2 1 # 3 # #
-2 1 # 4 # #
2 1 # 5 # #
2 1 # 6 # #
+2 1 # 7 # #
+2 1 # 8 # #
+2 1 # 9 # #
+2 1 # 10 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
2 1 # # 1 111
@@ -737,6 +869,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -763,6 +901,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -783,6 +927,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -810,6 +960,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -854,15 +1010,27 @@ commit;
*** slave - check conflict info, there should be some
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+4
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-1
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
-2 1 # -9 # #
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
+2 1 # 4 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
2 1 # # 4 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
@@ -893,15 +1061,27 @@ commit;
*** slave - check conflict info, change depends on calling test
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+4
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
-1
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
-2 1 # -9 # #
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
+2 1 # 4 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
2 1 # # 4 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
=== modified file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max_delete_win.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max_delete_win.result 2010-01-27 09:29:10 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_max_delete_win.result 2010-09-22 10:49:11 +0000
@@ -45,6 +45,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -71,6 +77,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -91,6 +103,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -118,6 +136,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -162,14 +186,26 @@ commit;
*** slave - check conflict info, there should be some
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check update some data that causes conflicts
@@ -198,14 +234,26 @@ commit;
*** slave - check conflict info, change depends on calling test
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check higer timestamp
@@ -263,6 +311,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -289,6 +343,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -309,6 +369,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -336,6 +402,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -380,14 +452,26 @@ commit;
*** slave - check conflict info, there should be some
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check update some data that causes conflicts
@@ -416,14 +500,26 @@ commit;
*** slave - check conflict info, change depends on calling test
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check higer timestamp
@@ -480,7 +576,13 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -512,7 +614,13 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
4
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -540,7 +648,13 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
4
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -576,6 +690,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -623,12 +743,18 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
-2 1 # 1 # #
-2 1 # 2 # #
-2 1 # 3 # #
+2 1 # 5 # #
+2 1 # 6 # #
+2 1 # 7 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
2 1 # # 1 111
@@ -665,15 +791,21 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
6
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
-2 1 # 1 # #
-2 1 # 2 # #
-2 1 # 3 # #
-2 1 # 4 # #
2 1 # 5 # #
2 1 # 6 # #
+2 1 # 7 # #
+2 1 # 8 # #
+2 1 # 9 # #
+2 1 # 10 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
2 1 # # 1 111
@@ -737,6 +869,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -763,6 +901,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -783,6 +927,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -810,6 +960,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -854,14 +1010,26 @@ commit;
*** slave - check conflict info, there should be some
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check update some data that causes conflicts
@@ -890,14 +1058,26 @@ commit;
*** slave - check conflict info, change depends on calling test
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX";
VARIABLE_VALUE-@init_ndb_conflict_fn_max
-3
+0
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
+2 1 # 1 # #
+2 1 # 2 # #
+2 1 # 3 # #
SELECT * FROM `t1$EX` ORDER BY a, d;
server_id master_server_id master_epoch count a d
+2 1 # # 1 111
+2 1 # # 2 111222
+2 1 # # 3 111222333
SELECT * FROM `t2$EX` ORDER BY server_id, master_server_id, master_epoch, count;
SELECT * FROM `t2$EX` ORDER BY a, d;
*** slave - check higer timestamp
=== modified file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_old.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_old.result 2010-01-27 09:29:10 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_conflict_old.result 2010-09-22 10:49:11 +0000
@@ -45,6 +45,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -71,6 +77,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -91,6 +103,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -118,6 +136,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -166,6 +190,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -208,6 +238,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
5
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # 1 # #
@@ -279,6 +315,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -305,6 +347,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -325,6 +373,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -352,6 +406,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -400,6 +460,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -4 # #
@@ -442,6 +508,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
5
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -4 # #
@@ -513,6 +585,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -9 # #
@@ -545,6 +623,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
4
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -9 # #
@@ -573,6 +657,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
4
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -9 # #
@@ -608,6 +698,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -656,6 +752,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
3
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -9 # #
@@ -698,6 +800,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
6
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -9 # #
@@ -769,6 +877,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -795,6 +909,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -815,6 +935,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -842,6 +968,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
SELECT * FROM `t1$EX` ORDER BY a, d;
@@ -890,6 +1022,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
4
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -19 # #
@@ -935,6 +1073,12 @@ VARIABLE_VALUE-@init_ndb_conflict_fn_max
SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_old FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_OLD";
VARIABLE_VALUE-@init_ndb_conflict_fn_old
6
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_MAX_DEL_WIN";
+VARIABLE_VALUE-@init_ndb_conflict_fn_max_del_win
+0
+SELECT VARIABLE_VALUE-@init_ndb_conflict_fn_epoch FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE "NDB_CONFLICT_FN_EPOCH";
+VARIABLE_VALUE-@init_ndb_conflict_fn_epoch
+0
SELECT server_id, master_server_id, master_epoch, count-@init_ndb_conflict_fn_old, a, d FROM `t1$EX` ORDER BY server_id, master_server_id, master_epoch, count;
server_id master_server_id master_epoch count-@init_ndb_conflict_fn_old a d
2 1 # -19 # #
=== added file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_init_rep_status.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_init_rep_status.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_init_rep_status.result 2010-09-22 10:49:11 +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;
+reset master;
+stop slave;
+Generate something in the Masters Binlog
+use test;
+create table t1 (a int primary key, b int) engine=ndb;
+insert into t1 values (1,1);
+Initial state
+select * from mysql.ndb_apply_status;
+server_id epoch log_name start_pos end_pos
+show variables like 'Ndb_cluster_server_ids';
+Variable_name Value
+ndb_cluster_server_ids
+select variable_value from information_schema.global_status
+where variable_name like '%Ndb_slave_max_replicated_epoch%';
+variable_value
+0
+select @slave_server_id:=(variable_value+0) from information_schema.global_variables
+where variable_name like 'server_id';
+@slave_server_id:=(variable_value+0)
+2
+Default, no data, max replicated epoch will be 0.
+reset slave;
+start slave;
+select server_id from mysql.ndb_apply_status order by server_id;
+server_id
+1
+select variable_value from information_schema.global_status
+where variable_name like 'Ndb_slave_max_replicated_epoch';
+variable_value
+0
+Default, load of own serverid from ndb_apply_status, should be 111
+drop table test.t1;
+stop slave;
+reset slave;
+insert into mysql.ndb_apply_status values (@slave_server_id, 111, 'Fictional log', 222, 333);
+start slave;
+select server_id from mysql.ndb_apply_status order by server_id;
+server_id
+1
+2
+select variable_value from information_schema.global_status
+where variable_name like 'Ndb_slave_max_replicated_epoch';
+variable_value
+111
+drop table test.t1;
+Check that reset slave resets Ndb_slave_max_replicated_epoch
+stop slave;
+select variable_value from information_schema.global_status
+where variable_name like 'Ndb_slave_max_replicated_epoch';
+variable_value
+111
+reset slave;
+select variable_value from information_schema.global_status
+where variable_name like 'Ndb_slave_max_replicated_epoch';
+variable_value
+0
+Multiple-channel, load highest of configured serverids, should be 222
+set @other_local_server_id=@slave_server_id+1;
+set @other_remote_server_id=@slave_server_id+2;
+insert into mysql.ndb_apply_status values (@slave_server_id, 111, 'Fictional log', 222, 333);
+insert into mysql.ndb_apply_status values (@other_local_server_id, 222, 'Fictional log', 222, 333);
+insert into mysql.ndb_apply_status values (@other_remote_server_id, 111, 'Fictional log', 222, 333);
+set global ndb_cluster_server_ids=concat_ws(',', @slave_server_id, @other_local_server_id);
+show variables like 'ndb_cluster_server_ids';
+Variable_name Value
+ndb_cluster_server_ids 2,3
+start slave;
+select server_id from mysql.ndb_apply_status order by server_id;
+server_id
+1
+2
+3
+4
+select variable_value from information_schema.global_status
+where variable_name like 'Ndb_slave_max_replicated_epoch';
+variable_value
+222
+set global ndb_cluster_server_ids='';
+drop table test.t1;
=== modified file 'mysql-test/suite/rpl_ndb/r/rpl_ndb_rep_error.result'
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_rep_error.result 2009-09-24 11:05:08 +0000
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_rep_error.result 2010-09-22 10:49:11 +0000
@@ -10,9 +10,7 @@ Error 1626 Bad schema for mysql.ndb_repl
drop table t1;
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$X(X)");
create table t1 (a int key, X int) engine ndb;
-Warnings:
-Error 1627 Error in parsing conflict function. Message: NDB$X(X), unknown conflict resolution function at 'NDB$X(X)'
-drop table t1;
+ERROR HY000: Can't create table 'test.t1' (errno: 1626)
delete from mysql.ndb_replication;
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX(X)");
create table t1 (a int key, X int) engine ndb;
@@ -22,13 +20,9 @@ drop table t1;
delete from mysql.ndb_replication;
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX()");
create table t1 (a int key, X int) engine ndb;
-Warnings:
-Error 1627 Error in parsing conflict function. Message: NDB$MAX(), missing function argument at ')'
-drop table t1;
+ERROR HY000: Can't create table 'test.t1' (errno: 1626)
delete from mysql.ndb_replication;
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX(X Y)");
create table t1 (a int key, X int) engine ndb;
-Warnings:
-Error 1627 Error in parsing conflict function. Message: NDB$MAX(X Y), missing ')' at 'Y)'
-drop table t1;
+ERROR HY000: Can't create table 'test.t1' (errno: 1626)
delete from mysql.ndb_replication;
=== 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-09-22 10:49:11 +0000
@@ -0,0 +1,124 @@
+!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.cluster1]
+
+[mysqld.1.cluster2]
+
+# Append <testname>-slave.opt file to the list of argument used when
+# starting the mysqld
+#!use-slave-opt
+
+# 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-09-22 10:49:11 +0000
@@ -0,0 +1,113 @@
+--source include/have_ndb.inc
+--source include/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;
+
+--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 2009-12-17 10:14:52 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test 2010-09-22 10:49:11 +0000
@@ -74,3 +74,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 File, 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 File, 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;
=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.cnf'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.cnf 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.cnf 2010-09-22 10:49:11 +0000
@@ -0,0 +1,40 @@
+!include ../my.cnf
+
+# 2 clusters, each with 2 MySQLDs
+# All MySQLDs log-slave-updates
+# Potential infinite loops are broken by both servers
+# on each cluster having the same server-id
+
+[mysqld]
+log-slave-updates
+ndb-log-apply-status
+
+[mysqld.1.1]
+server-id= 1
+log-bin = pref-master-1
+
+[mysqld.2.1]
+server-id= 2
+log-bin = pref-master-2
+
+[mysqld.1.slave]
+server-id= 3
+log-bin = sec-master-1
+skip-slave-start
+
+[mysqld.2.slave]
+server-id= 4
+log-bin = sec-master-2
+master-host= 127.0.0.1
+master-port= @mysqld.2.1.port
+master-password= @mysqld.2.1.#password
+master-user= @mysqld.2.1.#user
+master-connect-retry= 1
+init-rpl-role= slave
+skip-slave-start
+ndb_connectstring= @mysql_cluster.slave.ndb_connectstring
+
+[ENV]
+
+SLAVE_MYPORT1= @mysqld.2.slave.port
+SLAVE_MYSOCK1= @mysqld.2.slave.socket
=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.test'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch.test 2010-09-22 10:49:11 +0000
@@ -0,0 +1,94 @@
+#
+# Test engine native conflict resolution for ndb
+# NDB$EPOCH() function
+#
+#
+--source include/have_ndb.inc
+--source include/have_binlog_format_mixed_or_row.inc
+--source include/ndb_master-slave.inc
+
+--echo Setup circular replication
+
+--connection slave
+RESET MASTER;
+select @slave_server_id:=(variable_value+0)
+ from information_schema.global_variables
+ where variable_name like 'server_id';
+let $SLAVE_SERVER_ID= query_get_value('select @slave_server_id as v',v,1);
+
+--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"
+START SLAVE;
+select @master_server_id:=(variable_value+0)
+ from information_schema.global_variables
+ where variable_name like 'server_id';
+let $MASTER_SERVER_ID= query_get_value('select @master_server_id as v',v,1);
+
+--echo Setup ndb_replication and t1$EX exceptions table
+
+--disable_warnings
+--disable_query_log
+--connection master
+drop table if exists mysql.ndb_replication;
+CREATE TABLE mysql.ndb_replication
+ (db VARBINARY(63),
+ table_name VARBINARY(63),
+ server_id INT UNSIGNED,
+ binlog_type INT UNSIGNED,
+ conflict_fn VARBINARY(128),
+ PRIMARY KEY USING HASH (db,table_name,server_id))
+ ENGINE=NDB PARTITION BY KEY(db,table_name);
+--enable_warnings
+--enable_query_log
+
+--echo Populate ndb_replication table as necessary
+--echo -- 0 extra gci bits
+eval replace into mysql.ndb_replication values
+ ("test", "t1", $SLAVE_SERVER_ID, 7, NULL),
+ ("test", "t1", $MASTER_SERVER_ID, 7, "NDB\$EPOCH(0)");
+
+--source suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc
+
+--echo Populate ndb_replication table as necessary
+--echo -- 1 extra gci bits
+eval replace into mysql.ndb_replication values
+ ("test", "t1", $SLAVE_SERVER_ID, 7, NULL),
+ ("test", "t1", $MASTER_SERVER_ID, 7, "NDB\$EPOCH(1)");
+
+--source suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc
+
+--echo Populate ndb_replication table as necessary
+--echo -- 31 extra gci bits
+eval replace into mysql.ndb_replication values
+ ("test", "t1", $SLAVE_SERVER_ID, 7, NULL),
+ ("test", "t1", $MASTER_SERVER_ID, 7, "NDB\$EPOCH(31)");
+
+--source suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc
+
+--echo Populate ndb_replication table as necessary
+--echo -- Default extra Gci bits
+eval replace into mysql.ndb_replication values
+ ("test", "t1", $SLAVE_SERVER_ID, 7, NULL),
+ ("test", "t1", $MASTER_SERVER_ID, 7, "NDB\$EPOCH()");
+
+--source suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc
+
+delete from mysql.ndb_replication;
+insert into mysql.ndb_replication values
+ ("test", "t3", 0, 7, "NDB\$EPOCH(32)"),
+ ("test", "t4", 0, 7, "NDB\$EPOCH(-1)");
+
+--error 1005
+create table test.t3 (a int primary key) engine=ndb;
+show warnings;
+
+--error 1005
+create table test.t4 (a int primary key) engine=ndb;
+show warnings;
+
+--connection master
+drop table mysql.ndb_replication;
+
+--sync_slave_with_master slave
+
=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_conflict_epoch_1.inc 2010-09-22 10:49:11 +0000
@@ -0,0 +1,472 @@
+#
+# Include file for testing ndb$epoch conflict function
+#
+#
+
+create table `test`.`t1$EX`
+ (server_id int unsigned,
+ master_server_id int unsigned,
+ master_epoch bigint unsigned,
+ count int unsigned,
+ a int not null,
+ d int,
+ primary key(server_id, master_server_id, master_epoch, count)) engine ndb;
+
+
+--echo Create table
+create table test.t1(a int primary key, b varchar(255)) engine = ndb;
+
+--echo Create other table
+create table test.t2(a int primary key, b int) engine = ndb;
+
+--source include/ndb_conflict_info_init.inc
+
+--echo ----------------------------------
+--echo Test 1 : Basic two-way replication
+--echo ----------------------------------
+
+insert into test.t1 values (1, "Metropole");
+
+--echo -- Give time for a new epoch on the Master
+# This is 3 seconds to be > GCP_Save time, so that the next epoch
+# will be visibly greater than the one inserted above
+# (e.g. if we have 4 bits of extra GCI resolution, the max
+# representable GCI is XXX/15. If we insert at XXX/16, we
+# need to wait until we get to XXX+1/0 at least, to avoid
+# the Primary Master undoing the update)
+#
+--sleep 3
+
+--echo -- Insert something to ensure the new epoch is noticed
+#
+# Required in case our initial insert's epoch gets rounded up to
+# 0xffffffff, in which case 'later' updates from the slave will
+# be in conflict until some newer gci_hi is the MaxReplicatedEpoch
+#
+replace into test.t2 values (2, 1);
+--sync_slave_with_master slave
+--connection slave
+--echo -- Flushed to slave
+select * from test.t1 order by a;
+--sync_slave_with_master master
+--connection master
+--echo -- Flushed back to Master
+select * from test.t1 order by a;
+--connection slave
+
+--echo -- Now update data on slave
+update test.t1 set b="Favorit" where a=1;
+
+--sync_slave_with_master master
+
+--connection master
+--echo -- Now check data on master
+select * from test.t1 order by a;
+
+--source include/ndb_conflict_info.inc
+
+--connection slave
+--echo -- Now perform multiple consecutive updates on the slave
+
+update test.t1 set b="Elephant house" where a=1;
+update test.t1 set b="Beach house" where a=1;
+
+select * from test.t1 order by a;
+
+--sync_slave_with_master master
+--connection master
+--echo -- Now check they've applied on the master
+select * from test.t1 order by a;
+
+--source include/ndb_conflict_info.inc
+
+--echo --------------------------------------------
+--echo Test 2 : Normal Insert from Secondary Master
+--echo --------------------------------------------
+
+--connection slave
+--echo -- Insert a new row on the Slave
+insert into test.t1 values (2, "Forrest");
+
+--sync_slave_with_master master
+--connection master
+--echo -- Check it exists on the Master
+select * from test.t1 order by a;
+
+--connection slave
+--echo -- Update from the slave
+update test.t1 set b="Reds" where a=2;
+
+--sync_slave_with_master master
+--connection master
+select * from test.t1 order by a;
+
+--connection slave
+delete from test.t1 where a=2;
+
+--sync_slave_with_master master
+--connection master
+select * from test.t1 order by a;
+
+--source include/ndb_conflict_info.inc
+
+--echo -------------------------------
+--echo Test 3 : Insert-Insert conflict
+--echo -------------------------------
+
+--connection slave
+stop slave;
+--connection master
+
+--echo -- Insert a row on the Primary Master
+insert into test.t1 values (2, "Loopy Lornas");
+
+--connection slave
+--echo -- Insert a row on the secondary Master
+insert into test.t1 values (2, "Cloisters");
+
+--sync_slave_with_master master
+--connection master
+--echo -- Examine data on Primary Master (should be unaffected)
+select * from test.t1 order by a;
+
+--echo -- Examine conflict indicators on Primary Master
+--source include/ndb_conflict_info.inc
+
+--echo -- Examine data on isolated secondary Master (should be as-set)
+--connection slave
+select * from test.t1 order by a;
+
+--echo -- Restart secondary Masters slave
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+--connection slave
+
+--echo -- Reexamine secondary Master's data (should be same as Primary Masters)
+select * from test.t1 order by a;
+
+--echo -------------------------------
+--echo Test 4 : Update-Update conflict
+--echo -------------------------------
+
+--connection slave
+--echo -- Stop replication to secondary master
+stop slave;
+
+--connection master
+--echo -- Update row on Primary Master
+
+update test.t1 set b="Peters Yard" where a=2;
+
+--echo -- Show data on Primary Master
+
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--connection slave
+
+--echo -- Update row on Secondary Master
+update test.t1 set b="Toast" where a=2;
+
+--sync_slave_with_master master
+
+--echo -- Examine data on Primary Master - should be unaffected
+
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--connection slave
+--echo -- Check data on secondary - should be as set
+
+select * from test.t1 order by a;
+
+--echo -- Now restart slave, will re-align row
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+
+--connection slave
+--echo -- Check that Secondary is re-aligned
+
+select * from test.t1 order by a;
+
+
+--echo -------------------------------
+--echo Test 5 : Update-Delete conflict
+--echo -------------------------------
+
+--connection slave
+--echo -- Stop Secondary slave
+stop slave;
+
+--connection master
+--echo -- Update on Primary Master
+
+update test.t1 set b="Pear tree" where a = 2;
+
+--connection slave
+--echo -- Delete on Secondary Master
+
+delete from test.t1 where a = 2;
+
+--sync_slave_with_master master
+
+--echo -- Examine data on Primary Master, should be unaffected
+
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--echo -- Examine data on Secondary Master before slave restart, still missing
+--connection slave
+select * from test.t1 order by a;
+
+--echo -- Restart Secondary Master slave
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+--connection slave
+
+--echo -- Examine data on Secondary Master after slave restart, aligned with Master
+select * from test.t1 order by a;
+
+--echo -------------------------------
+--echo Test 6 : Delete-Update conflict
+--echo -------------------------------
+
+--connection slave
+--echo -- Stop Secondary slave
+stop slave;
+
+--connection master
+--echo -- Delete on Primary Master
+
+delete from test.t1 where a=2;
+
+--connection slave
+--echo -- Update on Secondary Master
+
+update test.t1 set b="Black pig" where a=2;
+
+--sync_slave_with_master master
+
+--echo -- Examine data on Primary Master, should be unaffected (no row)
+
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--echo -- Examine data on Secondary Master before slave restart, should be as inserted
+--connection slave
+select * from test.t1 order by a;
+
+--echo -- Restart Secondary Master slave
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+--connection slave
+
+--echo -- Examine data on Secondary Master after slave restart, aligned with Master (deleted)
+select * from test.t1 order by a;
+
+--echo -------------------------------
+--echo Test 7 : Delete-Delete conflict
+--echo -------------------------------
+
+--connection slave
+--echo -- Stop Secondary slave
+stop slave;
+
+--connection master
+--echo -- Delete on Primary Master
+
+delete from test.t1 where a=1;
+
+--connection slave
+--echo -- Delete on Secondary Master
+
+delete from test.t1 where a=1;
+
+--sync_slave_with_master master
+
+--echo -- Examine data on Primary Master, no row
+
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--echo -- Examine data on Secondary Master before slave restart, no row
+--connection slave
+select * from test.t1 order by a;
+
+--echo -- Restart Secondary Master slave
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+--connection slave
+
+--echo -- Examine data on Secondary Master after slave restart, no row
+select * from test.t1 order by a;
+
+
+--echo ------------------------------------------------
+--echo Test 8 : Delete-Delete, Insert conflict exposure
+--echo ------------------------------------------------
+# This occurs as the Primary Master's Delete is still
+# in-flight when the Secondary Master's Insert arrives,
+# but as there is no knowledge of this at the Primary
+# Master, it accepts the Insert.
+#
+
+--connection slave
+--echo -- Insert a row on Secondary Master
+insert into test.t1 values (3, "Espy");
+--sync_slave_with_master master
+
+--connection master
+--echo -- Check it's present on Primary Master
+select * from test.t1 order by a;
+
+--echo -- Stop replication in both directions
+stop slave;
+
+--connection slave
+stop slave;
+
+--echo -- Delete row from both clusters
+delete from test.t1 where a=3;
+
+--connection master
+delete from test.t1 where a=3;
+
+--echo -- Follow up with Insert from Secondary master
+--connection slave
+
+insert into test.t1 values (3, "Dalriada");
+
+--echo -- Restart replication in both directions
+start slave;
+
+--connection master
+start slave;
+
+--sync_slave_with_master slave
+--connection slave
+--sync_slave_with_master master
+
+--connection slave
+--echo -- Check data on both sites - diverged
+--echo -- Secondary master :
+select * from test.t1 order by a;
+--echo -- Primary master :
+--connection master
+select * from test.t1 order by a;
+
+--echo --Remove extra row
+delete from test.t1 where a=3;
+
+--echo -- Note that Delete-Delete conflict detected below
+--source include/ndb_conflict_info.inc
+
+--echo ------------------------------------------------
+--echo Test 9 : Insert, Insert-Update-Delete conflict
+--echo ------------------------------------------------
+
+--connection slave
+--echo -- Stop replication on Secondary Master
+stop slave;
+
+--connection master
+--echo -- Insert row on Primary Master
+insert into test.t1 values (4, "Haymarket");
+
+--connection slave
+--echo -- Insert row on Secondary Master
+insert into test.t1 values (4, "Outhouse");
+--echo -- Update row on Secondary Master
+update test.t1 set b="Mathers" where a = 4;
+--echo -- Delete row on Secondary Master
+delete from test.t1 where a=4;
+
+--echo -- Examine data (none) on Secondary Master
+select * from test.t1 order by a;
+
+--sync_slave_with_master master
+--connection master
+--echo -- Examine data on Primary Master, should be unaffected
+
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--connection slave
+--echo -- Examine data on Secondary Master (none)
+select * from test.t1 order by a;
+
+--echo -- Restart Secondary Master's slave
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+--connection slave
+--echo -- Check data on Secondary Master, should be same as Primary Master
+select * from test.t1;
+
+--echo ------------------------------------------------
+--echo Test 10 : Update, Delete-Insert-Update conflict
+--echo ------------------------------------------------
+--connection slave
+--echo -- Stop replication on Secondary Master
+stop slave;
+
+--connection master
+--echo -- Update row on Primary Master
+update test.t1 set b="Blind poet" where a=4;
+
+--connection slave
+--echo -- Delete row on Secondary Master
+delete from test.t1 where a=4;
+
+--echo -- Insert row on Secondary Master
+insert into test.t1 values (4, "Drouthy Neebors");
+
+--echo -- Update row on Secondary Master
+update test.t1 set b="The Tankard" where a=4;
+
+--sync_slave_with_master master
+
+--connection master
+
+--echo -- Check data on Primary Master, should be unaffected
+select * from test.t1 order by a;
+--source include/ndb_conflict_info.inc
+
+--connection slave
+--echo -- Check data on Secondary Master, as set
+
+select * from test.t1 order by a;
+
+--echo -- Restart Secondary Master slave
+start slave;
+
+--connection master
+--sync_slave_with_master slave
+--connection slave
+
+--echo -- Check data on Secondary Master - should be as Primary
+select * from test.t1 order by a;
+
+--sync_slave_with_master master
+
+--connection master
+--source include/ndb_conflict_info.inc
+
+drop table test.t1;
+drop table test.t2;
+drop table test.t1$EX;
+
+--sync_slave_with_master slave
+
+--connection master
\ No newline at end of file
=== added file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_init_rep_status.test'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_init_rep_status.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_init_rep_status.test 2010-09-22 10:49:11 +0000
@@ -0,0 +1,83 @@
+--source include/have_ndb.inc
+--source include/ndb_master-slave.inc
+
+# Test Slave initialisation of Ndb_slave_max_replicated_epoch status var
+
+--connection slave
+reset master;
+stop slave;
+
+--connection master
+--echo Generate something in the Masters Binlog
+use test;
+create table t1 (a int primary key, b int) engine=ndb;
+
+insert into t1 values (1,1);
+
+--connection slave
+--echo Initial state
+select * from mysql.ndb_apply_status;
+show variables like 'Ndb_cluster_server_ids';
+select variable_value from information_schema.global_status
+ where variable_name like '%Ndb_slave_max_replicated_epoch%';
+select @slave_server_id:=(variable_value+0) from information_schema.global_variables
+ where variable_name like 'server_id';
+
+--echo Default, no data, max replicated epoch will be 0.
+reset slave;
+start slave;
+--connection master
+--sync_slave_with_master
+--connection slave
+--replace_column 3 # 4 # 5 #
+select server_id from mysql.ndb_apply_status order by server_id;
+select variable_value from information_schema.global_status
+ where variable_name like 'Ndb_slave_max_replicated_epoch';
+
+--echo Default, load of own serverid from ndb_apply_status, should be 111
+drop table test.t1;
+stop slave;
+reset slave;
+insert into mysql.ndb_apply_status values (@slave_server_id, 111, 'Fictional log', 222, 333);
+start slave;
+--connection master
+--sync_slave_with_master
+--connection slave
+--replace_column 3 # 4 # 5 #
+select server_id from mysql.ndb_apply_status order by server_id;
+select variable_value from information_schema.global_status
+ where variable_name like 'Ndb_slave_max_replicated_epoch';
+
+drop table test.t1;
+
+--echo Check that reset slave resets Ndb_slave_max_replicated_epoch
+stop slave;
+select variable_value from information_schema.global_status
+ where variable_name like 'Ndb_slave_max_replicated_epoch';
+reset slave;
+select variable_value from information_schema.global_status
+ where variable_name like 'Ndb_slave_max_replicated_epoch';
+
+--echo Multiple-channel, load highest of configured serverids, should be 222
+set @other_local_server_id=@slave_server_id+1;
+set @other_remote_server_id=@slave_server_id+2;
+insert into mysql.ndb_apply_status values (@slave_server_id, 111, 'Fictional log', 222, 333);
+insert into mysql.ndb_apply_status values (@other_local_server_id, 222, 'Fictional log', 222, 333);
+insert into mysql.ndb_apply_status values (@other_remote_server_id, 111, 'Fictional log', 222, 333);
+
+set global ndb_cluster_server_ids=concat_ws(',', @slave_server_id, @other_local_server_id);
+show variables like 'ndb_cluster_server_ids';
+start slave;
+--connection master
+--sync_slave_with_master
+--connection slave
+--replace_column 3 # 4 # 5 #
+select server_id from mysql.ndb_apply_status order by server_id;
+select variable_value from information_schema.global_status
+ where variable_name like 'Ndb_slave_max_replicated_epoch';
+
+# Clean up
+set global ndb_cluster_server_ids='';
+--connection master
+drop table test.t1;
+--sync_slave_with_master
=== modified file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_rep_error.test'
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_rep_error.test 2007-11-06 10:07:03 +0000
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_rep_error.test 2010-09-22 10:49:11 +0000
@@ -47,10 +47,10 @@ CREATE TABLE mysql.ndb_replication
--enable_query_log
# Non existant conflict_fn
-# gives warning when creating table
+# gives error when creating table
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$X(X)");
+--error 1005
create table t1 (a int key, X int) engine ndb;
-drop table t1;
delete from mysql.ndb_replication;
# Column type cannot be used for this function
@@ -61,17 +61,17 @@ drop table t1;
delete from mysql.ndb_replication;
# Too few arguments
-# gives warning when creating table
+# gives error when creating table
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX()");
+--error 1005
create table t1 (a int key, X int) engine ndb;
-drop table t1;
delete from mysql.ndb_replication;
# Too many arguments
-# gives warning when creating table
+# gives error when creating table
insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX(X Y)");
+--error 1005
create table t1 (a int key, X int) engine ndb;
-drop table t1;
delete from mysql.ndb_replication;
--disable_query_log
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2010-09-15 19:31:03 +0000
+++ b/sql/ha_ndbcluster.cc 2010-09-22 10:49:11 +0000
@@ -67,6 +67,13 @@ static uint opt_ndb_cluster_connection_p
static char* opt_ndb_connectstring;
static uint opt_ndb_nodeid;
extern ulong opt_server_id_mask;
+/* 256 nodes, 9 digits + a comma */
+const Uint32 MAX_DIGITS_PER_SERVERID = 10;
+const Uint32 MAX_SERVER_IDS_STR_LEN = MAX_API_NODES *
+ (MAX_DIGITS_PER_SERVERID + 1);
+char* opt_ndb_cluster_server_ids;
+Uint32 cluster_server_ids[ MAX_API_NODES ];
+Uint32 cluster_server_id_count;
static MYSQL_THDVAR_UINT(
autoincrement_prefetch_sz, /* name */
@@ -349,8 +356,9 @@ struct st_ndb_status {
};
static struct st_ndb_status g_ndb_status;
-static long g_ndb_status_conflict_fn_max= 0;
-static long g_ndb_status_conflict_fn_old= 0;
+static long g_ndb_status_conflict_fn[CFT_NUMBER_OF_CFTS] = {0,0,0};
+
+Uint64 g_ndb_status_max_rep_epoch= 0;
static int update_status_variables(Thd_ndb *thd_ndb,
st_ndb_status *ns,
@@ -408,8 +416,15 @@ SHOW_VAR ndb_status_variables_fixed[]= {
};
SHOW_VAR ndb_status_conflict_variables[]= {
- {"fn_max", (char*) &g_ndb_status_conflict_fn_max, SHOW_LONG},
- {"fn_old", (char*) &g_ndb_status_conflict_fn_old, SHOW_LONG},
+ {"fn_max", (char*) &g_ndb_status_conflict_fn[CFT_NDB_MAX], SHOW_LONG},
+ {"fn_old", (char*) &g_ndb_status_conflict_fn[CFT_NDB_OLD], SHOW_LONG},
+ {"fn_max_del_win", (char*) &g_ndb_status_conflict_fn[CFT_NDB_MAX_DEL_WIN], SHOW_LONG},
+ {"fn_epoch", (char*) &g_ndb_status_conflict_fn[CFT_NDB_EPOCH], SHOW_LONG},
+ {NullS, NullS, SHOW_LONG}
+};
+
+SHOW_VAR ndb_status_variables_slave[]= {
+ {"max_replicated_epoch", (char*) &g_ndb_status_max_rep_epoch, SHOW_LONGLONG},
{NullS, NullS, SHOW_LONG}
};
@@ -524,6 +539,18 @@ static int write_conflict_row(NDB_SHARE
}
#endif
+#ifdef HAVE_NDB_BINLOG
+int
+handle_row_conflict(enum_conflict_fn_type cft,
+ NDB_CONFLICT_FN_SHARE* cfn_share,
+ const NdbRecord* key_rec,
+ const uchar* pkRow,
+ enum_conflicting_op_type op_type,
+ enum_conflict_cause conflict_cause,
+ NdbTransaction* conflictTrans,
+ NdbError& err);
+#endif
+
inline int
check_completed_operations_pre_commit(Thd_ndb *thd_ndb, NdbTransaction *trans,
const NdbOperation *first,
@@ -536,7 +563,7 @@ check_completed_operations_pre_commit(Th
or exceptions to report
*/
#ifdef HAVE_NDB_BINLOG
- uint conflict_rows_written= 0;
+ uint conflict_operations_defined= 0;
#endif
while (first)
{
@@ -550,74 +577,185 @@ check_completed_operations_pre_commit(Th
{
#ifdef HAVE_NDB_BINLOG
DBUG_PRINT("info", ("ndb error: %d", err.code));
- if (err.code == (int) error_conflict_fn_max_violation)
- {
- DBUG_PRINT("info", ("err.code == (int) error_conflict_fn_max_violation"));
- thd_ndb->m_max_violation_count++;
- }
- else if (err.code == (int) error_conflict_fn_old_violation ||
- err.classification == NdbError::ConstraintViolation ||
- err.classification == NdbError::NoDataFound)
+ if ((err.code == (int) error_conflict_fn_violation) ||
+ (err.classification == NdbError::ConstraintViolation) ||
+ (err.classification == NdbError::NoDataFound))
{
DBUG_PRINT("info",
- ("err.code %s (int) error_conflict_fn_old_violation, "
- "err.classification %s",
- err.code == (int) error_conflict_fn_old_violation ? "==" : "!=",
- err.classification
- == NdbError::ConstraintViolation
- ? "== NdbError::ConstraintViolation"
- : (err.classification == NdbError::NoDataFound
- ? "== NdbError::NoDataFound" : "!=")));
- thd_ndb->m_old_violation_count++;
+ ("err.code %s (int) error_conflict_fn_violation, "
+ "err.classification %s",
+ err.code == (int) error_conflict_fn_violation ? "==" : "!=",
+ err.classification
+ == NdbError::ConstraintViolation
+ ? "== NdbError::ConstraintViolation"
+ : (err.classification == NdbError::NoDataFound
+ ? "== NdbError::NoDataFound" : "!=")));
+
+ enum_conflict_cause conflict_cause;
+
+ if (err.code == (int) error_conflict_fn_violation)
+ {
+ conflict_cause= ROW_IN_CONFLICT;
+ }
+ else if (err.classification == NdbError::ConstraintViolation)
+ {
+ conflict_cause= ROW_ALREADY_EXISTS;
+ }
+ else
+ {
+ assert(err.classification == NdbError::NoDataFound);
+ conflict_cause= ROW_DOES_NOT_EXIST;
+ }
+
const void* buffer= first->getCustomData();
if (buffer != NULL)
{
Ndb_exceptions_data ex_data;
memcpy(&ex_data, buffer, sizeof(ex_data));
NDB_SHARE *share= ex_data.share;
+ const NdbRecord* key_rec= ex_data.key_rec;
const uchar* row= ex_data.row;
+ enum_conflicting_op_type op_type = ex_data.op_type;
DBUG_ASSERT(share != NULL && row != NULL);
NDB_CONFLICT_FN_SHARE* cfn_share= share->m_cfn_share;
- if (cfn_share && cfn_share->m_ex_tab)
+ if (cfn_share)
{
- NdbError ex_err;
- if (write_conflict_row(share, trans, row, ex_err))
+ enum_conflict_fn_type cft = cfn_share->m_resolve_cft;
+ bool haveExTable = cfn_share->m_ex_tab != NULL;
+
+ // MAX_* currently only handles a conflict rc differently
+ // and does not support an exceptions table. Also it
+ // increments the MAX counter, not the MAX_DEL_WIN counter
+ // Maintain this?
+ if (KEEP_NDB_MAX_SAME)
{
- char msg[FN_REFLEN];
- my_snprintf(msg, sizeof(msg), "table %s NDB error %d '%s'",
- cfn_share->m_ex_tab->getName(),
- ex_err.code, ex_err.message);
-
- NdbDictionary::Dictionary* dict= thd_ndb->ndb->getDictionary();
-
- if (ex_err.classification == NdbError::SchemaError)
+ switch(cft)
{
- dict->removeTableGlobal(*(cfn_share->m_ex_tab), false);
- cfn_share->m_ex_tab= NULL;
+ case CFT_NDB_MAX:
+ case CFT_NDB_MAX_DEL_WIN:
+ {
+ if (err.code == (int) error_conflict_fn_violation)
+ {
+ /* Increment Max violation count, and continue to
+ * next op
+ * TODO : COMPATABILITY MISSING : If it was a delete from
+ * CFT_NDB_MAX, take the old branch
+ * Requires Exceptions_data to have op type.
+ */
+ thd_ndb->m_violation_count[CFT_NDB_MAX]++;
+ if (err.classification != NdbError::NoError)
+ ignores++;
+ first= trans->getNextCompletedOperation(first);
+ continue;
+ }
+ else if (err.classification == NdbError::ConstraintViolation ||
+ err.classification == NdbError::NoDataFound)
+ {
+ /* Treat as an old violation count and continue processing */
+ thd_ndb->m_violation_count[CFT_NDB_OLD]++;
+ break;
+ }
+ else
+ {
+ /* Treat as an error and return */
+ DBUG_PRINT("info", ("err.code == %u", err.code));
+ DBUG_RETURN(err.code);
+ }
}
- else if (ex_err.status == NdbError::TemporaryError)
+ default:
+ {
+ thd_ndb->m_violation_count[cft]++;
+ }
+ }
+ } // NDB_MAX_IS_DIFFERENT
+ else
+ {
+ thd_ndb->m_violation_count[cft]++;
+ }
+
+ // thd_ndb->m_violation_count[cft]++;
+
+ {
+ NdbError handleError;
+ if (handle_row_conflict(cft,
+ cfn_share,
+ key_rec,
+ row,
+ op_type,
+ conflict_cause,
+ trans,
+ handleError))
{
- /* Slave will roll back and retry entire transaction. */
- ERR_RETURN(ex_err);
+ /* Error with function-specific handling of row conflict */
+ char msg[FN_REFLEN];
+ my_snprintf(msg, sizeof(msg), "Row conflict handling "
+ "on table %s hit Ndb error %d '%s'",
+ cfn_share->m_tab->getName(),
+ handleError.code,
+ handleError.message);
+
+ if (handleError.status == NdbError::TemporaryError)
+ {
+ /* Slave will roll back and retry entire transaction. */
+ ERR_RETURN(handleError);
+ }
+ else
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_EXCEPTIONS_WRITE_ERROR,
+ ER(ER_EXCEPTIONS_WRITE_ERROR), msg);
+ /* Slave will stop replication. */
+ DBUG_RETURN(ER_EXCEPTIONS_WRITE_ERROR);
+ }
}
else
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_EXCEPTIONS_WRITE_ERROR,
- ER(ER_EXCEPTIONS_WRITE_ERROR), msg);
- /* Slave will stop replication. */
- DBUG_RETURN(ER_EXCEPTIONS_WRITE_ERROR);
+ conflict_operations_defined++;
}
}
- else
+
+
+ if (haveExTable)
{
- conflict_rows_written++;
+ NdbError ex_err;
+ if (write_conflict_row(share, trans, row, ex_err))
+ {
+ char msg[FN_REFLEN];
+ my_snprintf(msg, sizeof(msg), "table %s NDB error %d '%s'",
+ cfn_share->m_ex_tab->getName(),
+ ex_err.code, ex_err.message);
+
+ NdbDictionary::Dictionary* dict= thd_ndb->ndb->getDictionary();
+
+ if (ex_err.classification == NdbError::SchemaError)
+ {
+ dict->removeTableGlobal(*(cfn_share->m_ex_tab), false);
+ cfn_share->m_ex_tab= NULL;
+ }
+ else if (ex_err.status == NdbError::TemporaryError)
+ {
+ /* Slave will roll back and retry entire transaction. */
+ ERR_RETURN(ex_err);
+ }
+ else
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_EXCEPTIONS_WRITE_ERROR,
+ ER(ER_EXCEPTIONS_WRITE_ERROR), msg);
+ /* Slave will stop replication. */
+ DBUG_RETURN(ER_EXCEPTIONS_WRITE_ERROR);
+ }
+ }
+ else
+ {
+ conflict_operations_defined++;
+ }
}
}
else
{
- DBUG_PRINT("info", ("missing %s", !cfn_share ? "cfn_share" : "ex_tab"));
+ DBUG_PRINT("info", ("missing cfn_share"));
}
}
else
@@ -639,7 +777,7 @@ check_completed_operations_pre_commit(Th
if (ignore_count)
*ignore_count= ignores;
#ifdef HAVE_NDB_BINLOG
- if (conflict_rows_written)
+ if (conflict_operations_defined)
{
if (trans->execute(NdbTransaction::NoCommit,
NdbOperation::AO_IgnoreError,
@@ -752,16 +890,25 @@ int execute_commit(Thd_ndb *thd_ndb, Ndb
DBUG_PRINT("info", ("execute_count: %u", thd_ndb->m_execute_count));
if (trans->execute(NdbTransaction::Commit, ao, force_send))
{
- thd_ndb->m_max_violation_count= 0;
- thd_ndb->m_old_violation_count= 0;
+ bzero(thd_ndb->m_violation_count, sizeof(thd_ndb->m_violation_count));
+ thd_ndb->m_max_replicated_epoch = 0;
thd_ndb->m_conflict_fn_usage_count= 0;
thd_ndb->m_unsent_bytes= 0;
DBUG_RETURN(-1);
}
- g_ndb_status_conflict_fn_max+= thd_ndb->m_max_violation_count;
- g_ndb_status_conflict_fn_old+= thd_ndb->m_old_violation_count;
- thd_ndb->m_max_violation_count= 0;
- thd_ndb->m_old_violation_count= 0;
+ for(int i=0; i< CFT_NUMBER_OF_CFTS; i++)
+ {
+ g_ndb_status_conflict_fn[i]+= thd_ndb->m_violation_count[i];
+ thd_ndb->m_violation_count[i]= 0;
+ }
+ if (thd_ndb->m_max_replicated_epoch > g_ndb_status_max_rep_epoch)
+ {
+ DBUG_PRINT("info", ("Max replicated epoch increases from %llu to %llu",
+ g_ndb_status_max_rep_epoch,
+ thd_ndb->m_max_replicated_epoch));
+ g_ndb_status_max_rep_epoch = thd_ndb->m_max_replicated_epoch;
+ }
+ thd_ndb->m_max_replicated_epoch = 0;
thd_ndb->m_conflict_fn_usage_count= 0;
thd_ndb->m_unsent_bytes= 0;
if (!ignore_error || trans->getNdbError().code == 0)
@@ -819,14 +966,14 @@ Thd_ndb::Thd_ndb()
m_execute_count= 0;
m_scan_count= 0;
m_pruned_scan_count= 0;
- m_max_violation_count= 0;
- m_old_violation_count= 0;
+ bzero(m_violation_count, sizeof(m_violation_count));
m_conflict_fn_usage_count= 0;
bzero(m_transaction_no_hint_count, sizeof(m_transaction_no_hint_count));
bzero(m_transaction_hint_count, sizeof(m_transaction_hint_count));
global_schema_lock_trans= NULL;
global_schema_lock_count= 0;
global_schema_lock_error= 0;
+ m_max_replicated_epoch= 0;
init_alloc_root(&m_batch_mem_root, BATCH_FLUSH_SIZE/4, 0);
}
@@ -2700,8 +2847,8 @@ int ha_ndbcluster::ndb_pk_update_row(THD
DBUG_PRINT("info", ("insert failed"));
if (trans->commitStatus() == NdbConnection::Started)
{
- m_thd_ndb->m_max_violation_count= 0;
- m_thd_ndb->m_old_violation_count= 0;
+ bzero(m_thd_ndb->m_violation_count, sizeof(m_thd_ndb->m_violation_count));
+ m_thd_ndb->m_max_replicated_epoch= 0;
m_thd_ndb->m_conflict_fn_usage_count= 0;
m_thd_ndb->m_unsent_bytes= 0;
m_thd_ndb->m_execute_count++;
@@ -3631,6 +3778,25 @@ bool ha_ndbcluster::isManualBinlogExec(T
}
+/*
+ is_serverid_local
+
+ Check the list of cluster-local serverids to see
+ whether the passed serverid is local.
+*/
+bool is_serverid_local(Uint32 serverid)
+{
+ for (Uint32 i=0; i< cluster_server_id_count; i++)
+ {
+ if (cluster_server_ids[i] == serverid)
+ return true;
+ }
+
+ assert(serverid != ::server_id);
+
+ return false;
+}
+
int ha_ndbcluster::write_row(uchar *record)
{
DBUG_ENTER("ha_ndbcluster::write_row");
@@ -3645,6 +3811,26 @@ int ha_ndbcluster::write_row(uchar *reco
memcpy(&master_epoch, table->field[1]->ptr + (record - table->record[0]),
sizeof(master_epoch));
active_mi->master_epoch= master_epoch;
+ assert(! is_serverid_local(sid));
+ }
+ else if (is_serverid_local(sid))
+ {
+ Uint64 applied_epoch;
+ memcpy(&applied_epoch, table->field[1]->ptr + (record - table->record[0]),
+ sizeof(applied_epoch));
+ DBUG_PRINT("info", ("Recording application of local server %u epoch %llu "
+ " which is %s.",
+ sid, applied_epoch,
+ (applied_epoch > g_ndb_status_max_rep_epoch)?
+ " new highest." : " older than previously applied"));
+ if (applied_epoch > g_ndb_status_max_rep_epoch)
+ {
+ /*
+ Store new highest epoch in thdvar. If we commit successfully
+ then this becomes the new global max
+ */
+ m_thd_ndb->m_max_replicated_epoch = applied_epoch;
+ }
}
}
#endif /* HAVE_NDB_BINLOG */
@@ -3665,10 +3851,12 @@ int ha_ndbcluster::ndb_write_row(uchar *
NdbTransaction *trans;
uint32 part_id;
int error;
- NdbOperation::SetValueSpec sets[2];
+ NdbOperation::SetValueSpec sets[3];
Uint32 num_sets= 0;
DBUG_ENTER("ha_ndbcluster::ndb_write_row");
+ check_slave_status(thd);
+
has_auto_increment= (table->next_number_field && record == table->record[0]);
if (has_auto_increment && table_share->primary_key != MAX_KEY)
@@ -3790,6 +3978,16 @@ int ha_ndbcluster::ndb_write_row(uchar *
eventSetAnyValue(thd, &options);
bool need_flush= add_row_check_if_batch_full(thd_ndb);
+ const Uint32 authorValue = 1;
+ if ((thd->slave_thread) &&
+ (m_table->getExtraRowAuthorBits()))
+ {
+ /* Set author to indicate slave updated last */
+ sets[num_sets].column= NdbDictionary::Column::ROW_AUTHOR;
+ sets[num_sets].value= &authorValue;
+ num_sets++;
+ }
+
if (m_user_defined_partitioning)
{
options.optionsPresent |= NdbOperation::OperationOptions::OO_PARTITION_ID;
@@ -3873,6 +4071,8 @@ int ha_ndbcluster::ndb_write_row(uchar *
Ndb_exceptions_data ex_data;
ex_data.share= m_share;
+ ex_data.key_rec= key_rec;
+ ex_data.op_type= WRITE_ROW;
/*
We need to save the row data for possible conflict resolution after
execute().
@@ -3907,6 +4107,8 @@ int ha_ndbcluster::ndb_write_row(uchar *
Ndb_exceptions_data ex_data;
ex_data.share= m_share;
+ ex_data.key_rec= key_rec;
+ ex_data.op_type= WRITE_ROW;
/*
We need to save the row data for possible conflict resolution after
execute().
@@ -4142,7 +4344,7 @@ ha_ndbcluster::row_conflict_fn_max(const
*/
r= code->branch_gt(RegNewValue, RegCurrentValue, label_0);
DBUG_ASSERT(r == 0);
- r= code->interpret_exit_nok(error_conflict_fn_max_violation);
+ r= code->interpret_exit_nok(error_conflict_fn_violation);
DBUG_ASSERT(r == 0);
r= code->def_label(label_0);
DBUG_ASSERT(r == 0);
@@ -4227,7 +4429,67 @@ ha_ndbcluster::row_conflict_fn_old(const
*/
r= code->branch_eq(RegOldValue, RegCurrentValue, label_0);
DBUG_ASSERT(r == 0);
- r= code->interpret_exit_nok(error_conflict_fn_old_violation);
+ r= code->interpret_exit_nok(error_conflict_fn_violation);
+ DBUG_ASSERT(r == 0);
+ r= code->def_label(label_0);
+ DBUG_ASSERT(r == 0);
+ r= code->interpret_exit_ok();
+ DBUG_ASSERT(r == 0);
+ r= code->finalise();
+ DBUG_ASSERT(r == 0);
+ return r;
+}
+
+/**
+ CFT_NDB_EPOCH
+
+ To perform conflict detection, an interpreted program is used to read
+ the existing row's epoch (if present) and compare it with the current
+ maximum replicated epoch.
+ If the row has a higher epoch than the current maximum replicated epoch
+ then it has been updated in conflict with this replication event.
+ In this case an error for this operation (9999) will be raised,
+ and new row will not be applied. The error codes for the operations will
+ be checked on return. For this to work is is vital that the operation
+ is run with ignore error option.
+*/
+int
+ha_ndbcluster::row_conflict_fn_epoch(NdbInterpretedCode *code)
+{
+ DBUG_PRINT("info", ("interpreted update/delete check that "
+ "if locally updated last, "
+ "ROW$GCI64 <= Maximum Replicated Epoch (%llu)",
+ g_ndb_status_max_rep_epoch));
+
+ const uint label_0= 0;
+ const Uint32
+ RegAuthor= 1, RegZero= 2,
+ RegMaxRepEpoch= 1, RegRowEpoch= 2;
+ int r;
+
+ r= code->load_const_u32(RegZero, 0);
+ DBUG_ASSERT(r == 0);
+ r= code->read_attr(RegAuthor, NdbDictionary::Column::ROW_AUTHOR);
+ DBUG_ASSERT(r == 0);
+ /* If last author was not local, assume no conflict */
+ r= code->branch_ne(RegZero, RegAuthor, label_0);
+ DBUG_ASSERT(r == 0);
+
+ /*
+ * Load registers RegMaxRepEpoch and RegRowEpoch
+ */
+ r= code->load_const_u64(RegMaxRepEpoch, g_ndb_status_max_rep_epoch);
+ DBUG_ASSERT(r == 0);
+ r= code->read_attr(RegRowEpoch, NdbDictionary::Column::ROW_GCI64);
+ DBUG_ASSERT(r == 0);
+
+ /*
+ * if RegRowEpoch <= RegMaxRepEpoch goto label_0
+ * else raise error for this row
+ */
+ r= code->branch_le(RegRowEpoch, RegMaxRepEpoch, label_0);
+ DBUG_ASSERT(r == 0);
+ r= code->interpret_exit_nok(error_conflict_fn_violation);
DBUG_ASSERT(r == 0);
r= code->def_label(label_0);
DBUG_ASSERT(r == 0);
@@ -4250,7 +4512,10 @@ ha_ndbcluster::update_row_conflict_fn(en
return row_conflict_fn_max(new_data, code);
case CFT_NDB_OLD:
return row_conflict_fn_old(old_data, code);
+ case CFT_NDB_EPOCH:
+ return row_conflict_fn_epoch(code);
case CFT_NDB_UNDEF:
+ case CFT_NUMBER_OF_CFTS:
abort();
}
DBUG_ASSERT(false);
@@ -4273,6 +4538,11 @@ ha_ndbcluster::write_row_conflict_fn(enu
already exists
*/
return 1;
+ case CFT_NDB_EPOCH:
+ /*
+ Detect if tuple already exists
+ */
+ return 1;
case CFT_NDB_UNDEF:
abort();
}
@@ -4307,12 +4577,105 @@ ha_ndbcluster::delete_row_conflict_fn(en
}
case CFT_NDB_OLD:
return row_conflict_fn_old(old_data, code);
+ case CFT_NDB_EPOCH:
+ return row_conflict_fn_epoch(code);
+ case CFT_NDB_UNDEF:
+ case CFT_NUMBER_OF_CFTS:
+ abort();
+ }
+ DBUG_ASSERT(false);
+ return 1;
+}
+
+int
+handle_row_conflict_fn_epoch(NDB_CONFLICT_FN_SHARE* cfn_share,
+ const NdbRecord* key_rec,
+ const uchar* pkRow,
+ enum_conflicting_op_type op_type,
+ enum_conflict_cause conflict_cause,
+ NdbTransaction* conflictTrans,
+ NdbError& err)
+{
+ DBUG_ENTER("handle_row_conflict_fn_epoch");
+ /* A conflict has been detected between a received event and the
+ * data in the DB.
+ * The attempt to change the local DB will have been rejected.
+ * We now take steps to generate a refresh Binlog event so that
+ * other clusters will be re-aligned.
+ */
+ /* 1 : Get orig table from cfn share
+ * 2 : Create operation on this tab in transaction
+ * 3 : Set PK based on details from pkRow
+ * 4 : ...
+ */
+
+ fprintf(stderr,
+ "In handle_row_conflict_fn_epoch() for table %s. Will generate "
+ "refresh event based on pk (%u columns)\n",
+ cfn_share->m_tab->getName(), cfn_share->m_pk_cols);
+
+ fprintf(stderr,
+ " Op type was %s, conflict type was %s\n",
+ ((op_type == WRITE_ROW)? "WRITE_ROW":
+ (op_type == UPDATE_ROW)? "UPDATE_ROW":
+ "DELETE_ROW"),
+ ((conflict_cause == ROW_ALREADY_EXISTS)?"ROW_ALREADY_EXISTS":
+ (conflict_cause == ROW_DOES_NOT_EXIST)?"ROW_DOES_NOT_EXIST":
+ "ROW_IN_CONFLICT"));
+
+ DBUG_ASSERT(cfn_share->m_tab != NULL);
+ DBUG_ASSERT(key_rec != NULL);
+ DBUG_ASSERT(pkRow != NULL);
+
+ /* Create a refresh to operation to realign other clusters */
+ // TODO AnyValue
+ // TODO Do we ever get non-PK key?
+ // Keyless table?
+ // Unique index
+ const NdbOperation* refreshOp= conflictTrans->refreshTuple(key_rec,
+ (const char*) pkRow);
+
+ if (!refreshOp)
+ {
+ err= conflictTrans->getNdbError();
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+int
+handle_row_conflict(enum_conflict_fn_type cft,
+ NDB_CONFLICT_FN_SHARE* cfn_share,
+ const NdbRecord* key_rec,
+ const uchar* pkRow,
+ enum_conflicting_op_type op_type,
+ enum_conflict_cause conflict_cause,
+ NdbTransaction* conflictTrans,
+ NdbError& err)
+{
+ switch (cft) {
+ case CFT_NDB_MAX:
+ case CFT_NDB_MAX_DEL_WIN:
+ case CFT_NDB_OLD:
+ /* No special handling */
+ return 0;
+ case CFT_NDB_EPOCH:
+ return handle_row_conflict_fn_epoch(cfn_share,
+ key_rec,
+ pkRow,
+ op_type,
+ conflict_cause,
+ conflictTrans,
+ err);
case CFT_NDB_UNDEF:
+ case CFT_NUMBER_OF_CFTS:
abort();
}
DBUG_ASSERT(false);
return 1;
}
+
#endif /* HAVE_NDB_BINLOG */
/**
@@ -4429,10 +4792,14 @@ int ha_ndbcluster::ndb_update_row(const
bitmap_is_overlapping(table->write_set, m_pk_bitmap_p) &&
primary_key_cmp(old_data, new_data));
bool batch_allowed= is_bulk_update || (thd->options & OPTION_ALLOW_BATCH);
- NdbOperation::SetValueSpec sets[1];
+ NdbOperation::SetValueSpec sets[2];
+ Uint32 num_sets= 0;
DBUG_ENTER("ndb_update_row");
DBUG_ASSERT(trans);
+
+ check_slave_status(thd);
+
/*
* If IGNORE the ignore constraint violations on primary and unique keys,
* but check that it is not part of INSERT ... ON DUPLICATE KEY UPDATE
@@ -4531,11 +4898,9 @@ int ha_ndbcluster::ndb_update_row(const
func_value_uint32= INT_MAX32;
else
func_value_uint32= (uint32)func_value;
- sets[0].column= get_partition_id_column();
- sets[0].value= &func_value_uint32;
- options.optionsPresent|= NdbOperation::OperationOptions::OO_SETVALUE;
- options.extraSetValues= sets;
- options.numExtraSetValues= 1;
+ sets[num_sets].column= get_partition_id_column();
+ sets[num_sets].value= &func_value_uint32;
+ num_sets++;
if (!cursor)
{
@@ -4548,6 +4913,23 @@ int ha_ndbcluster::ndb_update_row(const
bool need_flush= add_row_check_if_batch_full(thd_ndb);
+ const Uint32 authorValue = 1;
+ if ((thd->slave_thread) &&
+ (m_table->getExtraRowAuthorBits()))
+ {
+ /* Set author to indicate slave updated last */
+ sets[num_sets].column= NdbDictionary::Column::ROW_AUTHOR;
+ sets[num_sets].value= &authorValue;
+ num_sets++;
+ }
+
+ if (num_sets)
+ {
+ options.optionsPresent|= NdbOperation::OperationOptions::OO_SETVALUE;
+ options.extraSetValues= sets;
+ options.numExtraSetValues= num_sets;
+ }
+
if (cursor)
{
/*
@@ -4602,6 +4984,8 @@ int ha_ndbcluster::ndb_update_row(const
Ndb_exceptions_data ex_data;
ex_data.share= m_share;
+ ex_data.key_rec= key_rec;
+ ex_data.op_type= UPDATE_ROW;
/*
We need to save the row data for possible conflict resolution after
execute().
@@ -4725,6 +5109,8 @@ int ha_ndbcluster::ndb_delete_row(const
DBUG_ENTER("ndb_delete_row");
DBUG_ASSERT(trans);
+ check_slave_status(thd);
+
ha_statistic_increment(&SSV::ha_delete_count);
m_rows_changed++;
@@ -4836,6 +5222,8 @@ int ha_ndbcluster::ndb_delete_row(const
Ndb_exceptions_data ex_data;
ex_data.share= m_share;
+ ex_data.key_rec= key_rec;
+ ex_data.op_type= DELETE_ROW;
/*
We need to save the row data for possible conflict resolution after
execute().
@@ -6795,8 +7183,8 @@ static int ndbcluster_rollback(handlerto
DBUG_RETURN(0);
}
thd_ndb->save_point_count= 0;
- thd_ndb->m_max_violation_count= 0;
- thd_ndb->m_old_violation_count= 0;
+ bzero(thd_ndb->m_violation_count, sizeof(thd_ndb->m_violation_count));
+ thd_ndb->m_max_replicated_epoch= 0;
thd_ndb->m_conflict_fn_usage_count= 0;
thd_ndb->m_unsent_bytes= 0;
thd_ndb->m_execute_count++;
@@ -7462,6 +7850,61 @@ int ha_ndbcluster::create(const char *na
ndbtab_g.reinit();
}
+#ifdef HAVE_NDB_BINLOG
+ /* Read ndb_replication entry for this table, if any */
+ Uint32 binlogFlags;
+ st_conflict_fn_def* conflictFn= NULL;
+ st_conflict_fn_arg args[MaxConflictArgs];
+ Uint32 numArgs = MaxConflictArgs;
+
+ if (ndbcluster_get_binlog_replication_info(thd,
+ ndb,
+ m_dbname,
+ m_tabname,
+ ::server_id,
+ form,
+ &binlogFlags,
+ &conflictFn,
+ args,
+ &numArgs) != 0)
+ {
+ DBUG_RETURN(ER_NDB_REPLICATION_SCHEMA_ERROR);
+ }
+
+ /* Reset database name */
+ ndb->setDatabaseName(m_dbname);
+
+ if (conflictFn != NULL)
+ {
+ switch(conflictFn->type)
+ {
+ case CFT_NDB_EPOCH:
+ {
+ /* Default 6 extra Gci bits allows 2^6 == 64
+ * epochs / saveGCP, a comfortable default
+ */
+ Uint32 numExtraGciBits = 6;
+ Uint32 numExtraAuthorBits = 1;
+
+ if ((numArgs == 1) &&
+ (args[0].type == CFAT_EXTRA_GCI_BITS))
+ {
+ numExtraGciBits = args[0].extraGciBits;
+ }
+ DBUG_PRINT("info", ("Setting ExtraRowGciBits to %u, "
+ "ExtraAuthorBits to %u",
+ numExtraGciBits,
+ numExtraAuthorBits));
+
+ tab.setExtraRowGciBits(numExtraGciBits);
+ tab.setExtraRowAuthorBits(numExtraAuthorBits);
+ }
+ default:
+ break;
+ }
+ }
+#endif
+
if ((dict->beginSchemaTrans() == -1))
{
DBUG_PRINT("info", ("Failed to start schema transaction"));
@@ -7848,8 +8291,18 @@ cleanup_failed:
{
#ifdef HAVE_NDB_BINLOG
if (share)
- ndbcluster_read_binlog_replication(thd, ndb, share, m_table,
- ::server_id, form, TRUE);
+ {
+ /* Set the Binlogging information we retrieved above */
+ ndbcluster_apply_binlog_replication_info(thd,
+ share,
+ m_table,
+ form,
+ conflictFn,
+ args,
+ numArgs,
+ TRUE, /* Do set binlog flags */
+ binlogFlags);
+ }
#endif
String event_name(INJECTOR_EVENT_LEN);
ndb_rep_event_name(&event_name, m_dbname, m_tabname,
@@ -14274,6 +14727,115 @@ static int ndbcluster_fill_files_table(h
DBUG_RETURN(0);
}
+int try_determine_server_ids(const char* inputStr,
+ Uint32* serverIdsArray,
+ const Uint32 len)
+{
+ Uint32 numServerIds = 1;
+ memset(serverIdsArray, 0, len * sizeof(Uint32));
+ serverIdsArray[0] = ::server_id;
+
+ if (inputStr)
+ {
+ while ((*inputStr != 0) &&
+ (numServerIds < len))
+ {
+ char* nextChar;
+ Uint32 id = strtoul(inputStr, &nextChar, 0);
+ if (id == 0)
+ {
+ /* Bad conversion */
+ return -1;
+ }
+ {
+ /* Have a serverid, check that it's unique
+ * Duplicates are ok, but are ignored
+ */
+ bool duplicate = false;
+ for (Uint32 i=0; i< numServerIds; i++)
+ {
+ if (id == serverIdsArray[i])
+ {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate)
+ serverIdsArray[ numServerIds++ ] = id;
+ }
+
+ inputStr = nextChar;
+ switch (*nextChar)
+ {
+ case 0:
+ break;
+ case ',':
+ inputStr++;
+ break;
+ default:
+ /* Bad format */
+ return -2;
+ }
+ }
+ }
+
+ return numServerIds;
+}
+
+static int check_ndb_cluster_server_ids(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ /* Inspired by sql_plugin.cc check_func_str() */
+ char buff[ MAX_SERVER_IDS_STR_LEN ];
+ const char *str;
+ int length = MAX_SERVER_IDS_STR_LEN;
+
+ if ((str= value->val_str(value, buff, &length)))
+ {
+ str= thd->strmake(str, length);
+
+ Uint32 testServerIds[ MAX_API_NODES ];
+ if (try_determine_server_ids(str,
+ testServerIds,
+ MAX_API_NODES) < 0)
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "ndb_cluster_server_ids", str);
+ return 1;
+ }
+ }
+
+ *(const char**)save= str;
+ return 0;
+}
+
+static void update_ndb_cluster_server_ids(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, const void *save)
+{
+ /* Inspired by sql_plugin.cc update_func_str() */
+ /* - Duplicate string from save (from check function) into
+ * dynamic memory.
+ * - Set target to point to it.
+ * - Free old dynamic memory
+ */
+ char *old = *(char **) tgt;
+ const char* str = * ((char **) save);
+ Uint32 len = strlen(str);
+ assert(len < MAX_SERVER_IDS_STR_LEN);
+ *(char **)tgt = my_strdup(str, MYF(0));
+
+ if (old)
+ my_free(old, MYF(0));
+
+ /* Now compute the cluster serverids array values based on
+ * the string
+ */
+ int result = try_determine_server_ids(str,
+ cluster_server_ids,
+ MAX_API_NODES);
+ assert(result >= 0);
+ cluster_server_id_count = (Uint32) result;
+}
+
static int show_ndb_vars(THD *thd, SHOW_VAR *var, char *buff)
{
if (!check_ndb_in_thd(thd))
@@ -14305,6 +14867,7 @@ SHOW_VAR ndb_status_variables_export[]=
{"Ndb", (char*) &show_ndb_vars, SHOW_FUNC},
{"Ndb", (char*) &ndb_status_variables_fixed, SHOW_ARRAY},
{"Ndb_conflict", (char*) &ndb_status_conflict_variables, SHOW_ARRAY},
+ {"Ndb_slave", (char*) &ndb_status_variables_slave, SHOW_ARRAY},
{NullS, NullS, SHOW_LONG}
};
@@ -14501,6 +15064,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 */
@@ -14538,6 +15112,16 @@ static MYSQL_SYSVAR_UINT(
0 /* block */
);
+static MYSQL_SYSVAR_STR(
+ cluster_server_ids, /* name */
+ opt_ndb_cluster_server_ids, /* var */
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Comma separated list of server ids of other MySQLDs "
+ "attached to this Cluster.",
+ check_ndb_cluster_server_ids, /* check func. */
+ update_ndb_cluster_server_ids, /* update func. */
+ NULL /* default */
+);
static struct st_mysql_sys_var* system_variables[]= {
MYSQL_SYSVAR(cache_check_time),
@@ -14567,9 +15151,11 @@ 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),
+ MYSQL_SYSVAR(cluster_server_ids),
NULL
};
=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h 2010-09-15 18:38:13 +0000
+++ b/sql/ha_ndbcluster.h 2010-09-22 10:49:11 +0000
@@ -126,19 +126,69 @@ typedef enum {
NSS_ALTERED
} NDB_SHARE_STATE;
-#ifdef HAVE_NDB_BINLOG
enum enum_conflict_fn_type
{
CFT_NDB_UNDEF = 0
,CFT_NDB_MAX
,CFT_NDB_OLD
,CFT_NDB_MAX_DEL_WIN
+ ,CFT_NDB_EPOCH
+ ,CFT_NUMBER_OF_CFTS /* End marker */
+};
+
+#ifdef HAVE_NDB_BINLOG
+static const Uint32 MaxConflictArgs= 8;
+
+enum enum_conflict_fn_arg_type
+{
+ CFAT_END
+ ,CFAT_COLUMN_NAME
+ ,CFAT_EXTRA_GCI_BITS
+};
+
+struct st_conflict_fn_arg
+{
+ enum_conflict_fn_arg_type type;
+ const char *ptr;
+ uint32 len;
+ union
+ {
+ uint32 fieldno; // CFAT_COLUMN_NAME
+ uint32 extraGciBits; // CFAT_EXTRA_GCI_BITS
+ };
};
+struct st_conflict_fn_def
+{
+ const char *name;
+ enum_conflict_fn_type type;
+ enum enum_conflict_fn_arg_type arg_type;
+ bool optional;
+};
+
+/* What type of operation was issued */
+enum enum_conflicting_op_type
+{ /* NdbApi */
+ WRITE_ROW, /* insert (!write) */
+ UPDATE_ROW, /* update */
+ DELETE_ROW /* delete */
+};
+
+/* What sort of conflict was found */
+enum enum_conflict_cause
+{
+ ROW_ALREADY_EXISTS,
+ ROW_DOES_NOT_EXIST,
+ ROW_IN_CONFLICT
+};
+
+
/* NdbOperation custom data which points out handler and record. */
struct Ndb_exceptions_data {
struct st_ndbcluster_share *share;
+ const NdbRecord* key_rec;
const uchar* row;
+ enum_conflicting_op_type op_type;
};
typedef struct st_ndbcluster_conflict_fn_share {
@@ -151,6 +201,7 @@ typedef struct st_ndbcluster_conflict_fn
uint8 unused;
uint16 m_offset[16];
+ const NdbDictionary::Table *m_tab;
const NdbDictionary::Table *m_ex_tab;
uint32 m_count;
} NDB_CONFLICT_FN_SHARE;
@@ -351,8 +402,7 @@ class Thd_ndb
uint m_batch_size;
uint m_execute_count;
- uint m_max_violation_count;
- uint m_old_violation_count;
+ uint m_violation_count[CFT_NUMBER_OF_CFTS];
uint m_conflict_fn_usage_count;
uint m_scan_count;
@@ -365,6 +415,8 @@ class Thd_ndb
uint global_schema_lock_count;
uint global_schema_lock_error;
+ Uint64 m_max_replicated_epoch;
+
unsigned m_connect_count;
bool valid_ndb(void);
bool recycle_ndb(THD* thd);
@@ -579,6 +631,7 @@ static void set_tabname(const char *path
private:
#ifdef HAVE_NDB_BINLOG
+#define KEEP_NDB_MAX_SAME 0
int delete_row_conflict_fn(enum_conflict_fn_type cft,
const uchar *old_data,
NdbInterpretedCode *);
@@ -593,6 +646,7 @@ private:
NdbInterpretedCode *);
int row_conflict_fn_old(const uchar *old_data,
NdbInterpretedCode *);
+ int row_conflict_fn_epoch(NdbInterpretedCode *);
#endif
void setup_key_ref_for_ndb_record(const NdbRecord **key_rec,
const uchar **key_row,
@@ -777,6 +831,8 @@ private:
int start_statement(THD *thd, Thd_ndb *thd_ndb, uint table_count);
int init_handler_for_statement(THD *thd);
+ void check_slave_status(THD* thd);
+
Thd_ndb *m_thd_ndb;
NdbScanOperation *m_active_cursor;
const NdbDictionary::Table *m_table;
@@ -888,6 +944,7 @@ void ndbcluster_print_error(int error, c
static const char ndbcluster_hton_name[]= "ndbcluster";
static const int ndbcluster_hton_name_length=sizeof(ndbcluster_hton_name)-1;
+static const Uint32 MAX_API_NODES=256;
extern int ndbcluster_terminating;
extern int ndb_util_thread_running;
extern pthread_cond_t COND_ndb_util_ready;
=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc 2010-09-15 18:38:13 +0000
+++ b/sql/ha_ndbcluster_binlog.cc 2010-09-22 10:49:11 +0000
@@ -30,6 +30,8 @@
#include <ndbapi/ndb_cluster_connection.hpp>
#include <util/NdbAutoPtr.hpp>
#include <portlib/NdbTick.h>
+#include "slave.h"
+#include "rpl_mi.h"
#ifdef ndb_dynamite
#undef assert
@@ -42,8 +44,13 @@ 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;
+extern char* opt_ndb_cluster_server_ids;
+extern Uint32 cluster_server_ids[ ];
+extern Uint32 cluster_server_id_count;
+extern Uint64 g_ndb_status_max_rep_epoch;
/*
defines for cluster replication table names
@@ -131,6 +138,10 @@ pthread_mutex_t ndb_schema_share_mutex;
extern my_bool opt_log_slave_updates;
static my_bool g_ndb_log_slave_updates;
+#ifdef HAVE_NDB_BINLOG
+static Uint32 g_ndb_slave_sql_run_id = 0xffffffff;
+#endif
+
/* Schema object distribution handling */
HASH ndb_schema_objects;
typedef struct st_ndb_schema_object {
@@ -796,6 +807,9 @@ static void ndbcluster_reset_slave(THD *
thd->main_da.reset_diagnostics_area();
}
+ /* Reset Ndb_slave_max_replicated_epoch */
+ g_ndb_status_max_rep_epoch = 0;
+
DBUG_VOID_RETURN;
}
@@ -3476,6 +3490,10 @@ add_ndb_binlog_index_err:
return error;
}
+extern int try_determine_server_ids(const char* inputStr,
+ Uint32* serverIdsArray,
+ const Uint32 len);
+
/*********************************************************************
Functions for start, stop, wait for ndbcluster binlog thread
*********************************************************************/
@@ -3503,6 +3521,26 @@ int ndbcluster_binlog_start()
DBUG_RETURN(-1);
}
+ /*
+ Initialise the cluster_server_id structures from the command
+ line argument (if any). This is required as the plugin
+ framework doesn't use the update function when initialising
+ a variable from the command line!
+ */
+ {
+ int rc = try_determine_server_ids(opt_ndb_cluster_server_ids,
+ cluster_server_ids,
+ MAX_API_NODES);
+
+ if (unlikely(rc < 1))
+ {
+ sql_print_error("NDB: supplied ndb_cluster_server_ids parameter (%s) "
+ "is invalid", opt_ndb_cluster_server_ids);
+ DBUG_RETURN(-1);
+ }
+ cluster_server_id_count = Uint32(rc);
+ }
+
pthread_mutex_init(&injector_mutex, MY_MUTEX_INIT_FAST);
pthread_cond_init(&injector_cond, NULL);
pthread_mutex_init(&ndb_schema_share_mutex, MY_MUTEX_INIT_FAST);
@@ -3635,18 +3673,13 @@ inline void slave_reset_conflict_fn(NDB_
}
}
-static int
-slave_set_resolve_fn(THD *thd, NDB_SHARE *share,
- const NDBTAB *ndbtab, uint field_index,
- enum_conflict_fn_type type, TABLE *table)
+static uint
+slave_check_resolve_col_type(const NDBTAB *ndbtab,
+ uint field_index)
{
- DBUG_ENTER("slave_set_resolve_fn");
-
- Thd_ndb *thd_ndb= get_thd_ndb(thd);
- Ndb *ndb= thd_ndb->ndb;
- NDBDICT *dict= ndb->getDictionary();
+ DBUG_ENTER("slave_check_resolve_col_type");
const NDBCOL *c= ndbtab->getColumn(field_index);
- uint sz;
+ uint sz= 0;
switch (c->getType())
{
case NDBCOL::Unsigned:
@@ -3662,10 +3695,22 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE
default:
DBUG_PRINT("info", ("resolve column %u has wrong type",
field_index));
- slave_reset_conflict_fn(share);
- DBUG_RETURN(-1);
break;
}
+ DBUG_RETURN(sz);
+}
+
+static int
+slave_set_resolve_fn(THD *thd, NDB_SHARE *share,
+ const NDBTAB *ndbtab, uint field_index,
+ uint resolve_col_sz, enum_conflict_fn_type type,
+ TABLE *table)
+{
+ DBUG_ENTER("slave_set_resolve_fn");
+
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
+ Ndb *ndb= thd_ndb->ndb;
+ NDBDICT *dict= ndb->getDictionary();
NDB_CONFLICT_FN_SHARE *cfn_share= share->m_cfn_share;
if (cfn_share == NULL)
@@ -3674,9 +3719,10 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE
alloc_root(&share->mem_root, sizeof(NDB_CONFLICT_FN_SHARE));
slave_reset_conflict_fn(share);
}
- cfn_share->m_resolve_size= sz;
+ cfn_share->m_resolve_size= resolve_col_sz;
cfn_share->m_resolve_column= field_index;
cfn_share->m_resolve_cft= type;
+ cfn_share->m_tab= ndbtab;
{
/* get exceptions table */
@@ -3735,7 +3781,10 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE
cfn_share->m_pk_cols= nkey;
ndbtab_g.release();
if (opt_ndb_extra_logging)
- sql_print_information("NDB Slave: log exceptions to %s",
+ sql_print_information("NDB Slave: Table %s.%s logging exceptions to %s.%s",
+ table->s->db.str,
+ table->s->table_name.str,
+ table->s->db.str,
ex_tab_name);
}
else
@@ -3752,76 +3801,44 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE
DBUG_RETURN(0);
}
-enum enum_conflict_fn_arg_type
-{
- CFAT_END
- ,CFAT_COLUMN_NAME
-};
-struct st_conflict_fn_arg
-{
- enum_conflict_fn_arg_type type;
- const char *ptr;
- uint32 len;
- uint32 fieldno; // CFAT_COLUMN_NAME
-};
-struct st_conflict_fn_def
-{
- const char *name;
- enum_conflict_fn_type type;
- enum enum_conflict_fn_arg_type arg_type;
-};
+
static struct st_conflict_fn_def conflict_fns[]=
{
- { "NDB$MAX_DELETE_WIN", CFT_NDB_MAX_DEL_WIN, CFAT_COLUMN_NAME }
- ,{ NULL, CFT_NDB_MAX_DEL_WIN, CFAT_END }
- ,{ "NDB$MAX", CFT_NDB_MAX, CFAT_COLUMN_NAME }
- ,{ NULL, CFT_NDB_MAX, CFAT_END }
- ,{ "NDB$OLD", CFT_NDB_OLD, CFAT_COLUMN_NAME }
- ,{ NULL, CFT_NDB_OLD, CFAT_END }
+ { "NDB$MAX_DELETE_WIN", CFT_NDB_MAX_DEL_WIN, CFAT_COLUMN_NAME, false }
+ ,{ NULL, CFT_NDB_MAX_DEL_WIN, CFAT_END, false }
+ ,{ "NDB$MAX", CFT_NDB_MAX, CFAT_COLUMN_NAME, false }
+ ,{ NULL, CFT_NDB_MAX, CFAT_END, false }
+ ,{ "NDB$OLD", CFT_NDB_OLD, CFAT_COLUMN_NAME, false }
+ ,{ NULL, CFT_NDB_OLD, CFAT_END, false }
+ ,{ "NDB$EPOCH", CFT_NDB_EPOCH, CFAT_EXTRA_GCI_BITS, true }
+ ,{ NULL, CFT_NDB_EPOCH, CFAT_END, false }
};
static unsigned n_conflict_fns=
sizeof(conflict_fns) / sizeof(struct st_conflict_fn_def);
-static int
-set_conflict_fn(THD *thd, NDB_SHARE *share,
- const NDBTAB *ndbtab,
- const NDBCOL *conflict_col,
- char *conflict_fn,
- char *msg, uint msg_len,
- TABLE *table)
-{
- DBUG_ENTER("set_conflict_fn");
- uint len= 0;
- switch (conflict_col->getArrayType())
- {
- case NDBCOL::ArrayTypeShortVar:
- len= *(uchar*)conflict_fn;
- conflict_fn++;
- break;
- case NDBCOL::ArrayTypeMediumVar:
- len= uint2korr(conflict_fn);
- conflict_fn+= 2;
- break;
- default:
- break;
- }
- conflict_fn[len]= '\0';
- const char *ptr= conflict_fn;
+int
+parse_conflict_fn_spec(const char* conflictFnSpec,
+ st_conflict_fn_def** conflictFn,
+ st_conflict_fn_arg* args,
+ Uint32* maxArgs,
+ const TABLE* table,
+ char *msg, uint msg_len)
+{
+ DBUG_ENTER("parse_conflict_fn_spec");
+
+ Uint32 no_args = 0;
+ const char *ptr= conflictFnSpec;
const char *error_str= "unknown conflict resolution function";
/* remove whitespace */
while (*ptr == ' ' && *ptr != '\0') ptr++;
- const unsigned MAX_ARGS= 8;
- unsigned no_args= 0;
- struct st_conflict_fn_arg args[MAX_ARGS];
-
- DBUG_PRINT("info", ("parsing %s", conflict_fn));
+ DBUG_PRINT("info", ("parsing %s", conflictFnSpec));
for (unsigned i= 0; i < n_conflict_fns; i++)
{
struct st_conflict_fn_def &fn= conflict_fns[i];
if (fn.name == NULL)
- continue;
+ continue; /* Skip argument entries */
uint len= strlen(fn.name);
if (strncmp(ptr, fn.name, len))
@@ -3847,6 +3864,13 @@ set_conflict_fn(THD *thd, NDB_SHARE *sha
/* find all arguments */
for (;;)
{
+ if (no_args >= *maxArgs)
+ {
+ error_str= "too many arguments";
+ DBUG_PRINT("info", ("parse error %s", error_str));
+ break;
+ }
+
/* expected type */
enum enum_conflict_fn_arg_type type=
conflict_fns[i+no_args].arg_type;
@@ -3862,16 +3886,30 @@ set_conflict_fn(THD *thd, NDB_SHARE *sha
}
/* arg */
+ /* Todo : Should support comma as an arg separator? */
const char *start_arg= ptr;
while (*ptr != ')' && *ptr != ' ' && *ptr != '\0') ptr++;
const char *end_arg= ptr;
+ bool optionalArg = conflict_fns[i+no_args].optional;
/* any arg given? */
if (start_arg == end_arg)
{
- error_str= "missing function argument";
- DBUG_PRINT("info", ("parse error %s", error_str));
- break;
+ if (!optionalArg)
+ {
+ error_str= "missing function argument";
+ DBUG_PRINT("info", ("parse error %s", error_str));
+ break;
+ }
+ else
+ {
+ /* Arg was optional, and not present
+ * Must be at end of args, finish parsing
+ */
+ args[no_args].type= CFAT_END;
+ error_str= NULL;
+ break;
+ }
}
uint len= end_arg - start_arg;
@@ -3882,6 +3920,7 @@ set_conflict_fn(THD *thd, NDB_SHARE *sha
DBUG_PRINT("info", ("found argument %s %u", start_arg, len));
+ bool argProcessingError = false;
switch (type)
{
case CFAT_COLUMN_NAME:
@@ -3902,10 +3941,31 @@ set_conflict_fn(THD *thd, NDB_SHARE *sha
}
break;
}
+ case CFAT_EXTRA_GCI_BITS:
+ {
+ /* Map string to number and check it's in range etc */
+ char* end_of_arg = (char*) end_arg;
+ Uint32 bits = strtoul(start_arg, &end_of_arg, 0);
+ DBUG_PRINT("info", ("Using %u as the number of extra bits", bits));
+
+ if (bits > 31)
+ {
+ argProcessingError= true;
+ error_str= "Too many extra Gci bits";
+ DBUG_PRINT("info", ("%s", error_str));
+ break;
+ }
+ /* Num bits seems ok */
+ args[no_args].extraGciBits = bits;
+ break;
+ }
case CFAT_END:
abort();
}
+ if (argProcessingError)
+ break;
+
no_args++;
}
@@ -3932,44 +3992,128 @@ set_conflict_fn(THD *thd, NDB_SHARE *sha
error_str= "garbage in the end";
break;
}
+ /* Update ptrs to conflict fn + # of args */
+ *conflictFn = &conflict_fns[i];
+ *maxArgs = no_args;
- /* setup the function */
- switch (fn.type)
- {
- case CFT_NDB_MAX:
- case CFT_NDB_OLD:
- case CFT_NDB_MAX_DEL_WIN:
- if (args[0].fieldno == (uint32)-1)
- break;
- if (slave_set_resolve_fn(thd, share, ndbtab, args[0].fieldno,
- fn.type, table))
- {
- /* wrong data type */
- my_snprintf(msg, msg_len,
- "column '%s' has wrong datatype",
- table->s->field[args[0].fieldno]->field_name);
- DBUG_PRINT("info", ("%s", msg));
- DBUG_RETURN(-1);
- }
- if (opt_ndb_extra_logging)
- {
- sql_print_information("NDB Slave: conflict_fn %s on attribute %s",
- fn.name,
- table->s->field[args[0].fieldno]->field_name);
- }
- break;
- case CFT_NDB_UNDEF:
- abort();
- }
DBUG_RETURN(0);
}
/* parse error */
my_snprintf(msg, msg_len, "%s, %s at '%s'",
- conflict_fn, error_str, ptr);
+ conflictFnSpec, error_str, ptr);
DBUG_PRINT("info", ("%s", msg));
DBUG_RETURN(-1);
}
+static int
+setup_conflict_fn(THD *thd, NDB_SHARE *share,
+ const NDBTAB *ndbtab,
+ char *msg, uint msg_len,
+ TABLE *table,
+ const st_conflict_fn_def* conflictFn,
+ const st_conflict_fn_arg* args,
+ const Uint32 numArgs)
+{
+ DBUG_ENTER("setup_conflict_fn");
+
+ /* setup the function */
+ switch (conflictFn->type)
+ {
+ case CFT_NDB_MAX:
+ case CFT_NDB_OLD:
+ case CFT_NDB_MAX_DEL_WIN:
+ {
+ if (numArgs != 1)
+ {
+ my_snprintf(msg, msg_len,
+ "Incorrect arguments to conflict function");
+ DBUG_PRINT("info", ("%s", msg));
+ DBUG_RETURN(-1);
+ }
+
+ uint resolve_col_sz= 0;
+
+ if (0 == (resolve_col_sz =
+ slave_check_resolve_col_type(ndbtab, args[0].fieldno)))
+ {
+ /* wrong data type */
+ slave_reset_conflict_fn(share);
+ my_snprintf(msg, msg_len,
+ "column '%s' has wrong datatype",
+ table->s->field[args[0].fieldno]->field_name);
+ DBUG_PRINT("info", ("%s", msg));
+ DBUG_RETURN(-1);
+ }
+
+ if (slave_set_resolve_fn(thd, share, ndbtab,
+ args[0].fieldno, resolve_col_sz,
+ conflictFn->type, table))
+ {
+ my_snprintf(msg, msg_len,
+ "unable to setup conflict resolution using column '%s'",
+ table->s->field[args[0].fieldno]->field_name);
+ DBUG_PRINT("info", ("%s", msg));
+ DBUG_RETURN(-1);
+ }
+ if (opt_ndb_extra_logging)
+ {
+ sql_print_information("NDB Slave: Table %s.%s using conflict_fn %s on attribute %s.",
+ table->s->db.str,
+ table->s->table_name.str,
+ conflictFn->name,
+ table->s->field[args[0].fieldno]->field_name);
+ }
+ break;
+ }
+ case CFT_NDB_EPOCH:
+ {
+ if (numArgs > 1)
+ {
+ my_snprintf(msg, msg_len,
+ "Too many arguments to conflict function");
+ DBUG_PRINT("info", ("%s", msg));
+ DBUG_RETURN(-1);
+ }
+
+ /* Check that table has required extra meta-columns */
+ /* Todo : Could warn if extra gcibits is insufficient to
+ * represent SavePeriod/EpochPeriod
+ */
+ if (ndbtab->getExtraRowGciBits() == 0)
+ sql_print_information("Ndb Slave : CFT_NDB_EPOCH, low epoch resolution");
+ if (ndbtab->getExtraRowAuthorBits() == 0)
+ {
+ my_snprintf(msg, msg_len, "No extra row author bits in table.");
+ DBUG_PRINT("info", ("%s", msg));
+ DBUG_RETURN(-1);
+ }
+
+ if (slave_set_resolve_fn(thd, share, ndbtab,
+ 0, // field_no
+ 0, // resolve_col_sz
+ conflictFn->type, table))
+ {
+ my_snprintf(msg, msg_len,
+ "unable to setup conflict resolution");
+ DBUG_PRINT("info", ("%s", msg));
+ DBUG_RETURN(-1);
+ }
+ if (opt_ndb_extra_logging)
+ {
+ sql_print_information("NDB Slave: Table %s.%s using conflict_fn %s.",
+ table->s->db.str,
+ table->s->table_name.str,
+ conflictFn->name);
+ }
+ break;
+ }
+ case CFT_NUMBER_OF_CFTS:
+ case CFT_NDB_UNDEF:
+ abort();
+ }
+ DBUG_RETURN(0);
+}
+
static const char *ndb_rep_db= NDB_REP_DB;
static const char *ndb_replication_table= NDB_REPLICATION_TABLE;
static const char *nrt_db= "db";
@@ -3977,17 +4121,26 @@ static const char *nrt_table_name= "tabl
static const char *nrt_server_id= "server_id";
static const char *nrt_binlog_type= "binlog_type";
static const char *nrt_conflict_fn= "conflict_fn";
+
+/*
+ ndbcluster_read_replication_table
+
+ This function reads the information for the supplied table from
+ the mysql.ndb_replication table.
+ Where there is no information (or no table), defaults are
+ returned.
+*/
int
-ndbcluster_read_binlog_replication(THD *thd, Ndb *ndb,
- NDB_SHARE *share,
- const NDBTAB *ndbtab,
- uint server_id,
- TABLE *table,
- bool do_set_binlog_flags)
+ndbcluster_read_replication_table(THD *thd, Ndb *ndb,
+ const char* db,
+ const char* table_name,
+ uint server_id,
+ Uint32* binlogFlags,
+ char** conflictFnSpec,
+ char* conflictFnBuffer,
+ Uint32 conflictFnBufferLen)
{
- DBUG_ENTER("ndbcluster_read_binlog_replication");
- const char *db= share->db;
- const char *table_name= share->table_name;
+ DBUG_ENTER("ndbcluster_read_binlog_replication_table");
NdbError ndberror;
int error= 0;
const char *error_str= "<none>";
@@ -4001,8 +4154,8 @@ ndbcluster_read_binlog_replication(THD *
dict->getNdbError().code == 4009))
{
DBUG_PRINT("info", ("No %s.%s table", ndb_rep_db, ndb_replication_table));
- if (do_set_binlog_flags)
- set_binlog_flags(share, NBT_DEFAULT);
+ *binlogFlags= NBT_DEFAULT;
+ *conflictFnSpec= NULL;
DBUG_RETURN(0);
}
const NDBCOL
@@ -4068,6 +4221,10 @@ ndbcluster_read_binlog_replication(THD *
char *ndb_conflict_fn[2]= {ndb_conflict_fn_buf, ndb_conflict_fn_buf+sz};
NdbOperation *op[2];
uint32 i, id= 0;
+ /* Read generic row (server_id==0) and specific row (server_id == our id)
+ * from ndb_replication.
+ * Specific overrides generic, if present
+ */
for (i= 0; i < 2; i++)
{
NdbOperation *_op;
@@ -4127,39 +4284,70 @@ ndbcluster_read_binlog_replication(THD *
if (col_binlog_type_rec_attr[1] == NULL ||
col_binlog_type_rec_attr[1]->isNULL())
{
+ /* No specific value, use generic */
col_binlog_type_rec_attr[1]= col_binlog_type_rec_attr[0];
ndb_binlog_type[1]= ndb_binlog_type[0];
}
if (col_conflict_fn_rec_attr[1] == NULL ||
col_conflict_fn_rec_attr[1]->isNULL())
{
+ /* No specific value, use generic */
col_conflict_fn_rec_attr[1]= col_conflict_fn_rec_attr[0];
ndb_conflict_fn[1]= ndb_conflict_fn[0];
}
- if (do_set_binlog_flags)
+ if (col_binlog_type_rec_attr[1] == NULL ||
+ col_binlog_type_rec_attr[1]->isNULL())
{
- if (col_binlog_type_rec_attr[1] == NULL ||
- col_binlog_type_rec_attr[1]->isNULL())
- set_binlog_flags(share, NBT_DEFAULT);
- else
- set_binlog_flags(share, (enum Ndb_binlog_type) ndb_binlog_type[1]);
+ DBUG_PRINT("info", ("No binlog flag value, using default"));
+ /* No value */
+ *binlogFlags= NBT_DEFAULT;
}
- if (table)
+ else
{
- if (col_conflict_fn_rec_attr[1] == NULL ||
- col_conflict_fn_rec_attr[1]->isNULL())
- slave_reset_conflict_fn(share); /* no conflict_fn */
- else if (set_conflict_fn(thd, share, ndbtab,
- col_conflict_fn, ndb_conflict_fn[1],
- tmp_buf, sizeof(tmp_buf), table))
+ DBUG_PRINT("info", ("Taking binlog flag value from the table"));
+ *binlogFlags= (enum Ndb_binlog_type) ndb_binlog_type[1];
+ }
+
+ if (col_conflict_fn_rec_attr[1] == NULL ||
+ col_conflict_fn_rec_attr[1]->isNULL())
+ {
+ /* No conflict function */
+ *conflictFnSpec = NULL;
+ }
+ else
+ {
+ const char* conflict_fn = ndb_conflict_fn[1];
+ uint len= 0;
+ switch (col_conflict_fn->getArrayType())
+ {
+ case NDBCOL::ArrayTypeShortVar:
+ len= *(uchar*)conflict_fn;
+ conflict_fn++;
+ break;
+ case NDBCOL::ArrayTypeMediumVar:
+ len= uint2korr(conflict_fn);
+ conflict_fn+= 2;
+ break;
+ default:
+ abort();
+ }
+ if ((len + 1) > conflictFnBufferLen)
{
- error_str= tmp_buf;
- error= 1;
ndb->closeTransaction(trans);
+ error= -2;
+ error_str= "Conflict function specification too long.";
goto err;
}
+ memcpy(conflictFnBuffer, conflict_fn, len);
+ conflictFnBuffer[len] = '\0';
+ *conflictFnSpec = conflictFnBuffer;
}
+
+ DBUG_PRINT("info", ("Retrieved Binlog flags : %u and function spec : %s",
+ *binlogFlags, (*conflictFnSpec != NULL ?*conflictFnSpec:
+ "NULL")));
+
ndb->closeTransaction(trans);
DBUG_RETURN(0);
@@ -4168,14 +4356,7 @@ ndbcluster_read_binlog_replication(THD *
err:
DBUG_PRINT("info", ("error %d, error_str %s, ndberror.code %u",
error, error_str, ndberror.code));
- if (error > 0)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_CONFLICT_FN_PARSE_ERROR,
- ER(ER_CONFLICT_FN_PARSE_ERROR),
- error_str);
- }
- else if (error < 0)
+ if (error < 0)
{
char msg[FN_REFLEN];
switch (error)
@@ -4207,8 +4388,9 @@ err:
ER(ER_ILLEGAL_HA_CREATE_OPTION),
ndbcluster_hton_name, msg);
}
- if (do_set_binlog_flags)
- set_binlog_flags(share, NBT_DEFAULT);
+ *binlogFlags= NBT_DEFAULT;
+ *conflictFnSpec= NULL;
+
if (ndberror.code && opt_ndb_extra_logging)
{
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
@@ -4220,6 +4402,185 @@ err:
}
DBUG_RETURN(ndberror.code);
}
+
+/*
+ ndbcluster_get_binlog_replication_info
+
+ This function retrieves the data for the given table
+ from the ndb_replication table.
+
+ If the table is not found, or the table does not exist,
+ then defaults are returned.
+*/
+int
+ndbcluster_get_binlog_replication_info(THD *thd, Ndb *ndb,
+ const char* db,
+ const char* table_name,
+ uint server_id,
+ const TABLE *table,
+ Uint32* binlogFlags,
+ st_conflict_fn_def** conflictFn,
+ st_conflict_fn_arg* args,
+ Uint32* numArgs)
+{
+ DBUG_ENTER("ndbcluster_get_binlog_replication_info");
+
+ /* Override for ndb_apply_status when logging */
+ if (opt_ndb_log_apply_status)
+ {
+ 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.
+ */
+ 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);
+ *binlogFlags = NBT_FULL;
+ *conflictFn = NULL;
+ *numArgs = 0;
+ DBUG_RETURN(0);
+ }
+ }
+
+ const Uint32 MaxConflictFnSpecLen = 256;
+ char conflictFnBuffer[MaxConflictFnSpecLen];
+ char* conflictFnSpec;
+
+ if (ndbcluster_read_replication_table(thd,
+ ndb,
+ db,
+ table_name,
+ server_id,
+ binlogFlags,
+ &conflictFnSpec,
+ conflictFnBuffer,
+ MaxConflictFnSpecLen) != 0)
+ {
+ DBUG_RETURN(-1);
+ }
+
+ if (table != NULL)
+ {
+ if (conflictFnSpec != NULL)
+ {
+ char tmp_buf[FN_REFLEN];
+
+ if (parse_conflict_fn_spec(conflictFnSpec,
+ conflictFn,
+ args,
+ numArgs,
+ table,
+ tmp_buf,
+ sizeof(tmp_buf)) != 0)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_CONFLICT_FN_PARSE_ERROR,
+ ER(ER_CONFLICT_FN_PARSE_ERROR),
+ tmp_buf);
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ {
+ /* No conflict function specified */
+ conflictFn= NULL;
+ numArgs= 0;
+ }
+ }
+
+ DBUG_RETURN(0);
+}
+
+int
+ndbcluster_apply_binlog_replication_info(THD *thd,
+ NDB_SHARE *share,
+ const NDBTAB* ndbtab,
+ TABLE* table,
+ const st_conflict_fn_def* conflictFn,
+ const st_conflict_fn_arg* args,
+ Uint32 numArgs,
+ bool doSetBinlogFlags,
+ Uint32 binlogFlags)
+{
+ DBUG_ENTER("ndbcluster_apply_binlog_replication_info");
+ char tmp_buf[FN_REFLEN];
+
+ if (doSetBinlogFlags)
+ {
+ DBUG_PRINT("info", ("Setting binlog flags to %u", binlogFlags));
+ set_binlog_flags(share, (enum Ndb_binlog_type)binlogFlags);
+ }
+
+ if (conflictFn != NULL)
+ {
+ if (setup_conflict_fn(thd, share,
+ ndbtab,
+ tmp_buf, sizeof(tmp_buf),
+ table,
+ conflictFn,
+ args,
+ numArgs) != 0)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_CONFLICT_FN_PARSE_ERROR,
+ ER(ER_CONFLICT_FN_PARSE_ERROR),
+ tmp_buf);
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ {
+ /* No conflict function specified */
+ slave_reset_conflict_fn(share);
+ }
+
+ DBUG_RETURN(0);
+}
+
+int
+ndbcluster_read_binlog_replication(THD *thd, Ndb *ndb,
+ NDB_SHARE *share,
+ const NDBTAB *ndbtab,
+ uint server_id,
+ TABLE *table,
+ bool do_set_binlog_flags)
+{
+ DBUG_ENTER("ndbcluster_read_binlog_replication");
+ Uint32 binlogFlags;
+ st_conflict_fn_def* conflictFn= NULL;
+ st_conflict_fn_arg args[MaxConflictArgs];
+ Uint32 numArgs = MaxConflictArgs;
+
+ if ((ndbcluster_get_binlog_replication_info(thd, ndb,
+ share->db,
+ share->table_name,
+ server_id,
+ table,
+ &binlogFlags,
+ &conflictFn,
+ args,
+ &numArgs) != 0) ||
+ (ndbcluster_apply_binlog_replication_info(thd,
+ share,
+ ndbtab,
+ table,
+ conflictFn,
+ args,
+ numArgs,
+ do_set_binlog_flags,
+ binlogFlags) != 0))
+ {
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
#endif /* HAVE_NDB_BINLOG */
bool
@@ -5371,7 +5732,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;
@@ -5380,15 +5742,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;
@@ -5397,43 +5793,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;
+ }
}
/*
@@ -5480,8 +5910,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));
{
@@ -5503,8 +5936,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));
{
@@ -5544,8 +5980,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));
{
@@ -6274,6 +6713,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)
{
/*
@@ -6319,6 +6759,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;
@@ -6472,7 +6913,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);
@@ -6511,17 +6952,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";
@@ -6799,4 +7257,162 @@ void ndbcluster_anyvalue_set_serverid(Ui
anyValue |= (serverId & opt_server_id_mask);
}
+#ifdef HAVE_NDB_BINLOG
+extern Master_info *active_mi;
+#endif
+
+void
+ha_ndbcluster::check_slave_status(THD* thd)
+{
+ DBUG_ENTER("check_slave_status");
+
+#ifdef HAVE_NDB_BINLOG
+ if (thd->slave_thread)
+ {
+ Uint32 runId = active_mi->rli.slave_run_id;
+ DBUG_PRINT("info", ("Slave SQL thread run id is %u",
+ runId));
+ if (unlikely(runId != g_ndb_slave_sql_run_id))
+ {
+ DBUG_PRINT("info", ("Slave run id changed from %u, "
+ "treating as Slave restart",
+ g_ndb_slave_sql_run_id));
+ g_ndb_slave_sql_run_id = runId;
+
+ /* Always try to load the Max Replicated Epoch info
+ * first.
+ * Could be made optional if it's a problem
+ */
+ {
+ /*
+ Load highest replicated epoch from a local
+ MySQLD from the cluster.
+ */
+ DBUG_PRINT("info", ("Loading applied epoch information from %s",
+ NDB_APPLY_TABLE));
+ NdbError ndb_error;
+ Uint32 localServerIds[ MAX_API_NODES ];
+ Uint32 localServerIdCount;
+ NdbOperation* epochReadOps[ MAX_API_NODES ];
+ Uint64 epochs[ MAX_API_NODES ];
+ Uint64 highestAppliedEpoch= 0;
+
+ /* Copy from globals to minimise change of race with variable-setter */
+ memcpy(localServerIds, cluster_server_ids, sizeof(localServerIds));
+ localServerIdCount = cluster_server_id_count;
+
+ while(1)
+ {
+ Ndb* ndb= check_ndb_in_thd(thd);
+ NDBDICT* dict= ndb->getDictionary();
+ NdbTransaction* trans= NULL;
+ ndb->setDatabaseName(NDB_REP_DB);
+ Ndb_table_guard ndbtab_g(dict, NDB_APPLY_TABLE);
+
+ const NDBTAB* ndbtab= ndbtab_g.get_table();
+ if (unlikely(ndbtab == NULL))
+ {
+ ndb_error = dict->getNdbError();
+ break;
+ }
+
+ trans= ndb->startTransaction();
+ if (unlikely(trans == NULL))
+ {
+ ndb_error = ndb->getNdbError();
+ break;
+ }
+
+ for (Uint32 n=0; n < localServerIdCount; n++)
+ {
+ NdbOperation* op= trans->getNdbOperation(ndbtab);
+ if (unlikely(op == NULL))
+ {
+ ndb_error = trans->getNdbError();
+ break;
+ }
+
+ if (unlikely((op->readTuple(NdbOperation::LM_CommittedRead) != 0) ||
+ (op->setAbortOption(NdbOperation::AO_IgnoreError) != 0) ||
+ // TODO : ServerId column# constant
+ (op->equal(Uint32(0), localServerIds[n]) != 0) ||
+ // TODO : Epoch column# constant
+ (op->getValue(1, (char*) &epochs[n]) == NULL)))
+ {
+ ndb_error = op->getNdbError();
+ break;
+ }
+
+ epochReadOps[n] = op;
+ DBUG_PRINT("info", ("Defined applied epoch read op for serverid %u",
+ localServerIds[n]));
+ }
+ if (ndb_error.code != 0)
+ break;
+
+ if (trans->execute(NdbTransaction::Commit))
+ {
+ ndb_error= trans->getNdbError();
+ break;
+ }
+
+ for (Uint32 n=0; n < localServerIdCount; n++)
+ {
+ const NdbOperation* op = epochReadOps[n];
+ if (op->getNdbError().code == 0)
+ {
+ DBUG_PRINT("info", ("Cluster contains epoch %llu from serverid %u",
+ epochs[n], localServerIds[n]));
+ if (epochs[n] > highestAppliedEpoch)
+ {
+ DBUG_PRINT("info", ("New highest epoch is %llu", epochs[n]));
+ highestAppliedEpoch = epochs[n];
+ }
+ }
+ else
+ {
+ if (likely(op->getNdbError().code == 626))
+ {
+ DBUG_PRINT("info", ("No data present for serverid %u",
+ localServerIds[n]));
+ }
+ else
+ {
+ ndb_error = op->getNdbError();
+ break;
+ }
+ }
+ }
+
+ trans->close();
+ break;
+ } // while(1);
+
+ if (ndb_error.code != 0)
+ {
+ sql_print_warning("NDB Slave : Could not determine maximum replicated epoch from %s.%s "
+ "at Slave start, error %u %s",
+ NDB_REP_DB,
+ NDB_APPLY_TABLE,
+ ndb_error.code, ndb_error.message);
+ }
+
+ /*
+ Set Global status variable to the Highest Applied Epoch from
+ the Cluster DB.
+ If none was found, this will be zero.
+ */
+ g_ndb_status_max_rep_epoch = highestAppliedEpoch;
+ sql_print_information("NDB Slave : MaxReplicatedEpoch set to %llu (%u/%u) at Slave start",
+ g_ndb_status_max_rep_epoch,
+ (Uint32)(g_ndb_status_max_rep_epoch >> 32),
+ (Uint32)(g_ndb_status_max_rep_epoch & 0xffffffff));
+ } // Load highest replicated epoch
+ } // New Slave SQL thread run id
+ } // In slave SQL thread
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
#endif
=== modified file 'sql/ha_ndbcluster_binlog.h'
--- a/sql/ha_ndbcluster_binlog.h 2010-07-02 11:01:48 +0000
+++ b/sql/ha_ndbcluster_binlog.h 2010-09-22 10:49:11 +0000
@@ -95,8 +95,7 @@ static const char *ha_ndb_ext=".ndb";
#define NDB_EXCEPTIONS_TABLE_SUFFIX "$EX"
#define NDB_EXCEPTIONS_TABLE_SUFFIX_LOWER "$ex"
-const uint error_conflict_fn_old_violation= 9998;
-const uint error_conflict_fn_max_violation= 9999;
+const uint error_conflict_fn_violation= 9999;
#endif /* HAVE_NDB_BINLOG */
@@ -239,6 +238,26 @@ void ndb_rep_event_name(String *event_na
const char *db, const char *tbl, my_bool full);
#ifdef HAVE_NDB_BINLOG
int
+ndbcluster_get_binlog_replication_info(THD *thd, Ndb *ndb,
+ const char* db,
+ const char* table_name,
+ uint server_id,
+ const TABLE *table,
+ Uint32* binlogFlags,
+ st_conflict_fn_def** conflictFn,
+ st_conflict_fn_arg* args,
+ Uint32* numArgs);
+int
+ndbcluster_apply_binlog_replication_info(THD *thd,
+ NDB_SHARE *share,
+ const NDBTAB* ndbtab,
+ TABLE* table,
+ const st_conflict_fn_def* conflictFn,
+ const st_conflict_fn_arg* args,
+ Uint32 numArgs,
+ bool doSetBinlogFlags,
+ Uint32 binlogFlags);
+int
ndbcluster_read_binlog_replication(THD *thd, Ndb *ndb,
NDB_SHARE *share,
const NDBTAB *ndbtab,
=== modified file 'storage/ndb/include/kernel/AttributeHeader.hpp'
--- a/storage/ndb/include/kernel/AttributeHeader.hpp 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/include/kernel/AttributeHeader.hpp 2010-09-22 10:49:11 +0000
@@ -63,6 +63,17 @@ public:
STATIC_CONST( FRAGMENT_FREE_EXTENT_SPACE = 0xFFEB );
/**
+ * 64-bit row gci (extending lower if not sufficient bits)
+ * read-only
+ */
+ STATIC_CONST( ROW_GCI64 = 0xFFEA);
+
+ /**
+ * Row author... autoset to 0, can be over written
+ */
+ STATIC_CONST( ROW_AUTHOR = 0xFFE9);
+
+ /**
* Optimize pseudo column and optimization options
*/
STATIC_CONST( OPTIMIZE = 0xFFE0 ); //pseudo column id to optimize
=== modified file 'storage/ndb/include/kernel/kernel_types.h'
--- a/storage/ndb/include/kernel/kernel_types.h 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/include/kernel/kernel_types.h 2010-09-22 10:49:11 +0000
@@ -36,9 +36,7 @@ enum Operation_t {
,ZDELETE = 3
,ZWRITE = 4
,ZREAD_EX = 5
-#if 0
- ,ZREAD_CONSISTENT = 6
-#endif
+ ,ZREFRESH = 6
,ZUNLOCK = 7
};
=== modified file 'storage/ndb/include/kernel/signaldata/CreateTab.hpp'
--- a/storage/ndb/include/kernel/signaldata/CreateTab.hpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/include/kernel/signaldata/CreateTab.hpp 2010-09-22 10:49:11 +0000
@@ -24,7 +24,7 @@
struct CreateTabReq
{
STATIC_CONST( SignalLength = 6 );
- STATIC_CONST( SignalLengthLDM = 6 + 10 );
+ STATIC_CONST( SignalLengthLDM = 6 + 11 );
enum RequestType {
};
@@ -49,6 +49,7 @@ struct CreateTabReq
Uint32 noOfKeyAttr;
Uint32 checksumIndicator;
Uint32 GCPIndicator;
+ Uint32 extraRowAuthorBits;
SECTION( DICT_TAB_INFO = 0 );
SECTION( FRAGMENTATION = 1 );
=== modified file 'storage/ndb/include/kernel/signaldata/CreateTable.hpp'
--- a/storage/ndb/include/kernel/signaldata/CreateTable.hpp 2010-04-01 05:20:25 +0000
+++ b/storage/ndb/include/kernel/signaldata/CreateTable.hpp 2010-09-22 10:49:11 +0000
@@ -76,7 +76,8 @@ struct CreateTableRef {
OutOfStringBuffer = 773,
NoLoggingTemporaryTable = 778,
InvalidHashMap = 790,
- TableDefinitionTooBig = 793
+ TableDefinitionTooBig = 793,
+ FeatureRequiresUpgrade = 794
};
Uint32 senderRef;
=== modified file 'storage/ndb/include/kernel/signaldata/DictTabInfo.hpp'
--- a/storage/ndb/include/kernel/signaldata/DictTabInfo.hpp 2010-05-06 10:15:24 +0000
+++ b/storage/ndb/include/kernel/signaldata/DictTabInfo.hpp 2010-09-22 10:49:11 +0000
@@ -149,6 +149,9 @@ public:
HashMapObjectId = 153,
HashMapVersion = 154,
+ ExtraRowGCIBits = 155,
+ ExtraRowAuthorBits = 156,
+
TableEnd = 999,
AttributeName = 1000, // String, Mandatory
@@ -377,6 +380,9 @@ public:
Uint32 HashMapObjectId;
Uint32 HashMapVersion;
+
+ Uint32 ExtraRowGCIBits;
+ Uint32 ExtraRowAuthorBits;
Table() {}
void init();
=== modified file 'storage/ndb/include/ndb_version.h.in'
--- a/storage/ndb/include/ndb_version.h.in 2010-08-26 12:33:33 +0000
+++ b/storage/ndb/include/ndb_version.h.in 2010-09-22 10:49:11 +0000
@@ -502,4 +502,25 @@ ndbd_suma_stop_me(Uint32 x)
}
}
+// TODO : Check these before pushing
+#define NDBD_TUP_EXTRABITS_70 NDB_MAKE_VERSION(7,0,17)
+#define NDBD_TUP_EXTRABITS_71 NDB_MAKE_VERSION(7,1,6)
+
+static
+inline
+int
+ndb_tup_extrabits(Uint32 x)
+{
+ {
+ const Uint32 major = (x >> 16) & 0xFF;
+ const Uint32 minor = (x >> 8) & 0xFF;
+
+ if (major == 7 && minor == 0)
+ {
+ return x >= NDBD_TUP_EXTRABITS_70;
+ }
+ return x >= NDBD_TUP_EXTRABITS_71;
+ }
+}
+
#endif
=== modified file 'storage/ndb/include/ndbapi/NdbDictionary.hpp'
--- a/storage/ndb/include/ndbapi/NdbDictionary.hpp 2010-09-13 14:31:30 +0000
+++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp 2010-09-22 10:49:11 +0000
@@ -603,6 +603,8 @@ public:
static const Column * RECORDS_IN_RANGE;
static const Column * ROWID;
static const Column * ROW_GCI;
+ static const Column * ROW_GCI64;
+ static const Column * ROW_AUTHOR;
static const Column * ANY_VALUE;
static const Column * COPY_ROWID;
static const Column * LOCK_REF;
@@ -1041,6 +1043,18 @@ public:
* passing NULL pointer will equal to bitmap with all columns set
*/
int checkColumns(const Uint32* bitmap, unsigned len_in_bytes) const;
+
+ /**
+ * Get/set extra GCI bits (max 31)
+ */
+ void setExtraRowGciBits(Uint32);
+ Uint32 getExtraRowGciBits() const;
+
+ /**
+ * Get/set extra row author bits (max 31)
+ */
+ void setExtraRowAuthorBits(Uint32);
+ Uint32 getExtraRowAuthorBits() const;
#endif
// these 2 are not de-doxygenated
=== modified file 'storage/ndb/include/ndbapi/NdbOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp 2010-06-08 14:37:15 +0000
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp 2010-09-22 10:49:11 +0000
@@ -915,6 +915,7 @@ public:
DeleteRequest = 3, ///< Delete Operation
WriteRequest = 4, ///< Write Operation
ReadExclusive = 5, ///< Read exclusive
+ RefreshRequest = 6, ///<
UnlockRequest = 7, ///< Unlock operation
OpenScanRequest, ///< Scan Operation
OpenRangeScanRequest, ///< Range scan operation
=== modified file 'storage/ndb/include/ndbapi/NdbTransaction.hpp'
--- a/storage/ndb/include/ndbapi/NdbTransaction.hpp 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/include/ndbapi/NdbTransaction.hpp 2010-09-22 10:49:11 +0000
@@ -747,6 +747,12 @@ public:
const NdbOperation::OperationOptions *opts = 0,
Uint32 sizeOfOptions = 0);
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ const NdbOperation *refreshTuple(const NdbRecord *key_rec, const char *key_row,
+ const NdbOperation::OperationOptions *opts = 0,
+ Uint32 sizeOfOptions = 0);
+#endif
+
/**
* Scan a table, using NdbRecord to read out column data.
*
=== modified file 'storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp 2010-04-29 14:52:05 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp 2010-09-22 10:49:11 +0000
@@ -73,6 +73,8 @@ DictTabInfo::TableMapping[] = {
DTIMAP(Table, SingleUserMode, SingleUserMode),
DTIMAP(Table, HashMapObjectId, HashMapObjectId),
DTIMAP(Table, HashMapVersion, HashMapVersion),
+ DTIMAP(Table, ExtraRowGCIBits, ExtraRowGCIBits),
+ DTIMAP(Table, ExtraRowAuthorBits, ExtraRowAuthorBits),
DTIBREAK(AttributeName)
};
@@ -182,6 +184,9 @@ DictTabInfo::Table::init(){
HashMapObjectId = RNIL;
HashMapVersion = RNIL;
+
+ ExtraRowGCIBits = 0;
+ ExtraRowAuthorBits = 0;
}
void
=== modified file 'storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp 2010-09-22 10:49:11 +0000
@@ -37,6 +37,7 @@ printTCKEYREQ(FILE * output, const Uint3
sig->getOperationType(requestInfo) == ZDELETE ? "Delete" :
sig->getOperationType(requestInfo) == ZWRITE ? "Write" :
sig->getOperationType(requestInfo) == ZUNLOCK ? "Unlock" :
+ sig->getOperationType(requestInfo) == ZREFRESH ? "Refresh" :
"Unknown");
{
if(sig->getDirtyFlag(requestInfo)){
=== modified file 'storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp'
--- a/storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp 2010-03-02 17:49:20 +0000
+++ b/storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp 2010-09-22 10:49:11 +0000
@@ -140,7 +140,7 @@ ndbout << "Ptr: " << ptr.p->word32 << "
/**
* Check kernel_types for other operation types
*/
-#define ZSCAN_OP 6
+#define ZSCAN_OP 8
#define ZSCAN_REC_SIZE 256
#define ZSTAND_BY 2
#define ZTABLESIZE 16
@@ -642,6 +642,7 @@ public:
class Dblqh* c_lqh;
void execACCMINUPDATE(Signal* signal);
+ void removerow(Uint32 op, const Local_key*);
private:
BLOCK_DEFINES(Dbacc);
=== modified file 'storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp 2010-08-20 11:10:25 +0000
+++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp 2010-09-22 10:49:11 +0000
@@ -973,9 +973,12 @@ void Dbacc::initOpRec(Signal* signal)
Uint32 readFlag = (((Treqinfo >> 4) & 0x3) == 0); // Only 1 if Read
Uint32 dirtyFlag = (((Treqinfo >> 6) & 0x1) == 1); // Only 1 if Dirty
Uint32 dirtyReadFlag = readFlag & dirtyFlag;
+ Uint32 operation = Treqinfo & 0xf;
+ if (operation == ZREFRESH)
+ operation = ZWRITE;
Uint32 opbits = 0;
- opbits |= Treqinfo & 0x7;
+ opbits |= operation;
opbits |= ((Treqinfo >> 4) & 0x3) ? (Uint32) Operationrec::OP_LOCK_MODE : 0;
opbits |= ((Treqinfo >> 4) & 0x3) ? (Uint32) Operationrec::OP_ACC_LOCK_MODE : 0;
opbits |= (dirtyReadFlag) ? (Uint32) Operationrec::OP_DIRTY_READ : 0;
@@ -2318,6 +2321,34 @@ void Dbacc::execACCMINUPDATE(Signal* sig
ndbrequire(false);
}//Dbacc::execACCMINUPDATE()
+void
+Dbacc::removerow(Uint32 opPtrI, const Local_key* key)
+{
+ jamEntry();
+ operationRecPtr.i = opPtrI;
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ Uint32 opbits = operationRecPtr.p->m_op_bits;
+ fragrecptr.i = operationRecPtr.p->fragptr;
+
+ opbits |= Operationrec::OP_ELEMENT_DISAPPEARED;
+ opbits &= ~Uint32(Operationrec::OP_COMMIT_DELETE_CHECK);
+ operationRecPtr.p->m_op_bits = opbits;
+
+#ifdef VM_TRACE
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (likely(fragrecptr.p->localkeylen == 1))
+ {
+ ndbrequire(operationRecPtr.p->localdata[0] == key->ref());
+ return;
+ }
+ else if (fragrecptr.p->localkeylen == 2)
+ {
+ ndbrequire(operationRecPtr.p->localdata[0] == key->m_page_no);
+ ndbrequire(operationRecPtr.p->localdata[1] == key->m_page_idx);
+ }
+#endif
+}//Dbacc::execACCMINUPDATE()
+
/* ******************--------------------------------------------------------------- */
/* ACC_COMMITREQ COMMIT TRANSACTION */
/* SENDER: LQH, LEVEL B */
=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp 2010-09-21 07:36:08 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp 2010-09-22 10:49:11 +0000
@@ -721,6 +721,8 @@ Dbdict::packTableIntoPages(SimplePropert
w.add(DictTabInfo::MinRowsHigh, tablePtr.p->minRowsHigh);
w.add(DictTabInfo::SingleUserMode, tablePtr.p->singleUserMode);
w.add(DictTabInfo::HashMapObjectId, tablePtr.p->hashMapObjectId);
+ w.add(DictTabInfo::ExtraRowGCIBits, tablePtr.p->m_extra_row_gci_bits);
+ w.add(DictTabInfo::ExtraRowAuthorBits, tablePtr.p->m_extra_row_author_bits);
if (tablePtr.p->hashMapObjectId != RNIL)
{
@@ -4897,6 +4899,8 @@ void Dbdict::handleTabInfoInit(SimplePro
tablePtr.p->singleUserMode = c_tableDesc.SingleUserMode;
tablePtr.p->hashMapObjectId = c_tableDesc.HashMapObjectId;
tablePtr.p->hashMapVersion = c_tableDesc.HashMapVersion;
+ tablePtr.p->m_extra_row_gci_bits = c_tableDesc.ExtraRowGCIBits;
+ tablePtr.p->m_extra_row_author_bits = c_tableDesc.ExtraRowAuthorBits;
tabRequire(tablePtr.p->noOfAttributes <= MAX_ATTRIBUTES_IN_TABLE,
CreateTableRef::NoMoreAttributeRecords); // bad error code!
@@ -5414,6 +5418,27 @@ void Dbdict::handleTabInfo(SimplePropert
tabRequire(keyLength > 0,
CreateTableRef::InvalidPrimaryKeySize);
+ /* Check that all currently running nodes data support
+ * table features
+ */
+ for (Uint32 nodeId=1; nodeId < MAX_NODES; nodeId++)
+ {
+ const NodeInfo& ni = getNodeInfo(nodeId);
+
+ if (ni.m_connected &&
+ (ni.m_type == NODE_TYPE_DB))
+ {
+ /* Check that all nodes support extra bits */
+ if (tablePtr.p->m_extra_row_gci_bits ||
+ tablePtr.p->m_extra_row_author_bits)
+ {
+ tabRequire(ndb_tup_extrabits(ni.m_version),
+ CreateTableRef::FeatureRequiresUpgrade);
+ }
+ }
+ }
+
+
if(tablePtr.p->m_tablespace_id != RNIL || counts[3] || counts[4])
{
FilegroupPtr tablespacePtr;
@@ -6116,8 +6141,9 @@ Dbdict::createTab_local(Signal* signal,
req->noOfNullAttributes = tabPtr.p->noOfNullBits;
req->noOfKeyAttr = tabPtr.p->noOfPrimkey;
req->checksumIndicator = 1;
- req->GCPIndicator = 1;
+ req->GCPIndicator = 1 + tabPtr.p->m_extra_row_gci_bits;
req->noOfAttributes = tabPtr.p->noOfAttributes;
+ req->extraRowAuthorBits = tabPtr.p->m_extra_row_author_bits;
sendSignal(DBLQH_REF, GSN_CREATE_TAB_REQ, signal,
CreateTabReq::SignalLengthLDM, JBB);
=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp 2010-08-13 09:31:43 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp 2010-09-22 10:49:11 +0000
@@ -281,6 +281,8 @@ public:
TR_Temporary = 0x8,
TR_ForceVarPart = 0x10
};
+ Uint8 m_extra_row_gci_bits;
+ Uint8 m_extra_row_author_bits;
Uint16 m_bits;
/* Number of attibutes in table */
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp 2010-08-30 09:51:49 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp 2010-09-22 10:49:11 +0000
@@ -3073,6 +3073,7 @@ public:
bool is_same_trans(Uint32 opId, Uint32 trid1, Uint32 trid2);
void get_op_info(Uint32 opId, Uint32 *hash, Uint32* gci_hi, Uint32* gci_lo);
void accminupdate(Signal*, Uint32 opPtrI, const Local_key*);
+ void accremoverow(Signal*, Uint32 opPtrI, const Local_key*);
/**
*
@@ -3261,6 +3262,16 @@ Dblqh::accminupdate(Signal* signal, Uint
}
inline
+void
+Dblqh::accremoverow(Signal* signal, Uint32 opId, const Local_key* key)
+{
+ TcConnectionrecPtr regTcPtr;
+ regTcPtr.i= opId;
+ ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
+ c_acc->removerow(regTcPtr.p->accConnectrec, key);
+}
+
+inline
bool
Dblqh::TRACE_OP_CHECK(const TcConnectionrec* regTcPtr)
{
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2010-08-31 10:55:01 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2010-09-22 10:49:11 +0000
@@ -144,6 +144,7 @@ operator<<(NdbOut& out, Operation_t op)
case ZDELETE: out << "DELETE"; break;
case ZWRITE: out << "WRITE"; break;
case ZUNLOCK: out << "UNLOCK"; break;
+ case ZREFRESH: out << "REFRESH"; break;
}
return out;
}
@@ -4371,6 +4372,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal
regTcPtr->lockType =
op == ZREAD_EX ? ZUPDATE :
(Operation_t) op == ZWRITE ? ZINSERT :
+ (Operation_t) op == ZREFRESH ? ZINSERT :
(Operation_t) op == ZUNLOCK ? ZREAD : // lockType not relevant for unlock req
(Operation_t) op;
}
@@ -4494,8 +4496,11 @@ void Dblqh::execLQHKEYREQ(Signal* signal
sig2 = lqhKeyReq->variableData[nextPos + 0];
sig3 = cnewestGci;
+ /* If gci_hi provided, take it and set gci_lo to max value
+ * Otherwise, it will be decided by TUP at commit time as normal
+ */
regTcPtr->gci_hi = LqhKeyReq::getGCIFlag(Treqinfo) ? sig2 : sig3;
- regTcPtr->gci_lo = 0;
+ regTcPtr->gci_lo = LqhKeyReq::getGCIFlag(Treqinfo) ? ~Uint32(0) : 0;
nextPos += LqhKeyReq::getGCIFlag(Treqinfo);
if (LqhKeyReq::getRowidFlag(Treqinfo))
@@ -4878,6 +4883,7 @@ void Dblqh::prepareContinueAfterBlockedL
case ZINSERT: TRACENR("INSERT"); break;
case ZDELETE: TRACENR("DELETE"); break;
case ZUNLOCK: TRACENR("UNLOCK"); break;
+ case ZREFRESH: TRACENR("REFRESH"); break;
default: TRACENR("<Unknown: " << regTcPtr->operation << ">"); break;
}
@@ -4927,7 +4933,6 @@ Dblqh::exec_acckeyreq(Signal* signal, Tc
Uint32 taccreq;
regTcPtr.p->transactionState = TcConnectionrec::WAIT_ACC;
taccreq = regTcPtr.p->operation;
- taccreq = taccreq + (regTcPtr.p->opSimple << 3);
taccreq = taccreq + (regTcPtr.p->lockType << 4);
taccreq = taccreq + (regTcPtr.p->dirtyOp << 6);
taccreq = taccreq + (regTcPtr.p->replicaType << 7);
@@ -5092,7 +5097,7 @@ Dblqh::handle_nr_copy(Signal* signal, Pt
if (match)
{
jam();
- if (op != ZDELETE)
+ if (op != ZDELETE && op != ZREFRESH)
{
if (TRACENR_FLAG)
TRACENR(" Changing from to ZWRITE" << endl);
@@ -5100,7 +5105,9 @@ Dblqh::handle_nr_copy(Signal* signal, Pt
}
goto run;
}
-
+
+ ndbassert(!match && op == ZINSERT);
+
/**
* 1) Delete row at specified rowid (if len > 0)
* 2) Delete specified row at different rowid (if exists)
@@ -5711,7 +5718,7 @@ void Dblqh::execACCKEYCONF(Signal* signa
LqhKeyReq::setOperation(requestInfo, op);
regTcPtr->reqinfo = requestInfo;
}
- }//if
+ }
/* ------------------------------------------------------------------------
* IT IS NOW TIME TO CONTACT THE TUPLE MANAGER. THE TUPLE MANAGER NEEDS THE
@@ -5808,7 +5815,7 @@ Dblqh::acckeyconf_tupkeyreq(Signal* sign
TRACE_OP(regTcPtr, "TUPKEYREQ");
- regTcPtr->m_use_rowid |= (op == ZINSERT);
+ regTcPtr->m_use_rowid |= (op == ZINSERT || op == ZREFRESH);
regTcPtr->m_row_id.m_page_no = page_no;
regTcPtr->m_row_id.m_page_idx = page_idx;
@@ -11522,6 +11529,8 @@ Dblqh::execPREPARE_COPY_FRAG_REQ(Signal*
fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION;
fragptr.p->logFlag = Fragrecord::STATE_FALSE;
+ c_tup->start_copy_frag(req.tableId, req.fragId);
+
c_tup->get_frag_info(req.tableId, req.fragId, &max_page);
}
@@ -12508,6 +12517,8 @@ void Dblqh::execCOPY_ACTIVEREQ(Signal* s
fragptr.p->logFlag = Fragrecord::STATE_TRUE;
}
}
+
+ c_tup->complete_copy_frag(tabptr.i, fragptr.i);
if (flags & CopyActiveReq::CAR_NO_WAIT)
{
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2010-08-31 10:55:01 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2010-09-22 10:49:11 +0000
@@ -2991,6 +2991,7 @@ void Dbtc::execTCKEYREQ(Signal* signal)
case ZINSERT:
case ZDELETE:
case ZWRITE:
+ case ZREFRESH:
jam();
break;
default:
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2010-09-07 09:54:47 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2010-09-22 10:49:11 +0000
@@ -421,6 +421,8 @@ struct Fragoperrec {
Uint32 attributeCount;
Uint32 charsetIndex;
Uint32 m_null_bits[2];
+ Uint32 m_extra_row_gci_bits;
+ Uint32 m_extra_row_author_bits;
union {
BlockReference lqhBlockrefFrag;
Uint32 m_senderRef;
@@ -1009,7 +1011,9 @@ ArrayPool<TupTriggerData> c_triggerPool;
TR_Checksum = 0x1, // Need to be 1
TR_RowGCI = 0x2,
TR_ForceVarPart = 0x4,
- TR_DiskPart = 0x8
+ TR_DiskPart = 0x8,
+ TR_ExtraRowGCIBits = 0x10,
+ TR_ExtraRowAuthorBits = 0x20
};
Uint16 m_bits;
Uint16 total_rec_size; // Max total size for entire tuple in words
@@ -1022,6 +1026,7 @@ ArrayPool<TupTriggerData> c_triggerPool;
Uint16 noOfKeyAttr;
Uint16 noOfCharsets;
Uint16 m_dyn_null_bits;
+ Uint16 m_no_of_extra_columns; // "Hidden" columns
bool need_expand() const {
return m_no_of_attributes > m_attributes[MM].m_no_of_fixsize;
@@ -1047,6 +1052,17 @@ ArrayPool<TupTriggerData> c_triggerPool;
(disk && m_attributes[DD].m_no_of_varsize > 0);
}
+ template <Uint32 bit> Uint32 getExtraAttrId() const {
+ if (bit == TR_ExtraRowGCIBits)
+ return 0;
+ Uint32 no = 0;
+ if (m_bits & TR_ExtraRowGCIBits)
+ no++;
+ assert(bit == TR_ExtraRowAuthorBits);
+ //if (bit == TR_ExtraRowAuthorBits)
+ return no;
+ }
+
/**
* Descriptors for MM and DD part
*/
@@ -1712,7 +1728,9 @@ public:
void complete_restore_lcp(Signal*, Uint32 ref, Uint32 data,
Uint32 tableId, Uint32 fragmentId);
Uint32 get_max_lcp_record_size(Uint32 tableId);
-
+ void start_copy_frag(Uint32 tableId, Uint32 fragmentId);
+ void complete_copy_frag(Uint32 tableId, Uint32 fragmentId);
+
int nr_read_pk(Uint32 fragPtr, const Local_key*, Uint32* dataOut, bool©);
int nr_update_gci(Uint32 fragPtr, const Local_key*, Uint32 gci);
int nr_delete(Signal*, Uint32, Uint32 fragPtr, const Local_key*, Uint32 gci);
@@ -2010,6 +2028,13 @@ private:
KeyReqStruct* req_struct,
bool disk);
+ int handleRefreshReq(Signal* signal,
+ Ptr<Operationrec>,
+ Ptr<Fragrecord>,
+ Tablerec*,
+ KeyReqStruct*,
+ bool disk);
+
//------------------------------------------------------------------
//------------------------------------------------------------------
int updateStartLab(Signal* signal,
@@ -2880,10 +2905,14 @@ private:
void initData();
void initRecords();
+ // 2 words for optional GCI64 + AUTHOR info
+#define EXTRA_COPY_PROC_WORDS 2
+#define MAX_COPY_PROC_LEN (MAX_ATTRIBUTES_IN_TABLE + EXTRA_COPY_PROC_WORDS)
+
void deleteScanProcedure(Signal* signal, Operationrec* regOperPtr);
void allocCopyProcedure();
void freeCopyProcedure();
- void prepareCopyProcedure(Uint32 numAttrs);
+ void prepareCopyProcedure(Uint32 numAttrs, Uint16 tableBits);
void releaseCopyProcedure();
void copyProcedure(Signal* signal,
TablerecPtr regTabPtr,
@@ -2902,7 +2931,7 @@ private:
//-----------------------------------------------------------------------------
// Public methods
- Uint32 getTabDescrOffsets(Uint32, Uint32, Uint32, Uint32*);
+ Uint32 getTabDescrOffsets(Uint32, Uint32, Uint32, Uint32, Uint32*);
Uint32 getDynTabDescrOffsets(Uint32 MaskSize, Uint32* offset);
Uint32 allocTabDescr(Uint32 allocSize);
void releaseTabDescr(Uint32 desc);
@@ -3103,6 +3132,8 @@ private:
Uint32 czero;
Uint32 cCopyProcedure;
Uint32 cCopyLastSeg;
+ Uint32 cCopyOverwrite;
+ Uint32 cCopyOverwriteLen;
// A little bit bigger to cover overwrites in copy algorithms (16384 real size).
#define ZATTR_BUFFER_SIZE 16384
@@ -3301,11 +3332,16 @@ private:
void findFirstOp(OperationrecPtr&);
bool is_rowid_lcp_scanned(const Local_key& key1,
const Dbtup::ScanOp& op);
- void commit_operation(Signal*, Uint32, Tuple_header*, PagePtr,
+ void commit_operation(Signal*, Uint32, Uint32, Tuple_header*, PagePtr,
Operationrec*, Fragrecord*, Tablerec*);
-
- void dealloc_tuple(Signal* signal, Uint32, Page*, Tuple_header*,
+ void commit_refresh(Signal*, Uint32, Uint32, Tuple_header*, PagePtr,
+ Operationrec*, Fragrecord*, Tablerec*);
+ void dealloc_tuple(Signal* signal, Uint32, Uint32, Page*, Tuple_header*,
Operationrec*, Fragrecord*, Tablerec*);
+ bool store_extra_row_bits(Uint32, const Tablerec*, Tuple_header*, Uint32,
+ bool);
+ void read_extra_row_bits(Uint32, const Tablerec*, Tuple_header*, Uint32 *,
+ bool);
int handle_size_change_after_update(KeyReqStruct* req_struct,
Tuple_header* org,
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp 2010-09-03 05:35:51 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp 2010-09-22 10:49:11 +0000
@@ -155,7 +155,8 @@ Dbtup::is_rowid_lcp_scanned(const Local_
void
Dbtup::dealloc_tuple(Signal* signal,
- Uint32 gci,
+ Uint32 gci_hi,
+ Uint32 gci_lo,
Page* page,
Tuple_header* ptr,
Operationrec* regOperPtr,
@@ -176,7 +177,7 @@ Dbtup::dealloc_tuple(Signal* signal,
tmpptr.i = m_pgman_ptr.i;
tmpptr.p = reinterpret_cast<Page*>(m_pgman_ptr.p);
disk_page_free(signal, regTabPtr, regFragPtr,
- &disk, tmpptr, gci);
+ &disk, tmpptr, gci_hi);
}
if (! (bits & (Tuple_header::LCP_SKIP | Tuple_header::ALLOC)) &&
@@ -201,7 +202,12 @@ Dbtup::dealloc_tuple(Signal* signal,
if (regTabPtr->m_bits & Tablerec::TR_RowGCI)
{
jam();
- * ptr->get_mm_gci(regTabPtr) = gci;
+ * ptr->get_mm_gci(regTabPtr) = gci_hi;
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ Uint32 attrId = regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ store_extra_row_bits(attrId, regTabPtr, ptr, gci_lo, /* truncate */true);
+ }
}
}
@@ -227,7 +233,8 @@ static void dump_buf_hex(unsigned char *
void
Dbtup::commit_operation(Signal* signal,
- Uint32 gci,
+ Uint32 gci_hi,
+ Uint32 gci_lo,
Tuple_header* tuple_ptr,
PagePtr pagePtr,
Operationrec* regOperPtr,
@@ -338,7 +345,7 @@ Dbtup::commit_operation(Signal* signal,
if(copy_bits & Tuple_header::DISK_ALLOC)
{
jam();
- disk_page_alloc(signal, regTabPtr, regFragPtr, &key, diskPagePtr, gci);
+ disk_page_alloc(signal, regTabPtr, regFragPtr, &key, diskPagePtr, gci_hi);
}
if(regTabPtr->m_attributes[DD].m_no_of_varsize == 0)
@@ -358,7 +365,7 @@ Dbtup::commit_operation(Signal* signal,
{
jam();
disk_page_undo_update(diskPagePtr.p,
- &key, dst, sz, gci, logfile_group_id);
+ &key, dst, sz, gci_hi, logfile_group_id);
}
memcpy(dst, disk_ptr, 4*sz);
@@ -394,7 +401,13 @@ Dbtup::commit_operation(Signal* signal,
if (regTabPtr->m_bits & Tablerec::TR_RowGCI)
{
jam();
- * tuple_ptr->get_mm_gci(regTabPtr) = gci;
+ * tuple_ptr->get_mm_gci(regTabPtr) = gci_hi;
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ Uint32 attrId = regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ store_extra_row_bits(attrId, regTabPtr, tuple_ptr, gci_lo,
+ /* truncate */true);
+ }
}
if (regTabPtr->m_bits & Tablerec::TR_Checksum) {
@@ -741,23 +754,27 @@ skip_disk:
tuple_ptr->m_operation_ptr_i = RNIL;
- if(regOperPtr.p->op_struct.op_type != ZDELETE)
+ if (regOperPtr.p->op_struct.op_type == ZDELETE)
+ {
+ jam();
+ if (get_page)
+ ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART);
+ dealloc_tuple(signal, gci_hi, gci_lo, page.p, tuple_ptr,
+ regOperPtr.p, regFragPtr.p, regTabPtr.p);
+ }
+ else if(regOperPtr.p->op_struct.op_type != ZREFRESH)
{
jam();
- commit_operation(signal, gci_hi, tuple_ptr, page,
- regOperPtr.p, regFragPtr.p, regTabPtr.p);
+ commit_operation(signal, gci_hi, gci_lo, tuple_ptr, page,
+ regOperPtr.p, regFragPtr.p, regTabPtr.p);
}
else
{
jam();
- if (get_page)
- {
- ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART);
- }
- dealloc_tuple(signal, gci_hi, page.p, tuple_ptr,
- regOperPtr.p, regFragPtr.p, regTabPtr.p);
+ commit_refresh(signal, gci_hi, gci_lo, tuple_ptr, page,
+ regOperPtr.p, regFragPtr.p, regTabPtr.p);
}
- }
+ }
if (nextOp != RNIL)
{
@@ -808,3 +825,39 @@ Dbtup::set_commit_change_mask_info(const
}
}
}
+
+void
+Dbtup::commit_refresh(Signal* signal,
+ Uint32 gci_hi,
+ Uint32 gci_lo,
+ Tuple_header* tuple_ptr,
+ PagePtr pagePtr,
+ Operationrec* regOperPtr,
+ Fragrecord* regFragPtr,
+ Tablerec* regTabPtr)
+{
+ switch(regOperPtr->m_copy_tuple_location.m_file_no){
+ case 1:
+ case 3:
+ break;
+ case 2:
+ case 4:
+ // "Normal" update
+ commit_operation(signal, gci_hi, gci_lo, tuple_ptr, pagePtr,
+ regOperPtr, regFragPtr, regTabPtr);
+ return;
+
+ default:
+ ndbrequire(false);
+ }
+
+ Local_key key = regOperPtr->m_tuple_location;
+ key.m_page_no = pagePtr.p->frag_page_id;
+
+ /**
+ * Tell ACC to delete
+ */
+ c_lqh->accremoverow(signal, regOperPtr->userpointer, &key);
+ dealloc_tuple(signal, gci_hi, gci_lo, pagePtr.p, tuple_ptr,
+ regOperPtr, regFragPtr, regTabPtr);
+}
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2010-09-07 06:44:00 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2010-09-22 10:49:11 +0000
@@ -213,7 +213,13 @@ Dbtup::insertActiveOpList(OperationrecPt
prevOpPtr.p->op_struct.delete_insert_flag= true;
regOperPtr.p->op_struct.delete_insert_flag= true;
return true;
- } else {
+ }
+ else if (op == ZREFRESH)
+ {
+ return true;
+ }
+ else
+ {
terrorCode= ZTUPLE_DELETED_ERROR;
return false;
}
@@ -223,6 +229,17 @@ Dbtup::insertActiveOpList(OperationrecPt
terrorCode= ZINSERT_ERROR;
return false;
}
+ else if (prevOp == ZREFRESH)
+ {
+ /**
+ * Only ZREFRESH allowed after a ZREFRESH
+ */
+ if (op != ZREFRESH)
+ {
+ terrorCode= ZMUST_BE_ABORTED_ERROR;
+ return false;
+ }
+ }
return true;
}
else
@@ -287,7 +304,7 @@ Dbtup::setup_read(KeyReqStruct *req_stru
Uint32 currOp= currOpPtr.p->op_struct.op_type;
if((found && currOp == ZDELETE) ||
- ((dirty || !found) && currOp == ZINSERT))
+ ((dirty || !found) && (currOp == ZINSERT || currOp == ZREFRESH)))
{
terrorCode= ZTUPLE_DELETED_ERROR;
break;
@@ -351,7 +368,7 @@ Dbtup::load_diskpage(Signal* signal,
regOperPtr->op_struct.m_load_diskpage_on_commit= 1;
return 1;
}
-
+
jam();
Uint32 page_idx= local_key & MAX_TUPLES_PER_PAGE;
Uint32 frag_page_id= local_key >> MAX_TUPLES_BITS;
@@ -408,6 +425,7 @@ Dbtup::load_diskpage(Signal* signal,
case ZUPDATE:
case ZINSERT:
case ZWRITE:
+ case ZREFRESH:
regOperPtr->op_struct.m_wait_log_buffer= 1;
regOperPtr->op_struct.m_load_diskpage_on_commit= 1;
}
@@ -554,7 +572,7 @@ void Dbtup::execTUPKEYREQ(Signal* signal
Uint32 Rstoredid= tupKeyReq->storedProcedure;
regOperPtr->fragmentPtr= Rfragptr;
- regOperPtr->op_struct.op_type= (TrequestInfo >> 6) & 0xf;
+ regOperPtr->op_struct.op_type= (TrequestInfo >> 6) & 0x7;
regOperPtr->op_struct.delete_insert_flag = false;
regOperPtr->op_struct.m_reorg = (TrequestInfo >> 12) & 3;
@@ -634,6 +652,12 @@ void Dbtup::execTUPKEYREQ(Signal* signal
goto do_insert;
}
+ if (Roptype == ZREFRESH && localkey == ~ (Uint32) 0)
+ {
+ // No tuple allocatated yet
+ goto do_refresh;
+ }
+
/**
* Get pointer to tuple
*/
@@ -815,6 +839,23 @@ void Dbtup::execTUPKEYREQ(Signal* signal
sendTUPKEYCONF(signal, &req_struct, regOperPtr);
return;
}
+ else if (Roptype == ZREFRESH)
+ {
+ /**
+ * No TUX or immediate triggers
+ */
+ do_refresh:
+ if (unlikely(handleRefreshReq(signal, operPtr,
+ fragptr, regTabPtr,
+ &req_struct, disk_page != RNIL) == -1))
+ {
+ return;
+ }
+
+ sendTUPKEYCONF(signal, &req_struct, regOperPtr);
+ return;
+
+ }
else
{
ndbrequire(false); // Invalid op type
@@ -1063,6 +1104,15 @@ int Dbtup::handleUpdateReq(Signal* signa
if (!req_struct->interpreted_exec) {
jam();
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ jam();
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ store_extra_row_bits(attrId, regTabPtr, dst, /* default */ 0, false);
+ }
int retValue = updateAttributes(req_struct,
&cinBuffer[0],
req_struct->attrinfo_len);
@@ -1469,6 +1519,14 @@ int Dbtup::handleInsertReq(Signal* signa
terrorCode = ZAI_INCONSISTENCY_ERROR;
goto update_error;
}
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ store_extra_row_bits(attrId, regTabPtr, tuple_ptr, /* default */ 0, false);
+ }
if (!regTabPtr->m_default_value_location.isNull())
{
@@ -1831,6 +1889,138 @@ error:
return -1;
}
+int
+Dbtup::handleRefreshReq(Signal* signal,
+ Ptr<Operationrec> regOperPtr,
+ Ptr<Fragrecord> regFragPtr,
+ Tablerec* regTabPtr,
+ KeyReqStruct *req_struct,
+ bool disk)
+{
+ Uint32 refresh_case;
+ if (regOperPtr.p->is_first_operation())
+ {
+ jam();
+ if (req_struct->frag_page_id == (~(Uint32)0) >> MAX_TUPLES_BITS)
+ {
+ jam();
+ refresh_case = 1;
+ //ndbout_c("case 1");
+ /**
+ * This is refresh of non-existing tuple...
+ * i.e "delete", reuse initial insert
+ */
+ Local_key accminupdate;
+ Local_key * accminupdateptr = &accminupdate;
+
+ /**
+ * We don't need ...in this scenario
+ * - disk
+ * - default values
+ */
+ Uint32 save_disk = regTabPtr->m_no_of_disk_attributes;
+ Local_key save_defaults = regTabPtr->m_default_value_location;
+ Bitmask<MAXNROFATTRIBUTESINWORDS> save_mask =
+ regTabPtr->notNullAttributeMask;
+
+ regTabPtr->m_no_of_disk_attributes = 0;
+ regTabPtr->m_default_value_location.setNull();
+ regOperPtr.p->op_struct.op_type = ZINSERT;
+
+ /**
+ * Update notNullAttributeMask to only include primary keys
+ */
+ regTabPtr->notNullAttributeMask.clear();
+ const Uint32 * primarykeys =
+ (Uint32*)&tableDescriptor[regTabPtr->readKeyArray].tabDescr;
+ for (Uint32 i = 0; i<regTabPtr->noOfKeyAttr; i++)
+ regTabPtr->notNullAttributeMask.set(primarykeys[i] >> 16);
+
+ int res = handleInsertReq(signal, regOperPtr,
+ regFragPtr, regTabPtr, req_struct,
+ &accminupdateptr);
+
+ regTabPtr->m_no_of_disk_attributes = save_disk;
+ regTabPtr->m_default_value_location = save_defaults;
+ regTabPtr->notNullAttributeMask = save_mask;
+
+ if (unlikely(res == -1))
+ {
+ return -1;
+ }
+
+ regOperPtr.p->op_struct.op_type = ZREFRESH;
+
+ if (accminupdateptr)
+ {
+ /**
+ * Update ACC local-key, once *everything* has completed succesfully
+ */
+ c_lqh->accminupdate(signal,
+ regOperPtr.p->userpointer,
+ accminupdateptr);
+ }
+ }
+ else
+ {
+ refresh_case = 2;
+ //ndbout_c("case 2");
+ jam();
+
+ Uint32 tup_version_save = req_struct->m_tuple_ptr->get_tuple_version();
+ Uint32 new_tup_version = decr_tup_version(tup_version_save);
+ req_struct->m_tuple_ptr->set_tuple_version(new_tup_version);
+ int res = handleUpdateReq(signal, regOperPtr.p, regFragPtr.p,
+ regTabPtr, req_struct, disk);
+ req_struct->m_tuple_ptr->set_tuple_version(tup_version_save);
+ if (res == -1)
+ return -1;
+ }
+ }
+ else
+ {
+ jam();
+
+ Uint32 tup_version_save = req_struct->prevOpPtr.p->tupVersion;
+ Uint32 new_tup_version = decr_tup_version(tup_version_save);
+ req_struct->prevOpPtr.p->tupVersion = new_tup_version;
+
+ int res;
+ if (req_struct->prevOpPtr.p->op_struct.op_type == ZDELETE)
+ {
+ refresh_case = 3;
+ //ndbout_c("case 3");
+
+ jam();
+ /**
+ * This is multi-update + DELETE + REFRESH
+ */
+ Local_key * accminupdateptr = 0;
+ res = handleInsertReq(signal, regOperPtr,
+ regFragPtr, regTabPtr, req_struct,
+ &accminupdateptr);
+ }
+ else
+ {
+ jam();
+ refresh_case = 4;
+ //ndbout_c("case 4");
+ /**
+ * This is multi-update + INSERT/UPDATE + REFRESH
+ */
+ res = handleUpdateReq(signal, regOperPtr.p, regFragPtr.p,
+ regTabPtr, req_struct, disk);
+ }
+ req_struct->prevOpPtr.p->tupVersion = tup_version_save;
+ if (res == -1)
+ return -1;
+ }
+
+ // overload meaning...
+ regOperPtr.p->m_copy_tuple_location.m_file_no = refresh_case;
+ return 0;
+}
+
bool
Dbtup::checkNullAttributes(KeyReqStruct * req_struct,
Tablerec* regTabPtr)
@@ -2006,6 +2196,25 @@ int Dbtup::interpreterStartLab(Signal* s
return -1;
}
}
+
+ if ((RlogSize > 0) ||
+ (RfinalUpdateLen > 0))
+ {
+ /* Operation updates row,
+ * reset author pseudo-col before update takes effect
+ */
+ Tablerec* regTabPtr = req_struct->tablePtrP;
+ Tuple_header* dst = req_struct->m_tuple_ptr;
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ store_extra_row_bits(attrId, regTabPtr, dst, /* default */ 0, false);
+ }
+ }
+
if (RfinalUpdateLen > 0) {
jam();
/* ---------------------------------------------------------------- */
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp 2010-09-07 06:44:00 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp 2010-09-22 10:49:11 +0000
@@ -52,6 +52,8 @@ void Dbtup::initData()
cCopyProcedure = RNIL;
cCopyLastSeg = RNIL;
+ cCopyOverwrite = 0;
+ cCopyOverwriteLen = 0;
// Records with constant sizes
init_list_sizes();
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp 2010-09-21 07:36:08 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp 2010-09-22 10:49:11 +0000
@@ -77,6 +77,9 @@ Dbtup::execCREATE_TAB_REQ(Signal* signal
memset(fragOperPtr.p->m_null_bits, 0, sizeof(fragOperPtr.p->m_null_bits));
fragOperPtr.p->charsetIndex = 0;
fragOperPtr.p->lqhBlockrefFrag = req->senderRef;
+ fragOperPtr.p->m_extra_row_gci_bits =
+ req->GCPIndicator > 1 ? req->GCPIndicator - 1 : 0;
+ fragOperPtr.p->m_extra_row_author_bits = req->extraRowAuthorBits;
regTabPtr.p->m_createTable.m_fragOpPtrI = fragOperPtr.i;
regTabPtr.p->m_createTable.defValSectionI = RNIL;
@@ -85,6 +88,9 @@ Dbtup::execCREATE_TAB_REQ(Signal* signal
regTabPtr.p->m_bits |= (req->checksumIndicator ? Tablerec::TR_Checksum : 0);
regTabPtr.p->m_bits |= (req->GCPIndicator ? Tablerec::TR_RowGCI : 0);
regTabPtr.p->m_bits |= (req->forceVarPartFlag? Tablerec::TR_ForceVarPart : 0);
+ regTabPtr.p->m_bits |=
+ (req->GCPIndicator > 1 ? Tablerec::TR_ExtraRowGCIBits : 0);
+ regTabPtr.p->m_bits |= (req->extraRowAuthorBits ? Tablerec::TR_ExtraRowAuthorBits : 0);
regTabPtr.p->m_offsets[MM].m_disk_ref_offset= 0;
regTabPtr.p->m_offsets[MM].m_null_words= 0;
@@ -117,12 +123,26 @@ Dbtup::execCREATE_TAB_REQ(Signal* signal
regTabPtr.p->noOfCharsets= req->noOfCharsets;
regTabPtr.p->m_no_of_attributes= req->noOfAttributes;
regTabPtr.p->dynTabDescriptor= RNIL;
+ regTabPtr.p->m_no_of_extra_columns = 0;
+
+ if (regTabPtr.p->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ jam();
+ regTabPtr.p->m_no_of_extra_columns++;
+ }
+
+ if (regTabPtr.p->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ jam();
+ regTabPtr.p->m_no_of_extra_columns++;
+ }
{
Uint32 offset[10];
Uint32 allocSize= getTabDescrOffsets(req->noOfAttributes,
req->noOfCharsets,
req->noOfKeyAttr,
+ regTabPtr.p->m_no_of_extra_columns,
offset);
Uint32 tableDescriptorRef= allocTabDescr(allocSize);
if (tableDescriptorRef == RNIL)
@@ -177,6 +197,8 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
fragOperPtr.p->attributeCount--;
const bool lastAttr = (fragOperPtr.p->attributeCount == 0);
+ Uint32 extraAttrId = 0;
+
Uint32 firstTabDesIndex= regTabPtr.p->tabDescriptor + (attrId * ZAD_SIZE);
setTabDescrWord(firstTabDesIndex, attrDescriptor);
Uint32 attrLen = AttributeDescriptor::getSize(attrDescriptor);
@@ -320,7 +342,71 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
signal, 2, JBB);
return;
}
-
+
+ if (fragOperPtr.p->m_extra_row_gci_bits)
+ {
+ jam();
+
+ const Uint32 bits = fragOperPtr.p->m_extra_row_gci_bits;
+
+ /**
+ * Create attribute descriptor for extra row gci bits...
+ */
+ Uint32 desc = 0;
+ Uint32 off = 0;
+
+ AttributeDescriptor::setSize(desc, 0); // bit
+ AttributeDescriptor::setArraySize(desc, bits);
+ AttributeOffset::setNullFlagPos(off, fragOperPtr.p->m_null_bits[MM]);
+ fragOperPtr.p->m_null_bits[MM] += bits;
+
+ if (fragOperPtr.p->m_null_bits[MM] > AO_NULL_FLAG_POS_MASK)
+ {
+ jam();
+ terrorCode = ZTOO_MANY_BITS_ERROR;
+ goto error;
+ }
+
+ Uint32 idx = regTabPtr.p->tabDescriptor;
+ idx += ZAD_SIZE * (regTabPtr.p->m_no_of_attributes + extraAttrId);
+ setTabDescrWord(idx, desc);
+ setTabDescrWord(idx + 1, off);
+
+ extraAttrId++;
+ }
+
+ if (fragOperPtr.p->m_extra_row_author_bits)
+ {
+ jam();
+
+ const Uint32 bits = fragOperPtr.p->m_extra_row_author_bits;
+
+ /**
+ * Create attribute descriptor for extra row gci bits...
+ */
+ Uint32 desc = 0;
+ Uint32 off = 0;
+
+ AttributeDescriptor::setSize(desc, 0); // bit
+ AttributeDescriptor::setArraySize(desc, bits);
+ AttributeOffset::setNullFlagPos(off, fragOperPtr.p->m_null_bits[MM]);
+ fragOperPtr.p->m_null_bits[MM] += bits;
+
+ if (fragOperPtr.p->m_null_bits[MM] > AO_NULL_FLAG_POS_MASK)
+ {
+ jam();
+ terrorCode = ZTOO_MANY_BITS_ERROR;
+ goto error;
+ }
+
+ Uint32 idx = regTabPtr.p->tabDescriptor;
+ idx += ZAD_SIZE * (regTabPtr.p->m_no_of_attributes + extraAttrId);
+ setTabDescrWord(idx, desc);
+ setTabDescrWord(idx + 1, off);
+
+ extraAttrId++;
+ }
+
#define BTW(x) ((x+31) >> 5)
regTabPtr.p->m_offsets[MM].m_null_words= BTW(fragOperPtr.p->m_null_bits[MM]);
regTabPtr.p->m_offsets[DD].m_null_words= BTW(fragOperPtr.p->m_null_bits[DD]);
@@ -1015,6 +1101,7 @@ Dbtup::handleAlterTablePrepare(Signal *s
/* Allocate a new (possibly larger) table descriptor buffer. */
Uint32 allocSize= getTabDescrOffsets(newNoOfAttr, newNoOfCharsets,
newNoOfKeyAttrs,
+ regTabPtr->m_no_of_extra_columns,
regAlterTabOpPtr.p->tabDesOffset);
Uint32 tableDescriptorRef= allocTabDescr(allocSize);
if (tableDescriptorRef == RNIL) {
@@ -1035,11 +1122,24 @@ Dbtup::handleAlterTablePrepare(Signal *s
(CHARSET_INFO**)(desc + regAlterTabOpPtr.p->tabDesOffset[2]);
memcpy(CharsetArray, regTabPtr->charsetArray,
sizeof(*CharsetArray)*regTabPtr->noOfCharsets);
- Uint32 *attrDesPtr= desc + regAlterTabOpPtr.p->tabDesOffset[4];
+ Uint32 * const attrDesPtrStart = desc + regAlterTabOpPtr.p->tabDesOffset[4];
+ Uint32 * attrDesPtr = attrDesPtrStart;
memcpy(attrDesPtr,
&tableDescriptor[regTabPtr->tabDescriptor].tabDescr,
- (ZAD_SIZE<<2)*oldNoOfAttr);
- attrDesPtr+= ZAD_SIZE*oldNoOfAttr;
+ 4 * ZAD_SIZE * oldNoOfAttr);
+
+ /**
+ * Copy extra columns descriptors to end of attrDesPtr
+ */
+ {
+ const Uint32 * src = &tableDescriptor[regTabPtr->tabDescriptor].tabDescr;
+ src += ZAD_SIZE * oldNoOfAttr;
+
+ Uint32 * dst = attrDesPtr + (ZAD_SIZE * newNoOfAttr);
+ memcpy(dst, src, 4 * ZAD_SIZE * regTabPtr->m_no_of_extra_columns);
+ }
+
+ attrDesPtr+= ZAD_SIZE * oldNoOfAttr;
/*
Loop over the new attributes to add.
@@ -1110,6 +1210,7 @@ Dbtup::handleAlterTablePrepare(Signal *s
*attrDesPtr++= attrDes2;
}
ndbassert(newNoOfCharsets==charsetIndex);
+ ndbrequire(attrDesPtr == attrDesPtrStart + (ZAD_SIZE * newNoOfAttr));
regAlterTabOpPtr.p->noOfDynNullBits= dyn_nullbits;
ndbassert(noDynamic ==
@@ -1820,6 +1921,7 @@ void Dbtup::releaseTabDescr(Tablerec* co
getTabDescrOffsets(regTabPtr->m_no_of_attributes,
regTabPtr->noOfCharsets,
regTabPtr->noOfKeyAttr,
+ regTabPtr->m_no_of_extra_columns,
offset);
regTabPtr->tabDescriptor= RNIL;
@@ -2518,6 +2620,44 @@ Dbtup::complete_restore_lcp(Signal* sign
rebuild_page_free_list(signal);
}
+void
+Dbtup::start_copy_frag(Uint32 tableId, Uint32 fragmentId)
+{
+ TablerecPtr tabPtr;
+ tabPtr.i= tableId;
+ ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
+
+ /* If the table has extra row GCI bits, copyFrag uses
+ * attrinfo to restore the GCI. We clear the table's
+ * GCI bit here so that it is not trampled by LQH.
+ */
+ if (tabPtr.p->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ /* Save Table's TR_RowGCI bit in some borrowed space */
+ tabPtr.p->m_dropTable.tabUserRef= (tabPtr.p->m_bits &
+ Tablerec::TR_RowGCI)? 1 : 0;
+
+ /* Clear Table's TR_RowGCI bit as GCI is set from
+ * AttrInfo during COPYFRAG
+ */
+ tabPtr.p->m_bits &= ~((Uint16) Tablerec::TR_RowGCI);
+ }
+}
+
+void
+Dbtup::complete_copy_frag(Uint32 tableId, Uint32 fragmentId)
+{
+ TablerecPtr tabPtr;
+ tabPtr.i= tableId;
+ ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
+
+ if (tabPtr.p->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ /* Restore Table's TR_RowGCI bit */
+ tabPtr.p->m_bits |= ((tabPtr.p->m_dropTable.tabUserRef & 1) ? Tablerec::TR_RowGCI : 0);
+ }
+}
+
bool
Dbtup::get_frag_info(Uint32 tableId, Uint32 fragId, Uint32* maxPage)
{
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2010-09-07 06:44:00 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2010-09-22 10:49:11 +0000
@@ -26,6 +26,7 @@
#include <AttributeDescriptor.hpp>
#include "AttributeOffset.hpp"
#include <AttributeHeader.hpp>
+#include <dblqh/Dblqh.hpp>
void
Dbtup::setUpQueryRoutines(Tablerec *regTabPtr)
@@ -1744,6 +1745,70 @@ int Dbtup::updateAttributes(KeyReqStruct
inBufIndex += 1 + sz;
req_struct->in_buf_index = inBufIndex;
}
+ else if (attributeId == AttributeHeader::ROW_AUTHOR)
+ {
+ jam();
+ Uint32 sz= ahIn.getDataSize();
+ ndbrequire(sz == 1);
+
+ Uint32 value = * (inBuffer + inBufIndex + 1);
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ if (unlikely(!(regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)))
+ {
+ return -ZATTRIBUTE_ID_ERROR;
+ }
+
+ if (unlikely(store_extra_row_bits(attrId, regTabPtr,
+ req_struct->m_tuple_ptr,
+ value, /* truncate */ false) == false))
+ {
+ return -ZAI_INCONSISTENCY_ERROR;
+ }
+ inBufIndex += 1 + sz;
+ req_struct->in_buf_index = inBufIndex;
+ }
+ else if (attributeId == AttributeHeader::ROW_GCI64)
+ {
+ jam();
+ Uint32 sz= ahIn.getDataSize();
+ ndbrequire(sz == 2);
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ Uint32 gciLo = * (inBuffer + inBufIndex + 1);
+ Uint32 gciHi = * (inBuffer + inBufIndex + 2);
+
+ if (likely(! (regTabPtr->m_bits & Tablerec::TR_RowGCI)))
+ {
+ // TODO : Problem here that we allow GCI set for tables
+ // that genuinely don't have GCI.
+ /* Set GCI (setting rowGCI flag temporarily) */
+ {
+ Uint16 saveBits = regTabPtr->m_bits;
+ regTabPtr->m_bits |= Tablerec::TR_RowGCI;
+ *req_struct->m_tuple_ptr->get_mm_gci(regTabPtr) = gciHi;
+ regTabPtr->m_bits = saveBits;
+ }
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ if (unlikely(store_extra_row_bits(attrId, regTabPtr,
+ req_struct->m_tuple_ptr,
+ gciLo, /*truncate*/ true) == false))
+ {
+ return -ZAI_INCONSISTENCY_ERROR;
+ }
+ }
+ }
+ else
+ {
+ return -ZAI_INCONSISTENCY_ERROR;
+ }
+
+ inBufIndex+= 1 + sz;
+ req_struct->in_buf_index = inBufIndex;
+ }
else
{
jam();
@@ -2503,6 +2568,48 @@ Dbtup::read_pseudo(const Uint32 * inBuff
sz = 2;
}
break;
+ case AttributeHeader::ROW_GCI64:
+ {
+ sz = 0;
+ if (req_struct->tablePtrP->m_bits & Tablerec::TR_RowGCI)
+ {
+ Uint32 tmp0 = *req_struct->m_tuple_ptr->get_mm_gci(req_struct->tablePtrP);
+ Uint32 tmp1 = ~Uint32(0);
+ if (req_struct->tablePtrP->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ Uint32 attrId =
+ req_struct->tablePtrP->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ read_extra_row_bits(attrId,
+ req_struct->tablePtrP,
+ req_struct->m_tuple_ptr,
+ &tmp1,
+ /* extend */ true);
+ }
+ Uint64 tmp = Uint64(tmp0) << 32 | tmp1;
+ memcpy(outBuffer + 1, &tmp, sizeof(tmp));
+ sz = 2;
+ }
+ break;
+ }
+ case AttributeHeader::ROW_AUTHOR:
+ {
+ sz = 0;
+ if (req_struct->tablePtrP->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ Uint32 attrId = req_struct->tablePtrP
+ ->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ Uint32 tmp;
+ read_extra_row_bits(attrId,
+ req_struct->tablePtrP,
+ req_struct->m_tuple_ptr,
+ &tmp,
+ /* extend */ false);
+ outBuffer[1] = tmp;
+ sz = 1;
+ }
+ break;
+ }
case AttributeHeader::ANY_VALUE:
{
/**
@@ -3347,3 +3454,85 @@ Dbtup::read_lcp_keys(Uint32 tableId,
return ret;
}
+
+bool
+Dbtup::store_extra_row_bits(Uint32 extra_no,
+ const Tablerec* regTabPtr,
+ Tuple_header* ptr,
+ Uint32 value,
+ bool truncate)
+{
+ jam();
+ if (unlikely(extra_no >= regTabPtr->m_no_of_extra_columns))
+ return false;
+ /**
+ * ExtraRowGCIBits are using regTabPtr->m_no_of_attributes + extra_no
+ */
+ Uint32 num_attr= regTabPtr->m_no_of_attributes;
+ Uint32 attrId = num_attr + extra_no;
+ Uint32 descr_start = regTabPtr->tabDescriptor;
+ TableDescriptor *tab_descr = &tableDescriptor[descr_start];
+ ndbrequire(descr_start + (attrId << ZAD_LOG_SIZE)<= cnoOfTabDescrRec);
+
+ Uint32 attrDescriptorIndex = attrId << ZAD_LOG_SIZE;
+ Uint32 attrDescriptor = tab_descr[attrDescriptorIndex].tabDescr;
+ Uint32 attrOffset = tab_descr[attrDescriptorIndex + 1].tabDescr;
+
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrOffset);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ Uint32 maxVal = (1 << bitCount) - 1;
+ Uint32 *bits= ptr->get_null_bits(regTabPtr);
+
+ if (value > maxVal)
+ {
+ if (truncate)
+ {
+ value = maxVal;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ Uint32 check = regTabPtr->m_offsets[MM].m_null_words;
+ BitmaskImpl::setField(check, bits, pos, bitCount, &value);
+ return true;
+}
+
+void
+Dbtup::read_extra_row_bits(Uint32 extra_no,
+ const Tablerec* regTabPtr,
+ Tuple_header* ptr,
+ Uint32 * value,
+ bool extend)
+{
+ /**
+ * ExtraRowGCIBits are using regTabPtr->m_no_of_attributes + extra_no
+ */
+ ndbrequire(extra_no < regTabPtr->m_no_of_extra_columns);
+ Uint32 num_attr= regTabPtr->m_no_of_attributes;
+ Uint32 attrId = num_attr + extra_no;
+ Uint32 descr_start = regTabPtr->tabDescriptor;
+ TableDescriptor *tab_descr = &tableDescriptor[descr_start];
+ ndbrequire(descr_start + (attrId << ZAD_LOG_SIZE)<= cnoOfTabDescrRec);
+
+ Uint32 attrDescriptorIndex = attrId << ZAD_LOG_SIZE;
+ Uint32 attrDescriptor = tab_descr[attrDescriptorIndex].tabDescr;
+ Uint32 attrOffset = tab_descr[attrDescriptorIndex + 1].tabDescr;
+
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrOffset);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ Uint32 maxVal = (1 << bitCount) - 1;
+ Uint32 *bits= ptr->get_null_bits(regTabPtr);
+
+ Uint32 tmp;
+ Uint32 check = regTabPtr->m_offsets[MM].m_null_words;
+ BitmaskImpl::getField(check, bits, pos, bitCount, &tmp);
+
+ if (tmp == maxVal && extend)
+ {
+ tmp = ~Uint32(0);
+ }
+ * value = tmp;
+}
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp 2010-09-22 10:49:11 +0000
@@ -154,8 +154,15 @@ void Dbtup::allocCopyProcedure()
ndbrequire(appendToSection(iVal, &ahWord, 1));
}
+ /* Add space for extra attrs */
+ ahWord = 0;
+ for (Uint32 extra=0; extra < EXTRA_COPY_PROC_WORDS; extra++)
+ ndbrequire(appendToSection(iVal, &ahWord, 1));
+
cCopyProcedure= iVal;
cCopyLastSeg= RNIL;
+ cCopyOverwrite= 0;
+ cCopyOverwriteLen= 0;
}
void Dbtup::freeCopyProcedure()
@@ -166,7 +173,8 @@ void Dbtup::freeCopyProcedure()
cCopyProcedure=RNIL;
}
-void Dbtup::prepareCopyProcedure(Uint32 numAttrs)
+void Dbtup::prepareCopyProcedure(Uint32 numAttrs,
+ Uint16 tableBits)
{
/* Set length of copy procedure section to the
* number of attributes supplied
@@ -174,23 +182,51 @@ void Dbtup::prepareCopyProcedure(Uint32
ndbassert(numAttrs <= MAX_ATTRIBUTES_IN_TABLE);
ndbassert(cCopyProcedure != RNIL);
ndbassert(cCopyLastSeg == RNIL);
+ ndbassert(cCopyOverwrite == 0);
+ ndbassert(cCopyOverwriteLen == 0);
Ptr<SectionSegment> first;
g_sectionSegmentPool.getPtr(first, cCopyProcedure);
/* Record original 'last segment' of section */
cCopyLastSeg= first.p->m_lastSegment;
+ /* Check table bits to see if we need to do extra reads */
+ Uint32 extraAttrIds[EXTRA_COPY_PROC_WORDS];
+ Uint32 extraReads = 0;
+
+ if (tableBits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ AttributeHeader ah(AttributeHeader::ROW_GCI64,0);
+ extraAttrIds[extraReads++] = ah.m_value;
+ }
+ if (tableBits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ AttributeHeader ah(AttributeHeader::ROW_AUTHOR,0);
+ extraAttrIds[extraReads++] = ah.m_value;
+ }
+
/* Modify section to represent relevant prefix
* of code by modifying size and lastSegment
*/
- first.p->m_sz= numAttrs;
+ Uint32 newSize = numAttrs + extraReads;
+ first.p->m_sz= newSize;
+ if (extraReads)
+ {
+ cCopyOverwrite= numAttrs;
+ cCopyOverwriteLen = extraReads;
+
+ ndbrequire(writeToSection(first.i, numAttrs, extraAttrIds, extraReads));
+ }
+
+ /* Trim section size and lastSegment */
Ptr<SectionSegment> curr= first;
- while(numAttrs > SectionSegment::DataLength)
+ while(newSize > SectionSegment::DataLength)
{
g_sectionSegmentPool.getPtr(curr, curr.p->m_nextSegment);
- numAttrs-= SectionSegment::DataLength;
+ newSize-= SectionSegment::DataLength;
}
+
first.p->m_lastSegment= curr.i;
}
@@ -203,10 +239,24 @@ void Dbtup::releaseCopyProcedure()
Ptr<SectionSegment> first;
g_sectionSegmentPool.getPtr(first, cCopyProcedure);
- ndbassert(first.p->m_sz <= MAX_ATTRIBUTES_IN_TABLE);
- first.p->m_sz= MAX_ATTRIBUTES_IN_TABLE;
+ ndbassert(first.p->m_sz <= MAX_COPY_PROC_LEN);
+ first.p->m_sz= MAX_COPY_PROC_LEN;
first.p->m_lastSegment= cCopyLastSeg;
+ if (cCopyOverwriteLen)
+ {
+ ndbassert(cCopyOverwriteLen <= EXTRA_COPY_PROC_WORDS);
+ Uint32 attrids[EXTRA_COPY_PROC_WORDS];
+ for (Uint32 i=0; i < cCopyOverwriteLen; i++)
+ {
+ AttributeHeader ah(cCopyOverwrite + i, 0);
+ attrids[i] = ah.m_value;
+ }
+ ndbrequire(writeToSection(first.i, cCopyOverwrite, attrids, cCopyOverwriteLen));
+ cCopyOverwriteLen= 0;
+ cCopyOverwrite= 0;
+ }
+
cCopyLastSeg= RNIL;
}
@@ -222,8 +272,13 @@ void Dbtup::copyProcedure(Signal* signal
* This assumes that there is only one fragment copy going
* on at any time, which is verified by checking
* cCopyLastSeg == RNIL before starting each copy
+ *
+ * If the table has extra per-row metainformation that
+ * needs copied then we add that to the copy procedure
+ * as well.
*/
- prepareCopyProcedure(regTabPtr.p->m_no_of_attributes);
+ prepareCopyProcedure(regTabPtr.p->m_no_of_attributes,
+ regTabPtr.p->m_bits);
SectionHandle handle(this);
handle.m_cnt=1;
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp 2009-09-16 10:52:41 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp 2010-09-22 10:49:11 +0000
@@ -35,8 +35,11 @@
*/
Uint32
-Dbtup::getTabDescrOffsets(Uint32 noOfAttrs, Uint32 noOfCharsets,
- Uint32 noOfKeyAttr, Uint32* offset)
+Dbtup::getTabDescrOffsets(Uint32 noOfAttrs,
+ Uint32 noOfCharsets,
+ Uint32 noOfKeyAttr,
+ Uint32 extraColumns,
+ Uint32* offset)
{
// belongs to configure.in
unsigned sizeOfPointer = sizeof(CHARSET_INFO*);
@@ -50,7 +53,7 @@ Dbtup::getTabDescrOffsets(Uint32 noOfAtt
offset[2] = allocSize += noOfAttrs * sizeOfReadFunction();
offset[3] = allocSize += noOfCharsets * sizeOfPointer;
offset[4] = allocSize += noOfKeyAttr;
- offset[5] = allocSize += noOfAttrs * ZAD_SIZE;
+ offset[5] = allocSize += (noOfAttrs + extraColumns) * ZAD_SIZE;
offset[6] = allocSize += (noOfAttrs+1) >> 1; // real order
allocSize += ZTD_TRAILER_SIZE;
// return number of words
@@ -318,6 +321,7 @@ Dbtup::verifytabdes()
const Uint32 alloc = getTabDescrOffsets(ptr.p->m_no_of_attributes,
ptr.p->noOfCharsets,
ptr.p->noOfKeyAttr,
+ ptr.p->m_no_of_extra_columns,
offset);
const Uint32 desc = ptr.p->readKeyArray - offset[3];
Uint32 size = alloc;
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp 2010-09-03 05:35:51 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp 2010-09-22 10:49:11 +0000
@@ -619,6 +619,7 @@ void Dbtup::checkDetachedTriggers(KeyReq
switch (save_type) {
case ZUPDATE:
case ZINSERT:
+ case ZREFRESH:
req_struct->m_tuple_ptr =get_copy_tuple(®OperPtr->m_copy_tuple_location);
break;
}
@@ -634,7 +635,10 @@ void Dbtup::checkDetachedTriggers(KeyReq
return;
goto end;
}
- regOperPtr->op_struct.op_type = ZINSERT;
+ else if (save_type != ZREFRESH)
+ {
+ regOperPtr->op_struct.op_type = ZINSERT;
+ }
}
else if (save_type == ZINSERT) {
/**
@@ -686,6 +690,25 @@ void Dbtup::checkDetachedTriggers(KeyReq
regTablePtr->subscriptionUpdateTriggers,
regOperPtr, disk);
break;
+ case ZREFRESH:
+ jam();
+ switch(regOperPtr->m_copy_tuple_location.m_file_no){
+ case 1:
+ case 3:
+ fireDetachedTriggers(req_struct,
+ regTablePtr->subscriptionDeleteTriggers,
+ regOperPtr, disk);
+ break;
+ case 2:
+ case 4:
+ fireDetachedTriggers(req_struct,
+ regTablePtr->subscriptionInsertTriggers,
+ regOperPtr, disk);
+ break;
+ default:
+ ndbrequire(false);
+ }
+ break;
default:
ndbrequire(false);
break;
@@ -1055,12 +1078,14 @@ out:
switch(regOperPtr->op_struct.op_type) {
case(ZINSERT):
+ is_insert:
jam();
// Send AttrInfo signals with new attribute values
trigAttrInfo->setAttrInfoType(TrigAttrInfo::AFTER_VALUES);
sendTrigAttrInfo(signal, afterBuffer, noAfterWords, executeDirect, ref);
break;
case(ZDELETE):
+ is_delete:
if (trigPtr->sendBeforeValues) {
jam();
trigAttrInfo->setAttrInfoType(TrigAttrInfo::BEFORE_VALUES);
@@ -1077,6 +1102,22 @@ out:
trigAttrInfo->setAttrInfoType(TrigAttrInfo::AFTER_VALUES);
sendTrigAttrInfo(signal, afterBuffer, noAfterWords, executeDirect, ref);
break;
+ case ZREFRESH:
+ jam();
+ switch(regOperPtr->m_copy_tuple_location.m_file_no){
+ case 1:
+ jam();
+ case 3:
+ jam();
+ goto is_delete;
+ case 2:
+ jam();
+ case 4:
+ jam();
+ goto is_insert;
+ default:
+ ndbrequire(false);
+ }
default:
ndbrequire(false);
}
@@ -1104,6 +1145,25 @@ out:
jam();
fireTrigOrd->m_triggerEvent = TriggerEvent::TE_DELETE;
break;
+ case ZREFRESH:
+ jam();
+ switch(regOperPtr->m_copy_tuple_location.m_file_no){
+ case 1:
+ jam();
+ case 3:
+ jam();
+ fireTrigOrd->m_triggerEvent = TriggerEvent::TE_DELETE;
+ break;
+ case 2:
+ jam();
+ case 4:
+ jam();
+ fireTrigOrd->m_triggerEvent = TriggerEvent::TE_INSERT;
+ break;
+ default:
+ ndbrequire(false);
+ }
+ break;
default:
ndbrequire(false);
break;
@@ -1295,7 +1355,7 @@ bool Dbtup::readTriggerInfo(TupTriggerDa
// Delete without sending before values only read Primary Key
//--------------------------------------------------------------------
return true;
- } else {
+ } else if (regOperPtr->op_struct.op_type != ZREFRESH){
jam();
//--------------------------------------------------------------------
// All others send all attributes that are monitored, except:
@@ -1312,6 +1372,25 @@ bool Dbtup::readTriggerInfo(TupTriggerDa
numAttrsToRead = setAttrIds(attributeMask, regTabPtr->m_no_of_attributes,
&readBuffer[0]);
}
+ else
+ {
+ jam();
+ switch(regOperPtr->m_copy_tuple_location.m_file_no){
+ case 1:
+ case 3:
+ return true; // generate ZDELETE...no before values
+ case 2:
+ case 4:
+ // generate ZINSERT...all after values
+ numAttrsToRead = setAttrIds(trigPtr->attributeMask,
+ regTabPtr->m_no_of_attributes,
+ &readBuffer[0]);
+ break;
+ default:
+ ndbrequire(false);
+ }
+ }
+
ndbrequire(numAttrsToRead <= MAX_ATTRIBUTES_IN_TABLE);
//--------------------------------------------------------------------
// Read Main tuple values
@@ -1555,6 +1634,8 @@ Dbtup::executeTuxCommitTriggers(Signal*
return;
jam();
tupVersion= regOperPtr->tupVersion;
+ } else if (regOperPtr->op_struct.op_type == ZREFRESH) {
+ return;
} else {
ndbrequire(false);
tupVersion= 0; // remove warning
@@ -1587,6 +1668,9 @@ Dbtup::executeTuxAbortTriggers(Signal* s
} else if (regOperPtr->op_struct.op_type == ZDELETE) {
jam();
return;
+ } else if (regOperPtr->op_struct.op_type == ZREFRESH) {
+ jam();
+ return;
} else {
ndbrequire(false);
tupVersion= 0; // remove warning
=== modified file 'storage/ndb/src/kernel/vm/LongSignal.cpp'
--- a/storage/ndb/src/kernel/vm/LongSignal.cpp 2009-03-20 17:03:34 +0000
+++ b/storage/ndb/src/kernel/vm/LongSignal.cpp 2010-09-22 10:49:11 +0000
@@ -400,3 +400,58 @@ releaseSection(SPC_ARG Uint32 firstSegme
p->m_lastSegment);
}
}
+
+bool
+writeToSection(Uint32 firstSegmentIVal, Uint32 offset,
+ const Uint32* src,
+ Uint32 len)
+{
+ Ptr<SectionSegment> segPtr;
+
+ if (len == 0)
+ return true;
+
+ if (firstSegmentIVal == RNIL)
+ {
+ return false;
+ }
+ else
+ {
+ /* Section has at least one segment with data already */
+ g_sectionSegmentPool.getPtr(segPtr, firstSegmentIVal);
+
+ Uint32 existingLen= segPtr.p->m_sz;
+
+ assert(existingLen > 0);
+ if (offset >= existingLen)
+ return false; /* No sparse sections or extension */
+ if (len > (existingLen - offset))
+ return false; /* Would be extending beyond current length */
+
+ /* Advance through segments to the one containing the start offset */
+ while (offset >= SectionSegment::DataLength)
+ {
+ g_sectionSegmentPool.getPtr(segPtr, segPtr.p->m_nextSegment);
+ offset-= SectionSegment::DataLength;
+ }
+
+ /* Now overwrite the words */
+ while (true)
+ {
+ Uint32 wordsToCopy = MIN(len,
+ SectionSegment::DataLength - offset);
+ memcpy(&segPtr.p->theData[offset], src, (wordsToCopy << 2));
+ src+= wordsToCopy;
+ len-= wordsToCopy;
+
+ if (!len)
+ {
+ return true;
+ }
+
+ offset = 0;
+ g_sectionSegmentPool.getPtr(segPtr, segPtr.p->m_nextSegment);
+ }
+ }
+}
+
=== modified file 'storage/ndb/src/kernel/vm/LongSignalImpl.hpp'
--- a/storage/ndb/src/kernel/vm/LongSignalImpl.hpp 2008-10-08 19:09:05 +0000
+++ b/storage/ndb/src/kernel/vm/LongSignalImpl.hpp 2010-09-22 10:49:11 +0000
@@ -47,6 +47,8 @@ bool import(SPC_ARG Ptr<SectionSegment>
bool appendToSection(SPC_ARG Uint32& firstSegmentIVal, const Uint32* src, Uint32 len);
/* dupSection : Create new section as copy of src section */
bool dupSection(SPC_ARG Uint32& copyFirstIVal, Uint32 srcFirstIVal);
+/* writeToSection : Overwrite section from offset with data. */
+bool writeToSection(Uint32 firstSegmentIVal, Uint32 offset, const Uint32* src, Uint32 len);
void release(SPC_ARG SegmentedSectionPtr & ptr);
void releaseSection(SPC_ARG Uint32 firstSegmentIVal);
=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.cpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp 2010-06-10 14:32:07 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp 2010-09-22 10:49:11 +0000
@@ -1575,6 +1575,13 @@ SimulatedBlock::dupSection(Uint32& copyF
return ::dupSection(SB_SP_ARG copyFirstIVal, srcFirstIVal);
}
+bool
+SimulatedBlock::writeToSection(Uint32 firstSegmentIVal, Uint32 offset,
+ const Uint32* src, Uint32 len)
+{
+ return ::writeToSection(firstSegmentIVal, offset, src, len);
+}
+
class SectionSegmentPool&
SimulatedBlock::getSectionSegmentPool(){
return g_sectionSegmentPool;
=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.hpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp 2010-08-20 11:10:25 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp 2010-09-22 10:49:11 +0000
@@ -326,6 +326,7 @@ protected:
bool import(SegmentedSectionPtr& ptr, const Uint32* src, Uint32 len);
bool appendToSection(Uint32& firstSegmentIVal, const Uint32* src, Uint32 len);
bool dupSection(Uint32& copyFirstIVal, Uint32 srcFirstIVal);
+ bool writeToSection(Uint32 firstSegmentIVal, Uint32 offset, const Uint32* src, Uint32 len);
void handle_invalid_sections_in_send_signal(Signal*) const;
void handle_lingering_sections_after_execute(Signal*) const;
=== modified file 'storage/ndb/src/ndbapi/NdbDictionary.cpp'
--- a/storage/ndb/src/ndbapi/NdbDictionary.cpp 2010-09-13 14:31:30 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionary.cpp 2010-09-22 10:49:11 +0000
@@ -915,6 +915,36 @@ NdbDictionary::Table::getRowGCIIndicator
}
void
+NdbDictionary::Table::setExtraRowGciBits(Uint32 val)
+{
+ if (val <= 31)
+ {
+ m_impl.m_extra_row_gci_bits = val;
+ }
+}
+
+Uint32
+NdbDictionary::Table::getExtraRowGciBits() const
+{
+ return m_impl.m_extra_row_gci_bits;
+}
+
+void
+NdbDictionary::Table::setExtraRowAuthorBits(Uint32 val)
+{
+ if (val <= 31)
+ {
+ m_impl.m_extra_row_author_bits = val;
+ }
+}
+
+Uint32
+NdbDictionary::Table::getExtraRowAuthorBits() const
+{
+ return m_impl.m_extra_row_author_bits;
+}
+
+void
NdbDictionary::Table::setForceVarPart(bool val){
m_impl.m_force_var_part = val;
}
=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp'
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2010-09-14 09:57:29 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2010-09-22 10:49:11 +0000
@@ -369,6 +369,10 @@ NdbColumnImpl::create_pseudo_columns()
NdbColumnImpl::create_pseudo("NDB$ROWID");
NdbDictionary::Column::ROW_GCI=
NdbColumnImpl::create_pseudo("NDB$ROW_GCI");
+ NdbDictionary::Column::ROW_GCI64 =
+ NdbColumnImpl::create_pseudo("NDB$ROW_GCI64");
+ NdbDictionary::Column::ROW_AUTHOR =
+ NdbColumnImpl::create_pseudo("NDB$ROW_AUTHOR");
NdbDictionary::Column::ANY_VALUE=
NdbColumnImpl::create_pseudo("NDB$ANY_VALUE");
NdbDictionary::Column::COPY_ROWID=
@@ -399,6 +403,8 @@ NdbColumnImpl::destory_pseudo_columns()
delete NdbDictionary::Column::RECORDS_IN_RANGE;
delete NdbDictionary::Column::ROWID;
delete NdbDictionary::Column::ROW_GCI;
+ delete NdbDictionary::Column::ROW_GCI64;
+ delete NdbDictionary::Column::ROW_AUTHOR;
delete NdbDictionary::Column::ANY_VALUE;
delete NdbDictionary::Column::OPTIMIZE;
NdbDictionary::Column::FRAGMENT= 0;
@@ -412,6 +418,8 @@ NdbColumnImpl::destory_pseudo_columns()
NdbDictionary::Column::RECORDS_IN_RANGE= 0;
NdbDictionary::Column::ROWID= 0;
NdbDictionary::Column::ROW_GCI= 0;
+ NdbDictionary::Column::ROW_GCI64= 0;
+ NdbDictionary::Column::ROW_AUTHOR= 0;
NdbDictionary::Column::ANY_VALUE= 0;
NdbDictionary::Column::OPTIMIZE= 0;
@@ -490,6 +498,18 @@ NdbColumnImpl::create_pseudo(const char
col->m_impl.m_attrSize = 8;
col->m_impl.m_arraySize = 1;
col->m_impl.m_nullable = true;
+ } else if(!strcmp(name, "NDB$ROW_GCI64")){
+ col->setType(NdbDictionary::Column::Bigunsigned);
+ col->m_impl.m_attrId = AttributeHeader::ROW_GCI64;
+ col->m_impl.m_attrSize = 8;
+ col->m_impl.m_arraySize = 1;
+ col->m_impl.m_nullable = true;
+ } else if(!strcmp(name, "NDB$ROW_AUTHOR")){
+ col->setType(NdbDictionary::Column::Unsigned);
+ col->m_impl.m_attrId = AttributeHeader::ROW_AUTHOR;
+ col->m_impl.m_attrSize = 4;
+ col->m_impl.m_arraySize = 1;
+ col->m_impl.m_nullable = true;
} else if(!strcmp(name, "NDB$ANY_VALUE")){
col->setType(NdbDictionary::Column::Unsigned);
col->m_impl.m_attrId = AttributeHeader::ANY_VALUE;
@@ -628,6 +648,8 @@ NdbTableImpl::init(){
m_single_user_mode = 0;
m_hash_map_id = RNIL;
m_hash_map_version = ~0;
+ m_extra_row_gci_bits = 0;
+ m_extra_row_author_bits = 0;
}
bool
@@ -822,6 +844,22 @@ NdbTableImpl::equal(const NdbTableImpl&
DBUG_RETURN(false);
}
+ if (m_extra_row_gci_bits != obj.m_extra_row_gci_bits)
+ {
+ DBUG_PRINT("info",("m_extra_row_gci_bits %d != %d",
+ (int32)m_extra_row_gci_bits,
+ (int32)obj.m_extra_row_gci_bits));
+ DBUG_RETURN(false);
+ }
+
+ if (m_extra_row_author_bits != obj.m_extra_row_author_bits)
+ {
+ DBUG_PRINT("info",("m_extra_row_author_bits %d != %d",
+ (int32)m_extra_row_author_bits,
+ (int32)obj.m_extra_row_author_bits));
+ DBUG_RETURN(false);
+ }
+
DBUG_RETURN(true);
}
@@ -887,6 +925,8 @@ NdbTableImpl::assign(const NdbTableImpl&
m_fragmentCount = org.m_fragmentCount;
m_single_user_mode = org.m_single_user_mode;
+ m_extra_row_gci_bits = org.m_extra_row_gci_bits;
+ m_extra_row_author_bits = org.m_extra_row_author_bits;
if (m_index != 0)
delete m_index;
@@ -2709,6 +2749,8 @@ NdbDictInterface::parseTableInfo(NdbTabl
impl->m_minLoadFactor = tableDesc->MinLoadFactor;
impl->m_maxLoadFactor = tableDesc->MaxLoadFactor;
impl->m_single_user_mode = tableDesc->SingleUserMode;
+ impl->m_extra_row_gci_bits = tableDesc->ExtraRowGCIBits;
+ impl->m_extra_row_author_bits = tableDesc->ExtraRowAuthorBits;
impl->m_indexType = (NdbDictionary::Object::Type)
getApiConstant(tableDesc->TableType,
@@ -3224,7 +3266,9 @@ NdbDictInterface::compChangeMask(const N
impl.m_tablespace_version != old_impl.m_tablespace_version ||
impl.m_id != old_impl.m_id ||
impl.m_version != old_impl.m_version ||
- sz < old_sz)
+ sz < old_sz ||
+ impl.m_extra_row_gci_bits != old_impl.m_extra_row_gci_bits ||
+ impl.m_extra_row_author_bits != old_impl.m_extra_row_author_bits)
{
DBUG_PRINT("info", ("Old and new table not compatible"));
goto invalid_alter_table;
@@ -3410,6 +3454,8 @@ NdbDictInterface::serializeTableDesc(Ndb
tmpTab->LinearHashFlag = impl.m_linear_flag;
tmpTab->SingleUserMode = impl.m_single_user_mode;
tmpTab->ForceVarPartFlag = impl.m_force_var_part;
+ tmpTab->ExtraRowGCIBits = impl.m_extra_row_gci_bits;
+ tmpTab->ExtraRowAuthorBits = impl.m_extra_row_author_bits;
tmpTab->FragmentType = getKernelConstant(impl.m_fragmentType,
fragmentTypeMapping,
@@ -8276,6 +8322,8 @@ const NdbDictionary::Column * NdbDiction
const NdbDictionary::Column * NdbDictionary::Column::RECORDS_IN_RANGE = 0;
const NdbDictionary::Column * NdbDictionary::Column::ROWID = 0;
const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI = 0;
+const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI64 = 0;
+const NdbDictionary::Column * NdbDictionary::Column::ROW_AUTHOR = 0;
const NdbDictionary::Column * NdbDictionary::Column::ANY_VALUE = 0;
const NdbDictionary::Column * NdbDictionary::Column::COPY_ROWID = 0;
const NdbDictionary::Column * NdbDictionary::Column::OPTIMIZE = 0;
=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp 2010-09-13 14:31:30 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp 2010-09-22 10:49:11 +0000
@@ -233,6 +233,8 @@ public:
Uint16 m_keyLenInWords;
Uint16 m_fragmentCount;
Uint8 m_single_user_mode;
+ Uint8 m_extra_row_gci_bits;
+ Uint8 m_extra_row_author_bits;
NdbIndexImpl * m_index;
NdbColumnImpl * getColumn(unsigned attrId);
=== modified file 'storage/ndb/src/ndbapi/NdbOperationExec.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2010-06-08 14:37:15 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2010-09-22 10:49:11 +0000
@@ -1125,7 +1125,8 @@ NdbOperation::buildSignalsNdbRecord(Uint
/* Final update signal words */
if ((tOpType == InsertRequest) ||
(tOpType == WriteRequest) ||
- (tOpType == UpdateRequest))
+ (tOpType == UpdateRequest) ||
+ (tOpType == RefreshRequest))
{
updRow= m_attribute_row;
NdbBlob *currentBlob= theBlobList;
@@ -1338,7 +1339,8 @@ NdbOperation::buildSignalsNdbRecord(Uint
if ((tOpType == InsertRequest) ||
(tOpType == WriteRequest) ||
- (tOpType == UpdateRequest))
+ (tOpType == UpdateRequest) ||
+ (tOpType == RefreshRequest))
{
/* Handle setAnyValue() for all cases except delete */
if (m_use_any_value)
=== modified file 'storage/ndb/src/ndbapi/NdbTransaction.cpp'
--- a/storage/ndb/src/ndbapi/NdbTransaction.cpp 2010-08-09 10:20:17 +0000
+++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp 2010-09-22 10:49:11 +0000
@@ -2025,6 +2025,7 @@ NdbTransaction::receiveTCKEY_FAILCONF(co
case NdbOperation::DeleteRequest:
case NdbOperation::WriteRequest:
case NdbOperation::UnlockRequest:
+ case NdbOperation::RefreshRequest:
tOp = tOp->next();
break;
case NdbOperation::ReadRequest:
@@ -2597,6 +2598,41 @@ NdbTransaction::writeTuple(const NdbReco
return op;
}
+const NdbOperation *
+NdbTransaction::refreshTuple(const NdbRecord *key_rec, const char *key_row,
+ const NdbOperation::OperationOptions *opts,
+ Uint32 sizeOfOptions)
+{
+ /* Check that the NdbRecord specifies the full primary key. */
+ if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
+ {
+ setOperationErrorCodeAbort(4292);
+ return NULL;
+ }
+
+ Uint8 keymask[NDB_MAX_ATTRIBUTES_IN_TABLE/8];
+ bzero(keymask, sizeof(keymask));
+ for (Uint32 i = 0; i<key_rec->key_index_length; i++)
+ {
+ Uint32 id = key_rec->columns[key_rec->key_indexes[i]].attrId;
+ keymask[(id / 8)] |= (1 << (id & 7));
+ }
+
+ NdbOperation *op= setupRecordOp(NdbOperation::RefreshRequest,
+ NdbOperation::LM_Exclusive,
+ NdbOperation::AbortOnError,
+ key_rec, key_row,
+ key_rec, key_row,
+ keymask /* mask */,
+ opts,
+ sizeOfOptions);
+ if(!op)
+ return op;
+
+ theSimpleState= 0;
+
+ return op;
+}
NdbScanOperation *
NdbTransaction::scanTable(const NdbRecord *result_record,
=== modified file 'storage/ndb/test/include/HugoOperations.hpp'
--- a/storage/ndb/test/include/HugoOperations.hpp 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/test/include/HugoOperations.hpp 2010-09-22 10:49:11 +0000
@@ -87,6 +87,10 @@ public:
int recordNo,
int numRecords = 1);
+ int pkRefreshRecord(Ndb*,
+ int recordNo,
+ int numRecords = 1);
+
int execute_Commit(Ndb*,
AbortOption ao = AbortOnError);
int execute_NoCommit(Ndb*,
@@ -109,6 +113,9 @@ public:
int rowId);
int equalForRow(NdbOperation*, int rowid);
+ int equalForRecord(const NdbRecord*, char * buffer, int rowid);
+ int setValueForRecord(const NdbRecord*, char * buffer, int rowid,
+ const NdbDictionary::Column*);
bool getPartIdForRow(const NdbOperation* pOp, int rowid, Uint32& partId);
=== modified file 'storage/ndb/test/include/HugoTransactions.hpp'
--- a/storage/ndb/test/include/HugoTransactions.hpp 2010-02-18 23:50:31 +0000
+++ b/storage/ndb/test/include/HugoTransactions.hpp 2010-09-22 10:49:11 +0000
@@ -110,6 +110,9 @@ public:
int batch = 1,
bool allowConstraintViolation = true,
int doSleep = 0);
+
+ int pkRefreshRecords(Ndb*, int startFrom, int count = 1, int batch = 1);
+
int lockRecords(Ndb*,
int records,
int percentToLock = 1,
=== modified file 'storage/ndb/test/ndbapi/testRestartGci.cpp'
--- a/storage/ndb/test/ndbapi/testRestartGci.cpp 2010-09-15 09:43:39 +0000
+++ b/storage/ndb/test/ndbapi/testRestartGci.cpp 2010-09-22 10:49:11 +0000
@@ -29,10 +29,12 @@
*/
struct SavedRecord {
- int m_gci;
+ Uint64 m_gci;
+ Uint32 m_author;
BaseString m_str;
- SavedRecord(int _gci, BaseString _str){
+ SavedRecord(Uint64 _gci, Uint32 _author, BaseString _str){
m_gci = _gci;
+ m_author = _author;
m_str.assign(_str);
}
SavedRecord(){
@@ -41,7 +43,7 @@ struct SavedRecord {
};
};
Vector<SavedRecord> savedRecords;
-
+Uint64 highestExpectedGci;
#define CHECK(b) if (!(b)) { \
ndbout << "ERR: "<< step->getName() \
@@ -49,6 +51,109 @@ Vector<SavedRecord> savedRecords;
result = NDBT_FAILED; \
break; }
+static
+int
+maybeExtraBits(Ndb* ndb, NdbDictionary::Table& tab, int when, void* arg)
+{
+ switch(when){
+ case 0: // Before
+ break;
+ case 1: // After
+ return 0;
+ default:
+ return 0;
+ }
+
+ bool useExtendedBits = ((rand() % 5) != 0);
+ Uint32 numGciBits= rand() % 32; /* 0 -> 31 */
+ Uint32 numAuthorBits = rand() % 32; /* 0 -> 31 */
+
+ if (useExtendedBits && (numGciBits || numAuthorBits))
+ {
+ ndbout_c("Creating table %s with %u extra Gci and %u extra Author bits",
+ tab.getName(), numGciBits, numAuthorBits);
+ tab.setExtraRowGciBits(numGciBits);
+ tab.setExtraRowAuthorBits(numAuthorBits);
+ }
+ else
+ {
+ ndbout_c("Table has no extra bits");
+ }
+
+ return 0;
+}
+
+int runDropTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+ GETNDB(step)->getDictionary()->dropTable(ctx->getTableName(0));
+ return NDBT_OK;
+}
+
+int runCreateTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+
+ runDropTable(ctx, step);
+
+ /* Use extra proc to control whether we have extra bits */
+ if (NDBT_Tables::createTable(GETNDB(step),
+ ctx->getTableName(0),
+ false, false,
+ maybeExtraBits) == NDBT_OK)
+ {
+ ctx->setTab(GETNDB(step)->
+ getDictionary()->
+ getTable(ctx->getTableName(0)));
+ return NDBT_OK;
+ }
+ return NDBT_FAILED;
+}
+
+int setRowInNdbRecordBuff(NDBT_Context* ctx,
+ NDBT_Step* step,
+ Uint32 recNum,
+ Uint32 updateCount,
+ char* buff,
+ Uint32 buffLen)
+{
+ int result = NDBT_OK;
+ const NdbDictionary::Table* tab = ctx->getTab();
+ do
+ {
+ const NdbRecord* rec = tab->getDefaultRecord();
+ CHECK(rec != NULL);
+ HugoCalculator calc(*tab);
+ Uint32 attrId;
+ CHECK(NdbDictionary::getFirstAttrId(rec, attrId));
+
+ do
+ {
+ /* Calculate value for this column 'into' correct
+ * position in buffer
+ */
+ char attrBuf[NDB_MAX_TUPLE_SIZE];
+ char* valPtr = NdbDictionary::getValuePtr(rec,
+ buff,
+ attrId);
+ Uint32 colLen = tab->getColumn(attrId)->getSizeInBytes();
+
+ assert(((valPtr - buff) + colLen) < buffLen);
+
+ const char* calcPtr = calc.calcValue(recNum, attrId, updateCount,
+ attrBuf, colLen, &colLen);
+
+ if (calcPtr)
+ {
+ memcpy(valPtr, calcPtr, colLen);
+ }
+
+ if (tab->getColumn(attrId)->getNullable())
+ CHECK(NdbDictionary::setNull(rec, buff, attrId, (calcPtr == NULL)) == 0);
+ } while (NdbDictionary::getNextAttrId(rec, attrId));
+ } while (0);
+
+ return result;
+}
+
int runInsertRememberGci(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
int records = ctx->getNumRecords();
@@ -56,7 +161,15 @@ int runInsertRememberGci(NDBT_Context* c
Ndb* pNdb = GETNDB(step);
int i = 0;
- while(ctx->isTestStopped() == false && i < records){
+ ndbout_c("Inserting %u records", records);
+ Uint64 minGci = 0xffffffffffffffff;
+ Uint64 maxGci = 0;
+ Uint32 numAuthorBits = ctx->getTab()->getExtraRowAuthorBits();
+ Uint32 authorMask = (1 << numAuthorBits) -1;
+ ndbout_c("numAuthor bits is %u, mask is %x",
+ numAuthorBits, authorMask);
+
+ while(i < records){
// Insert record and read it in same transaction
CHECK(hugoOps.startTransaction(pNdb) == 0);
CHECK(hugoOps.pkInsertRecord(pNdb, i) == 0);
@@ -65,14 +178,50 @@ int runInsertRememberGci(NDBT_Context* c
result = NDBT_FAILED;
break;
}
+ /* Set the author column (if present) */
+ Uint32 authorVal = 0;
+ if (ctx->getTab()->getExtraRowAuthorBits() > 0)
+ {
+ authorVal = (rand() & authorMask);
+ /* Pain here due to need to use NdbRecord */
+ char rowBuff[NDB_MAX_TUPLE_SIZE];
+ const NdbDictionary::Table* tab = ctx->getTab();
+ CHECK(setRowInNdbRecordBuff(ctx, step, i, 0, rowBuff,
+ sizeof(rowBuff)) == NDBT_OK);
+ NdbOperation::SetValueSpec setValueSpec;
+ setValueSpec.column = NdbDictionary::Column::ROW_AUTHOR;
+ setValueSpec.value = &authorVal;
+ NdbOperation::OperationOptions opts;
+ opts.optionsPresent= NdbOperation::OperationOptions::OO_SETVALUE;
+ opts.extraSetValues= &setValueSpec;
+ opts.numExtraSetValues = 1;
+
+ const NdbOperation* update = hugoOps.getTransaction()->
+ updateTuple(tab->getDefaultRecord(), rowBuff,
+ tab->getDefaultRecord(), rowBuff,
+ NULL, /* mask */
+ &opts,
+ sizeof(opts));
+ CHECK(update != NULL);
+ }
+ /* Read row back */
CHECK(hugoOps.pkReadRecord(pNdb, i) == 0);
if (hugoOps.execute_Commit(pNdb) != 0){
ndbout << "Did not find record in DB " << i << endl;
result = NDBT_FAILED;
break;
}
- savedRecords.push_back(SavedRecord(hugoOps.getRecordGci(0),
- hugoOps.getRecordStr(0)));
+ Uint64 gci;
+ CHECK(hugoOps.getTransaction()->getGCI(&gci) == 0);
+
+ if (gci < minGci)
+ minGci = gci;
+ if (gci > maxGci)
+ maxGci = gci;
+
+ savedRecords.push_back(SavedRecord(gci,
+ authorVal,
+ hugoOps.getRecordStr(0)));
CHECK(hugoOps.closeTransaction(pNdb) == 0);
i++;
@@ -80,13 +229,21 @@ int runInsertRememberGci(NDBT_Context* c
NdbSleep_MilliSleep(10);
};
+ ndbout_c(" Inserted records from gci %x/%x to gci %x/%x",
+ (Uint32) (minGci >> 32), (Uint32) (minGci & 0xffffffff),
+ (Uint32) (maxGci >> 32), (Uint32) (maxGci & 0xffffffff));
+
+ highestExpectedGci = maxGci;
+
return result;
}
-int runRestart(NDBT_Context* ctx, NDBT_Step* step){
+int runRestartAll(NDBT_Context* ctx, NDBT_Step* step){
Ndb* pNdb = GETNDB(step);
NdbRestarter restarter;
+ ndbout_c("Restart of all nodes");
+
// Restart cluster with abort
if (restarter.restartAll(false, false, true) != 0){
ctx->stopTest();
@@ -104,6 +261,42 @@ int runRestart(NDBT_Context* ctx, NDBT_S
return NDBT_OK;
}
+int runRestartOneInitial(NDBT_Context* ctx, NDBT_Step* step){
+ Ndb* pNdb = GETNDB(step);
+ NdbRestarter restarter;
+
+ if (restarter.getNumDbNodes() < 2)
+ return NDBT_OK;
+
+ /* We don't restart the Master as we need to know a
+ * non-restarted node to reliably get the restartGci
+ * afterwards!
+ * Should be no real reason not to restart the master.
+ */
+ int node = restarter.getRandomNotMasterNodeId(rand());
+ ndbout_c("Restarting node %u initial", node);
+
+ if (restarter.restartOneDbNode(node,
+ true, /* Initial */
+ false, /* Nostart */
+ true) /* Abort */
+ != 0)
+ {
+ ctx->stopTest();
+ return NDBT_FAILED;
+ }
+
+ if (restarter.waitClusterStarted(300) != 0){
+ return NDBT_FAILED;
+ }
+
+ if (pNdb->waitUntilReady() != 0){
+ return NDBT_FAILED;
+ }
+
+ return NDBT_OK;
+}
+
int runRestartGciControl(NDBT_Context* ctx, NDBT_Step* step){
int records = ctx->getNumRecords();
Ndb* pNdb = GETNDB(step);
@@ -119,10 +312,31 @@ int runRestartGciControl(NDBT_Context* c
NdbSleep_MilliSleep(10);
}
- // Stop the other thread
- ctx->stopTest();
+ return runRestartAll(ctx,step);
+}
- return runRestart(ctx,step);
+int runDetermineRestartGci(NDBT_Context* ctx, NDBT_Step* step)
+{
+ Ndb* pNdb = GETNDB(step);
+ int restartGci = pNdb->NdbTamper(Ndb::ReadRestartGCI, 0);
+
+ ndbout_c("Restart GCI is %u (0x%x)",
+ restartGci, restartGci);
+
+ ndbout_c("Highest expected GCI was %x/%x",
+ (Uint32) (highestExpectedGci >> 32),
+ (Uint32) (highestExpectedGci & 0xffffffff));
+
+ highestExpectedGci = ((Uint64) restartGci) << 32 | 0xffffffff;
+ ndbout_c("Resetting Highest expected GCI to align with restart Gci (%x/%x)",
+ (Uint32) (highestExpectedGci >> 32),
+ (Uint32) (highestExpectedGci & 0xffffffff));
+ return NDBT_OK;
+}
+
+int runRequireExact(NDBT_Context* ctx, NDBT_Step* step){
+ ctx->incProperty("ExactGCI");
+ return NDBT_OK;
}
int runVerifyInserts(NDBT_Context* ctx, NDBT_Step* step){
@@ -132,9 +346,6 @@ int runVerifyInserts(NDBT_Context* ctx,
HugoOperations hugoOps(*ctx->getTab());
NdbRestarter restarter;
- int restartGCI = pNdb->NdbTamper(Ndb::ReadRestartGCI, 0);
-
- ndbout << "restartGCI = " << restartGCI << endl;
int count = 0;
if (utilTrans.selectCount(pNdb, 64, &count) != 0){
return NDBT_FAILED;
@@ -145,7 +356,7 @@ int runVerifyInserts(NDBT_Context* ctx,
int recordsWithLowerOrSameGci = 0;
unsigned i;
for (i = 0; i < savedRecords.size(); i++){
- if (savedRecords[i].m_gci <= restartGCI)
+ if (savedRecords[i].m_gci <= highestExpectedGci)
recordsWithLowerOrSameGci++;
}
if (recordsWithLowerOrSameGci != count){
@@ -153,10 +364,13 @@ int runVerifyInserts(NDBT_Context* ctx,
result = NDBT_FAILED;
}
+ bool exactGCIonly = ctx->getProperty("ExactGCI", (unsigned) 0);
// RULE2: The records found in db should have same or lower
// gci as in the vector
int recordsWithIncorrectGci = 0;
+ int recordsWithRoundedGci = 0;
+ int recordsWithIncorrectAuthor = 0;
for (i = 0; i < savedRecords.size(); i++){
CHECK(hugoOps.startTransaction(pNdb) == 0);
/* First read of row to check contents */
@@ -167,13 +381,15 @@ int runVerifyInserts(NDBT_Context* ctx,
CHECK(readOp != NULL);
CHECK(readOp->readTuple() == 0);
CHECK(hugoOps.equalForRow(readOp, i) == 0);
- NdbRecAttr* rowGci = readOp->getValue(NdbDictionary::Column::ROW_GCI);
+ NdbRecAttr* rowGci = readOp->getValue(NdbDictionary::Column::ROW_GCI64);
+ NdbRecAttr* rowAuthor = readOp->getValue(NdbDictionary::Column::ROW_AUTHOR);
CHECK(rowGci != NULL);
+ CHECK(rowAuthor != NULL);
if (hugoOps.execute_Commit(pNdb) != 0){
// Record was not found in db'
// Check record gci
- if (savedRecords[i].m_gci <= restartGCI){
+ if (savedRecords[i].m_gci <= highestExpectedGci){
ndbout << "ERR: Record "<<i<<" should have existed" << endl;
result = NDBT_FAILED;
}
@@ -183,7 +399,7 @@ int runVerifyInserts(NDBT_Context* ctx,
* Let's disappear it, so that it doesn't cause confusion
* after further restarts.
*/
- savedRecords[i].m_gci = (Uint32(1) << 31) -1; // Big number
+ savedRecords[i].m_gci = (Uint64(1) << 63) -1; // Big number
}
} else {
// Record was found in db
@@ -194,16 +410,42 @@ int runVerifyInserts(NDBT_Context* ctx,
result = NDBT_FAILED;
}
// Check record gci in range
- if (savedRecords[i].m_gci > restartGCI){
+ if (savedRecords[i].m_gci > highestExpectedGci){
ndbout << "ERR: Record "<<i<<" should not have existed" << endl;
result = NDBT_FAILED;
}
// Check record gci is exactly correct
- if (savedRecords[i].m_gci != rowGci->int32_value()){
- ndbout << "ERR: Record "<<i<<" should have GCI " <<
- savedRecords[i].m_gci << ", but has " <<
- rowGci->int32_value() << endl;
- recordsWithIncorrectGci++;
+ if (savedRecords[i].m_gci != rowGci->u_64_value()){
+ Uint64 expectedRoundedGci = (savedRecords[i].m_gci | 0xffffffff);
+ if ((!exactGCIonly) &&
+ (expectedRoundedGci != rowGci->u_64_value()))
+ {
+ ndbout_c("ERR: Record %u should have GCI %x/%x, but has "
+ "%x/%x.",
+ i,
+ (Uint32) (savedRecords[i].m_gci >> 32),
+ (Uint32) (savedRecords[i].m_gci & 0xffffffff),
+ (Uint32) (rowGci->u_64_value() >> 32),
+ (Uint32) (rowGci->u_64_value() & 0xffffffff));
+ recordsWithIncorrectGci++;
+ result = NDBT_FAILED;
+ }
+ else
+ {
+ recordsWithRoundedGci++;
+ }
+ }
+
+ // Check author value is correct.
+ Uint32 expectedAuthor = savedRecords[i].m_author;
+
+ if (rowAuthor->u_32_value() != expectedAuthor)
+ {
+ ndbout_c("ERR: Record %u should have Author %d, but has %d.",
+ i,
+ expectedAuthor,
+ rowAuthor->u_32_value());
+ recordsWithIncorrectAuthor++;
result = NDBT_FAILED;
}
}
@@ -216,17 +458,26 @@ int runVerifyInserts(NDBT_Context* ctx,
ndbout << "There are " << savedRecords.size()
<< " records in vector" << endl;
- ndbout << "There are " << recordsWithLowerOrSameGci
- << " records with lower or same gci than " << restartGCI << endl;
+ ndbout_c("There are %u records with lower or same gci than %x/%x",
+ recordsWithLowerOrSameGci,
+ (Uint32)(highestExpectedGci >> 32),
+ (Uint32)(highestExpectedGci & 0xffffffff));
+ ndbout_c("There are %u records with rounded Gcis. Exact GCI flag is %u",
+ recordsWithRoundedGci, exactGCIonly);
+
ndbout << "There are " << recordsWithIncorrectGci
<< " records with incorrect Gci on recovery." << endl;
+ ndbout << "There are " << recordsWithIncorrectAuthor
+ << " records with incorrect Author on recovery." << endl;
+
return result;
}
int runClearGlobals(NDBT_Context* ctx, NDBT_Step* step){
savedRecords.clear();
+ highestExpectedGci = 0;
return NDBT_OK;
}
@@ -245,23 +496,50 @@ NDBT_TESTSUITE(testRestartGci);
TESTCASE("InsertRestartGci",
"Verify that only expected records are still in NDB\n"
"after a restart" ){
- INITIALIZER(runClearTable);
+ INITIALIZER(runCreateTable);
INITIALIZER(runClearGlobals);
- STEP(runInsertRememberGci);
- STEP(runRestartGciControl);
+ INITIALIZER(runInsertRememberGci);
+ INITIALIZER(runRestartGciControl);
+ INITIALIZER(runDetermineRestartGci);
+ TC_PROPERTY("ExactGCI", Uint32(0)); /* Recovery from Redo == inexact low word */
VERIFIER(runVerifyInserts);
/* Restart again - LCP after first restart will mean that this
* time we recover from LCP, not Redo
*/
- VERIFIER(runRestart);
+ VERIFIER(runRestartAll);
+ VERIFIER(runDetermineRestartGci);
+ VERIFIER(runVerifyInserts); // Check GCIs again
+ /* Restart again - one node, initial. This will check
+ * COPYFRAG behaviour
+ */
+ VERIFIER(runRestartOneInitial);
VERIFIER(runVerifyInserts); // Check GCIs again
+ VERIFIER(runClearTable);
+ /* Re-fill table with records, will just be in Redo
+ * Then restart, testing COPYFRAG behaviour with
+ * non #ffff... low word
+ */
+ VERIFIER(runClearGlobals);
+ VERIFIER(runInsertRememberGci);
+ VERIFIER(runRestartOneInitial);
+ /* Require exact GCI match from here - no Redo messing it up */
+ VERIFIER(runRequireExact);
+ VERIFIER(runVerifyInserts);
+ /* Now-restart all nodes - all inserts should be
+ * in LCP, and should be restored correctly
+ */
+ VERIFIER(runRestartAll);
+ VERIFIER(runDetermineRestartGci);
+ VERIFIER(runVerifyInserts);
FINALIZER(runClearTable);
+ FINALIZER(runDropTable);
}
NDBT_TESTSUITE_END(testRestartGci);
int main(int argc, const char** argv){
ndb_init();
NDBT_TESTSUITE_INSTANCE(testRestartGci);
+ testRestartGci.setCreateTable(false);
return testRestartGci.execute(argc, argv);
}
=== modified file 'storage/ndb/test/src/HugoOperations.cpp'
--- a/storage/ndb/test/src/HugoOperations.cpp 2010-05-17 06:56:12 +0000
+++ b/storage/ndb/test/src/HugoOperations.cpp 2010-09-22 10:49:11 +0000
@@ -568,6 +568,39 @@ int HugoOperations::pkDeleteRecord(Ndb*
return NDBT_OK;
}
+int HugoOperations::pkRefreshRecord(Ndb* pNdb,
+ int recordNo,
+ int numRecords){
+
+ char buffer[NDB_MAX_TUPLE_SIZE];
+ const NdbDictionary::Table * pTab =
+ pNdb->getDictionary()->getTable(tab.getName());
+
+ if (pTab == 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ const NdbRecord * record = pTab->getDefaultRecord();
+ for(int r=0; r < numRecords; r++)
+ {
+ bzero(buffer, sizeof(buffer));
+ if (equalForRecord(record, buffer, r + recordNo))
+ {
+ return NDBT_FAILED;
+ }
+
+ const NdbOperation* pOp = pTrans->refreshTuple(record, buffer);
+ if (pOp == NULL)
+ {
+ ERR(pTrans->getNdbError());
+ setNdbError(pTrans->getNdbError());
+ return NDBT_FAILED;
+ }
+ }
+ return NDBT_OK;
+}
+
int HugoOperations::execute_Commit(Ndb* pNdb,
AbortOption eao){
@@ -794,6 +827,43 @@ HugoOperations::equalForRow(NdbOperation
return NDBT_OK;
}
+int
+HugoOperations::equalForRecord(const NdbRecord* record,
+ char * buffer, int rowId)
+{
+ for(int a = 0; a<tab.getNoOfColumns(); a++)
+ {
+ const NdbDictionary::Column* attr = tab.getColumn(a);
+ if (attr->getPrimaryKey() == true)
+ {
+ setValueForRecord(record, buffer, rowId, attr);
+ }
+ }
+ return NDBT_OK;
+}
+
+int
+HugoOperations::setValueForRecord(const NdbRecord* record,
+ char * buffer, int rowId,
+ const NdbDictionary::Column* attr)
+{
+ Uint32 attrId = attr->getColumnNo();
+ int len = attr->getSizeInBytes();
+ char buf[NDB_MAX_TUPLE_SIZE];
+ memset(buf, 0, sizeof(buf));
+ Uint32 real_len;
+ const char * value = calc.calcValue(rowId, attrId, 0, buf, len, &real_len);
+ if (value == 0)
+ {
+ NdbDictionary::setNull(record, buffer, attrId, true);
+ }
+ else
+ {
+ memcpy(NdbDictionary::getValuePtr(record, buffer, attrId), buf, real_len);
+ }
+ return NDBT_OK;
+}
+
bool HugoOperations::getPartIdForRow(const NdbOperation* pOp,
int rowid,
Uint32& partId)
=== modified file 'storage/ndb/test/src/HugoTransactions.cpp'
--- a/storage/ndb/test/src/HugoTransactions.cpp 2010-02-18 23:50:31 +0000
+++ b/storage/ndb/test/src/HugoTransactions.cpp 2010-09-22 10:49:11 +0000
@@ -1502,6 +1502,79 @@ HugoTransactions::pkDelRecords(Ndb* pNdb
}
int
+HugoTransactions::pkRefreshRecords(Ndb* pNdb,
+ int startFrom,
+ int count,
+ int batch)
+{
+ int r = 0;
+ int retryAttempt = 0;
+
+ g_info << "|- Refreshing records..." << startFrom << "-" << (startFrom+count)
+ << " (batch=" << batch << ")" << endl;
+
+ while (r < count)
+ {
+ if(r + batch > count)
+ batch = count - r;
+
+ if (retryAttempt >= m_retryMax)
+ {
+ g_info << "ERROR: has retried this operation " << retryAttempt
+ << " times, failing!" << endl;
+ return NDBT_FAILED;
+ }
+
+ pTrans = pNdb->startTransaction();
+ if (pTrans == NULL)
+ {
+ const NdbError err = pNdb->getNdbError();
+
+ if (err.status == NdbError::TemporaryError){
+ ERR(err);
+ NdbSleep_MilliSleep(50);
+ retryAttempt++;
+ continue;
+ }
+ ERR(err);
+ return NDBT_FAILED;
+ }
+
+ if (pkRefreshRecord(pNdb, r, batch) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
+ }
+
+ if (pTrans->execute(Commit, AbortOnError) == -1)
+ {
+ const NdbError err = pTrans->getNdbError();
+
+ switch(err.status){
+ case NdbError::TemporaryError:
+ ERR(err);
+ closeTransaction(pNdb);
+ NdbSleep_MilliSleep(50);
+ retryAttempt++;
+ continue;
+ break;
+
+ default:
+ ERR(err);
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
+ }
+ }
+
+ closeTransaction(pNdb);
+ r += batch; // Read next record
+ }
+
+ return NDBT_OK;
+}
+
+int
HugoTransactions::pkReadUnlockRecords(Ndb* pNdb,
int records,
int batch,
=== modified file 'storage/ndb/test/src/NDBT_Table.cpp'
--- a/storage/ndb/test/src/NDBT_Table.cpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/test/src/NDBT_Table.cpp 2010-09-22 10:49:11 +0000
@@ -39,6 +39,8 @@ operator <<(class NdbOut& ndbout, const
ndbout << "SingleUserMode: " << (Uint32) tab.getSingleUserMode() << endl;
ndbout << "ForceVarPart: " << tab.getForceVarPart() << endl;
ndbout << "FragmentCount: " << tab.getFragmentCount() << endl;
+ ndbout << "ExtraRowGciBits: " << tab.getExtraRowGciBits() << endl;
+ ndbout << "ExtraRowAuthorBits: " << tab.getExtraRowAuthorBits() << endl;
//<< ((tab.getTupleKey() == TupleId) ? " tupleid" : "") <<endl;
ndbout << "TableStatus: ";
=== modified file 'storage/ndb/test/tools/hugoPkUpdate.cpp'
--- a/storage/ndb/test/tools/hugoPkUpdate.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/test/tools/hugoPkUpdate.cpp 2010-09-22 10:49:11 +0000
@@ -43,6 +43,8 @@ struct ThrOutput {
NDBT_Stats latency;
};
+static int _refresh = 0;
+
int main(int argc, const char** argv){
ndb_init();
@@ -63,7 +65,9 @@ int main(int argc, const char** argv){
// { "batch", 'b', arg_integer, &_batch, "batch value", "batch" },
{ "records", 'r', arg_integer, &_records, "Number of records", "records" },
{ "usage", '?', arg_flag, &_help, "Print help", "" },
- { "database", 'd', arg_string, &db, "Database", "" }
+ { "database", 'd', arg_string, &db, "Database", "" },
+ { "refresh", 0, arg_flag, &_refresh, "refresh record rather than update them", "" }
+
};
int num_args = sizeof(args) / sizeof(args[0]);
int optind = 0;
@@ -177,9 +181,19 @@ static void hugoPkUpdate(NDBT_Thread& th
hugoTrans.setThrInfo(ths.get_count(), thr.get_thread_no());
int ret;
- ret = hugoTrans.pkUpdateRecords(thr.get_ndb(),
- input->records,
- input->batch);
+ if (_refresh == 0)
+ {
+ ret = hugoTrans.pkUpdateRecords(thr.get_ndb(),
+ input->records,
+ input->batch);
+ }
+ else
+ {
+ ret = hugoTrans.pkRefreshRecords(thr.get_ndb(),
+ 0,
+ input->records,
+ input->batch);
+ }
if (ret != 0)
thr.set_err(ret);
}
=== modified file 'storage/ndb/tools/select_all.cpp'
--- a/storage/ndb/tools/select_all.cpp 2010-05-04 14:34:54 +0000
+++ b/storage/ndb/tools/select_all.cpp 2010-09-22 10:49:11 +0000
@@ -50,6 +50,8 @@ static int _dumpDisk = 0;
static int use_rowid = 0;
static int nodata = 0;
static int use_gci = 0;
+static int use_gci64 = 0;
+static int use_author = 0;
static struct my_option my_long_options[] =
{
@@ -87,6 +89,12 @@ static struct my_option my_long_options[
{ "gci", NDB_OPT_NOSHORT, "Dump gci",
(uchar**) &use_gci, (uchar**) &use_gci, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "gci64", NDB_OPT_NOSHORT, "Dump ROW$GCI64",
+ (uchar**) &use_gci64, (uchar**) &use_gci64, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "author", NDB_OPT_NOSHORT, "Dump ROW$AUTHOR",
+ (uchar**) &use_author, (uchar**) &use_author, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "tupscan", 't', "Scan in tup order",
(uchar**) &_tup, (uchar**) &_tup, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
@@ -329,7 +337,7 @@ int scanReadRecords(Ndb* pNdb,
if(_dumpDisk && disk)
disk_ref = pOp->getValue(NdbDictionary::Column::DISK_REF);
- NdbRecAttr * rowid= 0, *frag = 0, *gci = 0;
+ NdbRecAttr * rowid= 0, *frag = 0, *gci = 0, *gci64 = 0, *author = 0;
if (use_rowid)
{
frag = pOp->getValue(NdbDictionary::Column::FRAGMENT);
@@ -340,7 +348,17 @@ int scanReadRecords(Ndb* pNdb,
{
gci = pOp->getValue(NdbDictionary::Column::ROW_GCI);
}
+
+ if (use_gci64)
+ {
+ gci64 = pOp->getValue(NdbDictionary::Column::ROW_GCI64);
+ }
+ if (use_author)
+ {
+ author = pOp->getValue(NdbDictionary::Column::ROW_AUTHOR);
+ }
+
check = pTrans->execute(NdbTransaction::NoCommit);
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
@@ -387,6 +405,18 @@ int scanReadRecords(Ndb* pNdb,
ndbout << "DISK_REF";
}
+ if (gci64)
+ {
+ DELIMITER;
+ ndbout << "ROW$GCI64";
+ }
+
+ if (author)
+ {
+ DELIMITER;
+ ndbout << "ROW$AUTHOR";
+ }
+
ndbout << endl;
}
#undef DELIMITER
@@ -427,8 +457,30 @@ int scanReadRecords(Ndb* pNdb,
<< " m_page: " << disk_ref->u_32_value()
<< " m_page_idx: " << *(Uint16*)(disk_ref->aRef() + 4) << " ]";
}
+
+ if (gci64)
+ {
+ if (gci64->isNULL())
+ ndbout << "NULL\t";
+ else
+ {
+ Uint64 tmp = gci64->u_64_value();
+ ndbout << Uint32(tmp >> 32) << "/" << Uint32(tmp) << "\t";
+ }
+ }
+
+ if (author)
+ {
+ if (author->isNULL())
+ ndbout << "NULL\t";
+ else
+ {
+ ndbout << author->u_32_value() << "\t";
+ }
+ }
+
- if (rowid || disk_ref || gci || !nodata)
+ if (rowid || disk_ref || gci || !nodata || gci64 || author)
ndbout << endl;
eof = pOp->nextResult();
}
Attachment: [text/bzr-bundle] bzr/frazer@mysql.com-20100922104911-zdy23qg5ofrvdu7k.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0 branch (frazer:3773) | Frazer Clement | 22 Sep |