459 lines
15 KiB
Plaintext
459 lines
15 KiB
Plaintext
# ==== Purpose ====
|
|
#
|
|
# Test timestamps generated by binlog-transaction-dependency-tracking
|
|
# modes WRITESET, WRITESET_SESSION and COMMIT_ORDER.
|
|
#
|
|
# The following properties are tested:
|
|
# - With binlog-transaction-dependency-tracking=WRITESET, the logical timestamps
|
|
# are generated as expected, marking each transaction as conflicting with
|
|
# transactions having intersecting writesets.
|
|
# (type = 0)
|
|
# - With binlog-transaction-dependency-tracking=WRITESET_SESSION, transactions
|
|
# are additionally marked as conflicting with all previous transactions in the
|
|
# same session.
|
|
# (type = 1)
|
|
# - Additionally, transactions are marked as conflicting with any DDL.
|
|
# (step = 2)
|
|
# - Additionally, transactions are marked as conflicting if one appears before
|
|
# and the other after a binlog rotation.
|
|
# (step = 3)
|
|
# - Additionally, transactions are marked as conflicting if the writeset history
|
|
# was cleared between the transactions.
|
|
# (step = 4)
|
|
#
|
|
# - It tests this for INSERT, UPDATE and DELETE statements.
|
|
#
|
|
# ==== Implementation ====
|
|
#
|
|
# 1. Apply 8 transactions with different data dependencies and check the binary
|
|
# log generated (step 1). Do the same with DDL in the middle (step 2), with
|
|
# rotation (step 3) and when writeset history becomes full (step 4).
|
|
#
|
|
# 2. Test Bug#2561672: POST RESET MASTER/FLUSH LOGS SETTING BTDT=WRITESET
|
|
# BEHAVES LIKE COMMIT_ORDER
|
|
#
|
|
# 3. Test ROLLBACK TO SAVEPOINT.
|
|
#
|
|
# ==== References ====
|
|
#
|
|
# WL#9556: Writeset-based MTS dependency tracking on master
|
|
#
|
|
|
|
--source include/master-slave.inc
|
|
--source include/have_binlog_format_row.inc
|
|
|
|
--echo #### INITIALIZE ####
|
|
|
|
--connection slave
|
|
call mtr.add_suppression("Transaction is tagged with inconsistent logical timestamps");
|
|
call mtr.add_suppression("Cannot execute the current event group in the parallel mode.");
|
|
|
|
--source include/stop_slave.inc
|
|
|
|
SET @save_slave_parallel_type = @@GLOBAL.slave_parallel_type;
|
|
SET @save_slave_parallel_workers = @@GLOBAL.slave_parallel_workers;
|
|
SET @save_slave_transaction_retries = @@GLOBAL.slave_transaction_retries;
|
|
|
|
SET GLOBAL slave_parallel_type = LOGICAL_CLOCK;
|
|
SET GLOBAL slave_parallel_workers = 3;
|
|
SET GLOBAL slave_transaction_retries = 0;
|
|
|
|
--connection master
|
|
|
|
SET @save_binlog_transaction_dependency_tracking = @@GLOBAL.binlog_transaction_dependency_tracking;
|
|
SET @save_binlog_transaction_dependency_history_size = @@GLOBAL.binlog_transaction_dependency_history_size;
|
|
SET @save_transaction_write_set_extraction = @@GLOBAL.transaction_write_set_extraction;
|
|
|
|
# for step 4
|
|
SET GLOBAL binlog_transaction_dependency_tracking = COMMIT_ORDER;
|
|
|
|
SET GLOBAL transaction_write_set_extraction = XXHASH64;
|
|
SET LOCAL transaction_write_set_extraction = XXHASH64;
|
|
|
|
--connection master1
|
|
SET LOCAL transaction_write_set_extraction = XXHASH64;
|
|
|
|
--connection server_1
|
|
SET LOCAL transaction_write_set_extraction = XXHASH64;
|
|
|
|
--connection master
|
|
|
|
CREATE TABLE tests (`id` INT NOT NULL, `description` VARCHAR(50), `results` VARCHAR(100), PRIMARY KEY(`id`));
|
|
INSERT INTO `tests` (`id`, `description`, `results`) VALUES
|
|
(1, 'Writeset', '0 1;1 2;1 3;1 4;3 5;3 6;4 7;7 8;6 9;9 10'),
|
|
(2, 'Writeset+DDL', '0 1;1 2;1 3;1 4;4 5;5 6;6 7;7 8;4 9;7 10;10 11;9 12;12 13'),
|
|
(3, 'Writeset+rotation', '0 1;0 2;1 3;3 4;2 5;5 6'),
|
|
(4, 'Writeset+history', '0 1;1 2;1 3;1 4;4 5;4 6;6 7;7 8;6 9;9 10'),
|
|
(5, 'Writeset_session', '0 1;1 2;1 3;2 4;3 5;3 6;5 7;7 8;7 9;9 10'),
|
|
(6, 'Writeset_session+DDL', '0 1;1 2;1 3;2 4;4 5;5 6;6 7;7 8;4 9;8 10;10 11;10 12;12 13'),
|
|
(7, 'Writeset_session+rotation', '0 1;0 2;1 3;3 4;3 5;5 6'),
|
|
(8, 'Writeset_session+history', '0 1;1 2;1 3;2 4;4 5;4 6;6 7;7 8;7 9;9 10'),
|
|
(9, 'Commit_order', '0 1;1 2;1 3;3 4;4 5;4 6;6 7;7 8;7 9;9 10'),
|
|
(10, 'Commit_order+DDL', '0 1;1 2;1 3;3 4;4 5;5 6;6 7;7 8;4 9;9 10;10 11;10 12;12 13'),
|
|
(11, 'Commit_order+rotation', '0 1;0 2;2 3;3 4;3 5;5 6'),
|
|
(12, 'Commit_order+history', '0 1;1 2;1 3;3 4;4 5;4 6;6 7;7 8;7 9;9 10');
|
|
|
|
# flush logs to clear previous transactions
|
|
FLUSH LOGS;
|
|
|
|
--let $idx= 0
|
|
|
|
--echo #### TEST ####
|
|
|
|
# loop between WRITESET and WRITESET_SESSION
|
|
--let $type= 0
|
|
while ($type < 3)
|
|
{
|
|
--inc $type
|
|
|
|
--connection master
|
|
if ($type == 1)
|
|
{
|
|
SET GLOBAL binlog_transaction_dependency_tracking = WRITESET;
|
|
--echo ######## 1. WRITESET ########
|
|
}
|
|
if ($type == 2)
|
|
{
|
|
SET GLOBAL binlog_transaction_dependency_tracking = WRITESET_SESSION;
|
|
--echo ######## 2. WRITESET_SESSION ########
|
|
}
|
|
if ($type == 3)
|
|
{
|
|
SET GLOBAL binlog_transaction_dependency_tracking = COMMIT_ORDER;
|
|
--echo ######## 3. COMMIT_ORDER ########
|
|
}
|
|
|
|
# loop between steps
|
|
--let $step= 0
|
|
while ($step < 4)
|
|
{
|
|
--inc $step
|
|
--inc $idx
|
|
|
|
--let $testname=`SELECT description FROM tests WHERE id=$idx`
|
|
--echo #### STEP $type.$step TEST $testname ####
|
|
|
|
SET GLOBAL binlog_transaction_dependency_history_size=25000;
|
|
if ($step == 4)
|
|
{
|
|
--echo History size reduced to 5 to test when it becomes full
|
|
SET GLOBAL binlog_transaction_dependency_history_size=5;
|
|
}
|
|
|
|
SELECT @@local.transaction_write_set_extraction,
|
|
@@global.transaction_write_set_extraction,
|
|
@@binlog_transaction_dependency_tracking,
|
|
@@binlog_transaction_dependency_history_size;
|
|
|
|
CREATE TABLE `t1` (`id` int(11) NOT NULL, `val` int(11) NOT NULL,
|
|
PRIMARY KEY (`id`)) ENGINE=InnoDB;
|
|
|
|
--connection master
|
|
--echo #TRX2 (session A, independent)
|
|
BEGIN;
|
|
INSERT INTO t1(id, val) VALUES (1, 0),(2, 0),(3, 0);
|
|
|
|
--connection master1
|
|
--echo #TRX1 (session B, independent)
|
|
BEGIN;
|
|
INSERT INTO t1(id, val) VALUES (4, 0),(5, 0);
|
|
COMMIT;
|
|
|
|
--connection master
|
|
--echo finish TRX2 after TRX1
|
|
COMMIT;
|
|
|
|
--connection master1
|
|
--echo #TRX3 (session B, no data dependency, depends on TRX1 (session))
|
|
BEGIN;
|
|
INSERT INTO t1(id, val) VALUES (6, 0),(7, 0);
|
|
COMMIT;
|
|
|
|
--connection master
|
|
--echo #TRX5 (session A, depends on TRX2 (session and data) and TRX1(data))
|
|
BEGIN;
|
|
INSERT INTO t1(id, val) VALUES (8, 1);
|
|
UPDATE t1 SET val=val+1 WHERE id=1;
|
|
UPDATE t1 SET val=val+1 WHERE id=4;
|
|
|
|
if ($step == 2)
|
|
{
|
|
--connection master1
|
|
--echo Inserted a DDL after TRX5 and check that they run in parallel due to commit_order
|
|
CREATE TABLE `t2` (`id` int(11) NOT NULL, `val` int(11) NOT NULL) ENGINE=InnoDB;
|
|
ALTER TABLE t2 ADD COLUMN b INT;
|
|
DROP TABLE `t2`;
|
|
}
|
|
|
|
# flush logs in the middle
|
|
if ($step == 3)
|
|
{
|
|
--connection master1
|
|
--echo Flushing logs in the middle of the set
|
|
FLUSH LOGS;
|
|
}
|
|
|
|
--connection server_1
|
|
--echo #TRX4 (session C, depends on TRX2 (data))
|
|
BEGIN;
|
|
UPDATE t1 SET val=val+1 WHERE id=3;
|
|
INSERT INTO t1(id, val) VALUES (9, 1);
|
|
COMMIT;
|
|
|
|
--connection master
|
|
--echo finish TRX5 after TRX4
|
|
COMMIT;
|
|
|
|
--connection server_1
|
|
--echo #TRX6 (session C, depends on TRX4 (session) and TRX3(data))
|
|
BEGIN;
|
|
DELETE FROM t1 WHERE id=6;
|
|
COMMIT;
|
|
|
|
--connection server_1
|
|
--echo #TRX8 (session C, depends on TRX5 (data) and TRX6 (session))
|
|
BEGIN;
|
|
UPDATE t1 SET val=val+1 WHERE id=4;
|
|
|
|
--connection master1
|
|
--echo #TRX7 (session B, depends on TRX1 and TRX6 (data) and TRX3 (session))
|
|
BEGIN;
|
|
UPDATE t1 SET val=val+1 WHERE id=5;
|
|
INSERT INTO t1(id, val) VALUES (6, 0);
|
|
COMMIT;
|
|
|
|
--connection server_1
|
|
--echo finish TRX8 after TRX7
|
|
COMMIT;
|
|
|
|
--connection master
|
|
--echo Drop table and flush logs to force binlog to rotate
|
|
DROP TABLE t1;
|
|
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
--echo Processing binlog $binlog_file
|
|
FLUSH LOGS;
|
|
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=`SELECT results FROM tests WHERE id=$idx`
|
|
--source include/assert_logical_timestamps.inc
|
|
}
|
|
}
|
|
|
|
--echo
|
|
--echo #### Verify that replication was correct ####
|
|
|
|
--connection slave
|
|
--source include/start_slave.inc
|
|
|
|
--connection master
|
|
--source include/sync_slave_sql_with_master.inc
|
|
|
|
--let $diff_tables= master:test.tests, slave:test.tests
|
|
--source include/diff_tables.inc
|
|
|
|
--connection master
|
|
DROP TABLE `tests`;
|
|
--source include/sync_slave_sql_with_master.inc
|
|
|
|
--connection master
|
|
SET GLOBAL binlog_transaction_dependency_tracking= WRITESET;
|
|
SET GLOBAL binlog_transaction_dependency_history_size= DEFAULT;
|
|
FLUSH LOGS;
|
|
|
|
--echo
|
|
--echo #### Bug#25616372, PART1 ####
|
|
CREATE TABLE t1 (a INT PRIMARY KEY NOT NULL AUTO_INCREMENT); # 0 1
|
|
INSERT INTO t1 VALUES (null); # 1 2
|
|
INSERT INTO t1 VALUES (null); # 1 3
|
|
set global binlog_transaction_dependency_tracking=WRITESET;
|
|
INSERT INTO t1 VALUES (null); # 3 4
|
|
INSERT INTO t1 VALUES (null); # 3 5
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
-- echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;1 3;3 4;3 5
|
|
--source include/assert_logical_timestamps.inc
|
|
FLUSH LOGS;
|
|
|
|
--echo
|
|
--echo #### Bug#25616372, PART2 ####
|
|
INSERT INTO t1 VALUES (null); # 0 1
|
|
INSERT INTO t1 VALUES (null); # 0 2
|
|
set global binlog_transaction_dependency_tracking=WRITESET;
|
|
INSERT INTO t1 VALUES (null); # 2 3
|
|
INSERT INTO t1 VALUES (null); # 3 4. # It should be 2 4
|
|
INSERT INTO t1 VALUES (null); # 4 5. # It should be 2 5
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
-- echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;2 3;2 4;2 5
|
|
--source include/assert_logical_timestamps.inc
|
|
DROP TABLE t1;
|
|
FLUSH LOGS;
|
|
|
|
|
|
--echo
|
|
--echo #### Bug#26277771, PART1 ####
|
|
# Bug#26277771 original issue due to missing collation in generating hashes
|
|
CREATE TABLE t1 (c1 int(10) NOT NULL, c2 varchar(20) NOT NULL, PRIMARY KEY (c1),
|
|
UNIQUE KEY (c1, c2)) ENGINE=InnoDB DEFAULT CHARSET=latin1; # 0 1
|
|
INSERT INTO t1 VALUES (1, 'a'); # 1 2
|
|
DELETE FROM t1 WHERE c1=1 AND c2='a'; # 2 3
|
|
INSERT INTO t1 VALUES (1, 'A'); # 3 4
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
-- echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;2 3;3 4
|
|
--source include/assert_logical_timestamps.inc
|
|
DROP TABLE t1;
|
|
FLUSH LOGS;
|
|
|
|
--echo
|
|
--echo #### Bug#26277771, PART2 ####
|
|
# Bug#26277771 issue due to wrong string length calculation
|
|
CREATE TABLE t1 (c1 VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL PRIMARY KEY); # 0 1
|
|
INSERT INTO t1 VALUES ('a'); # 1 2
|
|
INSERT INTO t1 VALUES ('A'); # 1 3
|
|
INSERT INTO t1 VALUES ('b'); # 1 4
|
|
INSERT INTO t1 VALUES ('B'); # 1 5
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
-- echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;1 3;1 4;1 5
|
|
--source include/assert_logical_timestamps.inc
|
|
DROP TABLE t1;
|
|
FLUSH LOGS;
|
|
|
|
--echo
|
|
--echo #### Bug#26277771, PART3 ####
|
|
# test for unset charset, padding and null terminaton
|
|
CREATE TABLE t1 (c1 VARCHAR(20) NOT NULL PRIMARY KEY); # 0 1
|
|
INSERT INTO t1 VALUES ('a'); # 1 2
|
|
INSERT INTO t1 VALUES ('b'); # 1 3
|
|
|
|
CREATE TABLE t2 (c1 BINARY(3) NOT NULL PRIMARY KEY); # 3 4
|
|
INSERT INTO t2 VALUES ('a'); # 4 5
|
|
# copy using strmake will generate same hash for '\0a' and '\0'
|
|
# as it was copying till null termination character and binary
|
|
# doesn't consider null as temination character.
|
|
INSERT INTO t2 VALUES ('\0a'); # 4 6
|
|
INSERT INTO t2 VALUES ('\0'); # 4 7
|
|
INSERT INTO t2 VALUES ('a '); # 4 8
|
|
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
-- echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;1 3;3 4;4 5;4 6;4 7;4 8
|
|
--source include/assert_logical_timestamps.inc
|
|
DROP TABLE t1;
|
|
DROP TABLE t2;
|
|
FLUSH LOGS;
|
|
|
|
--echo
|
|
--echo #### Bug#26277771, PART4 ####
|
|
CREATE TABLE t1 (c1 varchar(20) NOT NULL PRIMARY KEY)
|
|
ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; # 0 1
|
|
INSERT INTO t1 VALUES ('a'); # 1 2
|
|
INSERT INTO t1 VALUES ('á'); # 1 3
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
--echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;1 3
|
|
--source include/assert_logical_timestamps.inc
|
|
DROP TABLE t1;
|
|
FLUSH LOGS;
|
|
|
|
|
|
#
|
|
# Test ROLLBACK TO SAVEPOINT. The rolled-back rows will still have their
|
|
# hashes in the writeset and may cause spurious conflicts.
|
|
#
|
|
--echo
|
|
-- echo #### Test ROLLBACK TO SAVEPOINT ####
|
|
CREATE TABLE t1 (a INT PRIMARY KEY);
|
|
CREATE TABLE nopk (a INT);
|
|
CREATE TABLE parent (a INT PRIMARY KEY);
|
|
CREATE TABLE child (a INT PRIMARY KEY, FOREIGN KEY (a) REFERENCES parent(a));
|
|
|
|
--echo # 1. Hashes of rolled-back rows are removed from writeset
|
|
FLUSH LOGS;
|
|
INSERT INTO t1 VALUES (1);
|
|
BEGIN;
|
|
SAVEPOINT sp;
|
|
UPDATE t1 SET a = 2;
|
|
ROLLBACK TO sp;
|
|
INSERT INTO t1 VALUES (2);
|
|
COMMIT;
|
|
INSERT INTO t1 VALUES (3);
|
|
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
--echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;1 3
|
|
--source include/assert_logical_timestamps.inc
|
|
|
|
--echo # 2. If transaction is flagged as updating a non-index table, the flag is not rolled-back
|
|
FLUSH LOGS;
|
|
INSERT INTO t1 VALUES (4);
|
|
BEGIN;
|
|
SAVEPOINT sp;
|
|
INSERT INTO nopk VALUES (1);
|
|
ROLLBACK TO sp;
|
|
INSERT INTO t1 VALUES (5);
|
|
COMMIT;
|
|
INSERT INTO t1 VALUES (6);
|
|
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
--echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;1 3
|
|
--source include/assert_logical_timestamps.inc
|
|
|
|
--echo # 3. If transaction is flagged as updating a foreign key parent table, the flag is not rolled-back
|
|
FLUSH LOGS;
|
|
INSERT INTO t1 VALUES (7);
|
|
BEGIN;
|
|
SAVEPOINT sp;
|
|
INSERT INTO parent VALUES (1);
|
|
ROLLBACK TO sp;
|
|
INSERT INTO t1 VALUES (8);
|
|
COMMIT;
|
|
INSERT INTO t1 VALUES (9);
|
|
|
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
|
--echo Processing binlog $binlog_file
|
|
--let $source_file= $server_1_datadir/$binlog_file
|
|
--let $logical_timestamps=0 1;1 2;2 3
|
|
--source include/assert_logical_timestamps.inc
|
|
|
|
--echo # Clean up SAVEPOINT tests
|
|
DROP TABLE t1;
|
|
DROP TABLE nopk;
|
|
DROP TABLE child;
|
|
DROP TABLE parent;
|
|
|
|
#
|
|
# Cleanup
|
|
#
|
|
--echo
|
|
--echo #### CLEANUP ####
|
|
|
|
--source include/sync_slave_sql_with_master.inc
|
|
--source include/stop_slave.inc
|
|
|
|
SET @@GLOBAL.slave_parallel_type= @save_slave_parallel_type;
|
|
SET @@GLOBAL.slave_parallel_workers= @save_slave_parallel_workers;
|
|
SET @@GLOBAL.slave_transaction_retries= @save_slave_transaction_retries;
|
|
|
|
--source include/start_slave.inc
|
|
|
|
--connection master
|
|
SET GLOBAL binlog_transaction_dependency_tracking = COMMIT_ORDER;
|
|
SET @@GLOBAL.transaction_write_set_extraction= @save_transaction_write_set_extraction;
|
|
SET @@GLOBAL.binlog_transaction_dependency_tracking= @save_binlog_transaction_dependency_tracking;
|
|
SET @@GLOBAL.binlog_transaction_dependency_history_size= @save_binlog_transaction_dependency_history_size;
|
|
|
|
--source include/rpl_end.inc
|
|
|