Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions mysql-test/suite/galera/r/MDEV-41012-collision.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
connection node_2;
connection node_1;
#
# Each pair below is two distinct values whose bytes fold to the same
# latin1_swedish_ci weight string (0xC0->0x41, 0x6A->0x4A, 0x6B->0x4B,
# 0xD2->0x4F, 0x7A->0x5A). A UUID is stored as a byte permutation of the
# value shown, which does not affect a byte-wise folding.
#
SELECT WEIGHT_STRING(_latin1 0xC0A8016B9E4D4F7AB3D26A1E8F9C0D1B) =
WEIGHT_STRING(_latin1 0x41A8014B9E4D4F5AB34F4A1E8F9C0D1B) AS uuid_pair_collides,
WEIGHT_STRING(_latin1 0x20010DB80000000000000000C0A8016B) =
WEIGHT_STRING(_latin1 0x20010DB8000000000000000041A8014B) AS inet6_pair_collides,
WEIGHT_STRING(_latin1 0xC0A8016B) =
WEIGHT_STRING(_latin1 0x41A8014B) AS inet4_pair_collides;
uuid_pair_collides inet6_pair_collides inet4_pair_collides
1 1 1
#
# UUID
#
connection node_1;
CREATE TABLE t (id UUID PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES ('c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b', 0), ('41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
UPDATE t SET v = 1 WHERE id = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b';
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE t SET v = 2 WHERE id = '41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b';
connection node_2;
no_false_dependency
1
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
second_row_applied_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT id, v FROM t ORDER BY v;
id v
c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b 1
41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b 2
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE t;
#
# INET6
#
connection node_1;
CREATE TABLE t (id INET6 PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES ('2001:db8::c0a8:16b', 0), ('2001:db8::41a8:14b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
UPDATE t SET v = 1 WHERE id = '2001:db8::c0a8:16b';
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE t SET v = 2 WHERE id = '2001:db8::41a8:14b';
connection node_2;
no_false_dependency
1
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
second_row_applied_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT id, v FROM t ORDER BY v;
id v
2001:db8::c0a8:16b 1
2001:db8::41a8:14b 2
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE t;
#
# INET4
#
connection node_1;
CREATE TABLE t (id INET4 PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES ('192.168.1.107', 0), ('65.168.1.75', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
UPDATE t SET v = 1 WHERE id = '192.168.1.107';
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE t SET v = 2 WHERE id = '65.168.1.75';
connection node_2;
no_false_dependency
1
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
second_row_applied_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT id, v FROM t ORDER BY v;
id v
192.168.1.107 1
65.168.1.75 2
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE t;
104 changes: 104 additions & 0 deletions mysql-test/suite/galera/r/MDEV-41012.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
connection node_2;
connection node_1;
#
# UUID
#
connection node_1;
CREATE TABLE p (id UUID PRIMARY KEY, v INT) ENGINE=InnoDB;
CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id UUID NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB;
INSERT INTO p VALUES ('c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
INSERT INTO c (p_id) VALUES ('c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b');
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE p SET v = v + 1 WHERE id = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b';
connection node_2;
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
no_row_modified_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT v FROM p;
v
1
SELECT COUNT(*) FROM c;
COUNT(*)
1
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE c, p;
#
# INET6
#
connection node_1;
CREATE TABLE p (id INET6 PRIMARY KEY, v INT) ENGINE=InnoDB;
CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id INET6 NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB;
INSERT INTO p VALUES ('2001:db8::c0a8:16b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
INSERT INTO c (p_id) VALUES ('2001:db8::c0a8:16b');
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE p SET v = v + 1 WHERE id = '2001:db8::c0a8:16b';
connection node_2;
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
no_row_modified_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT v FROM p;
v
1
SELECT COUNT(*) FROM c;
COUNT(*)
1
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE c, p;
#
# INET4
#
connection node_1;
CREATE TABLE p (id INET4 PRIMARY KEY, v INT) ENGINE=InnoDB;
CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id INET4 NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB;
INSERT INTO p VALUES ('192.168.1.107', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
INSERT INTO c (p_id) VALUES ('192.168.1.107');
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE p SET v = v + 1 WHERE id = '192.168.1.107';
connection node_2;
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
no_row_modified_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT v FROM p;
v
1
SELECT COUNT(*) FROM c;
COUNT(*)
1
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE c, p;
67 changes: 67 additions & 0 deletions mysql-test/suite/galera/t/MDEV-41012-collision.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#
# Body of galera.MDEV-41012-collision, parameterized by the data type.
#
# $fbt_type - data type of the primary key column
# $fbt_value1 - a literal of that type
# $fbt_value2 - a *different* literal whose binary representation folds to
# the same latin1_swedish_ci weight string as $fbt_value1
#

--connection node_1
--eval CREATE TABLE t (id $fbt_type PRIMARY KEY, v INT) ENGINE=InnoDB
--eval INSERT INTO t VALUES ($fbt_value1, 0), ($fbt_value2, 0)

--connection node_2
SET SESSION wsrep_sync_wait = 0;
--let $wait_condition = SELECT COUNT(*) = 2 FROM t
--source include/wait_condition.inc

SET GLOBAL wsrep_slave_threads = 2;

# Park the applier of the first UPDATE on entry to the apply monitor.
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc

--connection node_1
--eval UPDATE t SET v = 1 WHERE id = $fbt_value1

--connection node_2
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc

# Disarm, so the second applier runs into the real dependency check.
--source include/galera_clear_sync_point.inc

--let $apply_waits = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits'`

--connection node_1
--eval UPDATE t SET v = 2 WHERE id = $fbt_value2

--connection node_2
# The two statements modify two *different* rows, so their
# certification keys must differ, there must be no dependency between the two
# writesets, and the second applier must be free to apply its row while the
# first one is still parked.
--let $wait_condition = SELECT (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits') > $apply_waits OR EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0)
--source include/wait_condition.inc

# While the key was collated with latin1_swedish_ci the two keys were equal,
# the second writeset was made to depend on the first, and both of these
# reported 0.
--disable_query_log
--eval SELECT VARIABLE_VALUE = $apply_waits AS no_false_dependency FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits'
--enable_query_log
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;

--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_signal_sync_point.inc

--let $wait_condition = SELECT SUM(v) = 3 FROM t
--source include/wait_condition.inc
SELECT id, v FROM t ORDER BY v;

SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;

--connection node_1
DROP TABLE t;
64 changes: 64 additions & 0 deletions mysql-test/suite/galera/t/MDEV-41012-collision.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#
# MDEV-41012: certification key collision between distinct values of a fixed
# binary data type (UUID, INET6, INET4).
#
# Testing key collisions with data types on Field_fbt: UUID, INET6 and INET4,
# where different keys could potentially generate same certification keys.
# i.e. a scenario where two transactions modifying two *different*
# rows certified as a conflict and the later one was aborted with a spurious
# ER_LOCK_DEADLOCK.
#
# A shared key also gives the two writesets a false dependency on each other,
# which serializes applying that should have run in parallel. The test detects
# the collision that way, because it can be driven deterministically. Whether
# the spurious ER_LOCK_DEADLOCK is observed instead depends on whether the
# first writeset has already been applied by the time the second transaction
# replicates, which is a race.
#
# This needs no foreign key: it is the row key path,
# wsrep_store_key_val_for_row(), alone.
#
# This is the second half of MDEV-41012. The other half, a key *mismatch* for
# one and the same row, is covered by galera.MDEV-41012.
#

--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/galera_have_debug_sync.inc

--echo #
--echo # Each pair below is two distinct values whose bytes fold to the same
--echo # latin1_swedish_ci weight string (0xC0->0x41, 0x6A->0x4A, 0x6B->0x4B,
--echo # 0xD2->0x4F, 0x7A->0x5A). A UUID is stored as a byte permutation of the
--echo # value shown, which does not affect a byte-wise folding.
--echo #
SELECT WEIGHT_STRING(_latin1 0xC0A8016B9E4D4F7AB3D26A1E8F9C0D1B) =
WEIGHT_STRING(_latin1 0x41A8014B9E4D4F5AB34F4A1E8F9C0D1B) AS uuid_pair_collides,
WEIGHT_STRING(_latin1 0x20010DB80000000000000000C0A8016B) =
WEIGHT_STRING(_latin1 0x20010DB8000000000000000041A8014B) AS inet6_pair_collides,
WEIGHT_STRING(_latin1 0xC0A8016B) =
WEIGHT_STRING(_latin1 0x41A8014B) AS inet4_pair_collides;

--echo #
--echo # UUID
--echo #
--let $fbt_type = UUID
--let $fbt_value1 = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b'
--let $fbt_value2 = '41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b'
--source MDEV-41012-collision.inc

--echo #
--echo # INET6
--echo #
--let $fbt_type = INET6
--let $fbt_value1 = '2001:db8::c0a8:16b'
--let $fbt_value2 = '2001:db8::41a8:14b'
--source MDEV-41012-collision.inc

--echo #
--echo # INET4
--echo #
--let $fbt_type = INET4
--let $fbt_value1 = '192.168.1.107'
--let $fbt_value2 = '65.168.1.75'
--source MDEV-41012-collision.inc
Loading