#
# This test is a modified version of Gabor Orosz (GOro) test in jira tracker:
# https://jira.mariadb.org/browse/MDEV-25551
#
# The underlying problem with MDEV-25551 turned out to be that
# transactions having changes for tables with no primary key, 
# were not safe to apply in parallel. This is due to excessive locking
# in innodb side, and even non related row modifications could end up
# in lock conflict during applying.
#
# The test creates a table with no primary key definition and executes two
# transactions (in node1) modifying separate rows in the table. In node2
# first applier is paused before commit phase, and second transaction is
# then submitted to see if it can interfere with the first transaciton.
# The fix for MDEV-25551 has disabled parallel applying for tables with no PK,
# and in the test applying of the send trasnaction should not even start, before
# the fisrt trkansaction is released from the sync point.
# The test also verifies that certification depedency status reflects the fact
# that the two transactions depend on each other.
#
# The test has two scenarios where both UPDATE and DELETE statements are verified
# to disable parallel applying
#

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

# Setup

CREATE TABLE t1 (f1 VARCHAR(32) NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES ('0e66c5227a8a');
INSERT INTO t1 (f1) VALUES ('c6c112992c9');

CREATE TABLE t2 (i int primary key);

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

# Ensure that we have enough applier threads to process transactions in parallel
SET GLOBAL wsrep_slave_threads = 2;

--echo ***************************************************************
--echo scenario 1, conflicting UPDATE
--echo ***************************************************************

# Set up a synchronization point to catch the first transaction
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc

--connection node_1
# Invoke the first transaction
START TRANSACTION;
UPDATE t1 SET f1='5ffceebfada' WHERE t1.f1 = 'c6c112992c9';
COMMIT;

--connection node_2
# Wait for the first transaction to apply until commit phase
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc

# remember status for received replication counter and certification dependency distance
--let $expected_wsrep_received = `SELECT VARIABLE_VALUE+1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_received'`
--let $cert_deps_distance = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cert_deps_distance'`

--connection node_1
# Invoke the second transaction
START TRANSACTION;
UPDATE t1 SET f1='4ffceebfcdc' WHERE t1.f1 = '0e66c5227a8a';
COMMIT;

# sleep is probably obsolete here, but it is good to give the latter update time to
# proceed in applying in node 2. In buggy version the update will start applying
# and cause conflict there.
--sleep 5

--connection node_2
# Wait for the second transaction to appear in repliaction queue
--let $wait_condition = SELECT VARIABLE_VALUE= $expected_wsrep_received FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_received';
--source include/wait_condition.inc

# verify that certification dependency distance has dropped
--disable_query_log
--eval  SELECT  VARIABLE_VALUE < $cert_deps_distance as 'distance' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cert_deps_distance'
--enable_query_log

# if deps distance dropped, it is indirect evidence that parallel applying was not approved

# Let the first transaction to proceed
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_signal_sync_point.inc

# second applier should now hit sync point
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc
--source include/galera_signal_sync_point.inc
--source include/galera_clear_sync_point.inc

--echo ***************************************************************
--echo scenario 2, conflicting DELETE
--echo ***************************************************************

# Set up a synchronization point to catch the first transaction
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc

--connection node_1
# Invoke the first transaction, mix this with insert to table having PK
START TRANSACTION;
INSERT INTO t2 VALUES (1);
DELETE FROM t1 WHERE f1='5ffceebfada';
COMMIT;

--connection node_2
# Wait for the first transaction to apply until commit phase
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc

# remember status for received replication counter and certification dependency distance
--let $expected_wsrep_received = `SELECT VARIABLE_VALUE+1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_received'`
--let $cert_deps_distance = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cert_deps_distance'`

--connection node_1
# Invoke the second transaction, again mix this with insert to table having PK
START TRANSACTION;
INSERT INTO t2 VALUES (2);
DELETE FROM t1 WHERE f1='4ffceebfcdc';
COMMIT;

# sleep is probably obsolete here, but it is good to give the latter update time to
# proceed in applying in node 2. In buggy version the update will start applying
# and cause conflict there.
--sleep 5

--connection node_2
# Wait for the second transaction to appear in repliaction queue
--let $wait_condition = SELECT VARIABLE_VALUE= $expected_wsrep_received FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_received';
--source include/wait_condition.inc

# verify that certification dependency distance has dropped
--disable_query_log
--eval  SELECT  VARIABLE_VALUE < $cert_deps_distance as 'distance' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cert_deps_distance'
--enable_query_log

# if deps distance dropped, it is indirect evidence that parallel applying was not approved

# Let the first transaction to proceed
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_signal_sync_point.inc

# second applier should now hit sync point
--let $galera_sync_point = commit_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc
--source include/galera_signal_sync_point.inc
--source include/galera_clear_sync_point.inc

# Teardown
--connection node_1
SET GLOBAL wsrep_slave_threads = DEFAULT;

DROP TABLE t1;
DROP TABLE t2;

--connection node_2
SET GLOBAL wsrep_slave_threads = DEFAULT;
