diff --git a/mysql-test/include/wait_show_condition.inc b/mysql-test/include/wait_show_condition.inc index b8dd9bdf97156..f3d995739fb74 100644 --- a/mysql-test/include/wait_show_condition.inc +++ b/mysql-test/include/wait_show_condition.inc @@ -9,7 +9,7 @@ # # USAGE # -# All rows of the result must fulfil the condition if $all_rows_fulfil is 1 +# All rows of the result must fulfil the condition if $wait_for_all is 1 # else at least one of the result must fulfil the condition. # let $wait_for_all= 1; # let $show_statement= SHOW PROCESSLIST; @@ -25,7 +25,7 @@ # let $condition= = 'Updating'; # --source include/wait_show_condition.inc # -# Please do not use this use routine if you can replace the SHOW statement +# Please do not use this routine if you can replace the SHOW statement # with a select. In such a case include/wait_condition.inc is recommended. # # Created: 2009-02-18 mleich diff --git a/mysql-test/main/grant_master_admin.result b/mysql-test/main/grant_master_admin.result index bd08ade940c9c..97a7b4d002408 100644 --- a/mysql-test/main/grant_master_admin.result +++ b/mysql-test/main/grant_master_admin.result @@ -28,7 +28,7 @@ GRANT REPLICATION MASTER ADMIN ON *.* TO `user1`@`localhost` connect con1,localhost,user1,,; connection con1; SHOW SLAVE HOSTS; -Server_id Host Port Master_id +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status connection default; DROP USER user1@localhost; # diff --git a/mysql-test/suite/rpl/r/rpl_fail_register.result b/mysql-test/suite/rpl/r/rpl_fail_register.result index 0398220c4d07a..7af07b335b35e 100644 --- a/mysql-test/suite/rpl/r/rpl_fail_register.result +++ b/mysql-test/suite/rpl/r/rpl_fail_register.result @@ -14,7 +14,7 @@ set global debug_dbug=@old_dbug; connection master; kill DUMP_THREAD; show slave hosts; -Server_id Host Port Master_id +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status connection slave; start slave; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_mixed_ddl_dml.result b/mysql-test/suite/rpl/r/rpl_mixed_ddl_dml.result index 0cee79434ee50..3459641114485 100644 --- a/mysql-test/suite/rpl/r/rpl_mixed_ddl_dml.result +++ b/mysql-test/suite/rpl/r/rpl_mixed_ddl_dml.result @@ -11,8 +11,8 @@ n 2002 connection master; show slave hosts; -Server_id Host Port Master_id -2 127.0.0.1 9999 1 +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 127.0.0.1 9999 1 asynchronous drop table t1; connection slave; stop slave; diff --git a/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result b/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result index 79803cca0d0ea..43ae5558611b8 100644 --- a/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result +++ b/mysql-test/suite/rpl/r/rpl_show_slave_hosts.result @@ -8,13 +8,583 @@ START SLAVE IO_THREAD; include/wait_for_slave_io_to_start.inc connection master; SHOW SLAVE HOSTS; -Server_id Host Port Master_id -3 slave2 SLAVE_PORT 1 -2 localhost SLAVE_PORT 1 +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 asynchronous +2 localhost SLAVE_PORT 1 asynchronous connection slave2; include/stop_slave_io.inc connection master; SHOW SLAVE HOSTS; -Server_id Host Port Master_id -2 localhost SLAVE_PORT 1 +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 asynchronous +# +# MDEV-21322: report slave progress to the primary +# +call mtr.add_suppression('Slave I/O: Relay log write failure: could not queue event from master.*'); +call mtr.add_suppression('Slave I/O: Replication event checksum verification failed while reading from network.*'); +call mtr.add_suppression('Replication event checksum verification failed'); +call mtr.add_suppression("Timeout waiting for reply of binlog*"); +call mtr.add_suppression('Found invalid event in binary log'); +call mtr.add_suppression('event read from binlog did not pass crc check'); +call mtr.add_suppression('Event crc check failed! Most likely there is event corruption'); +call mtr.add_suppression('Slave SQL: Error initializing relay log position: I/O error reading event at position .*, error.* 1593'); +call mtr.add_suppression("Semi-sync slave .* reply"); +select @@global.rpl_semi_sync_master_wait_point; +@@global.rpl_semi_sync_master_wait_point +AFTER_COMMIT +reset master; +# Test 1: Primary has not enabled semisync +# Note: even if not enabled semisync we are expecting to see following +# columns: +# `Server_id`,`Host Port`,`Master_id`,`Gtid_State_Sent`,`Gtid_State_Ack`,`Sync`, +# where replica with `server_id=2` is already connected +# ----------------------------------------------------------------------- +SHOW SLAVE HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 asynchronous +# Test 2: Primary enabled semisync +# Note: it should be the same as test 1 +# ----------------------------------------------------------------------- +set global rpl_semi_sync_master_enabled = 1; +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +SHOW SLAVE HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 asynchronous +# Test 3: Replica (server_id=2) enabled semisync +# Note: No new GTIDs, so expected empty `Gtid_State_Sent`,`Gtid_State_Ack` +# ----------------------------------------------------------------------- +connection slave; +include/stop_slave.inc +include/reset_slave.inc +set global rpl_semi_sync_slave_enabled = 1; +include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +connection master; +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 semi-sync stale +# Test 4: Make new events - generate new GTID +# Note 1: Create 2 events on primary. Replica is already connected +# Note 2: `Gtid_State_Sent` and `Gtid_State_Ack` should have event group +# ----------------------------------------------------------------------- +create table t(t int); +insert into t values (1); +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 2 +include/save_master_gtid.inc +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 0-1-2 0-1-2 semi-sync active +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 2 +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +Rpl_semi_sync_master_request_ack 2 +show status like 'Rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 2 +connection slave; +include/diff_tables.inc [master:test.t,slave:test.t] +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 2 +# Test 5: Enable semi-sync for slave2 +# Note 1: Replica (`server_id=3`) should be started and semi-sync enabled +# Note 2: In semi-sync replication ACK thread (on primary), +# waits only on single replica to respond about received events. +# Note 3: Since `Gtid_State_Ack` is received for 2 events +# from `server_id=2` in previous test and there is no new event +# in this test, primary is resending old transactions, +# we are expecting empty `Gtid_State_Ack` for `server_id=3` +# in show statement (see Note 2). +# ----------------------------------------------------------------------- +connection slave2; +set global rpl_semi_sync_slave_enabled = 1; +include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +connection master; +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 2 +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-2 semi-sync stale +2 localhost SLAVE_PORT 1 0-1-2 0-1-2 semi-sync active +connection slave2; +include/diff_tables.inc [master:test.t,slave:test.t,slave2:test.t] +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +connection slave; +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 2 +# Test 6: Create new transactions on primary +# Note: New transactions on primary are sent to replicas +# and connected replicas (`server_id=2` and `server_id=3`) +# should sync to the GTID state on primary. +# ----------------------------------------------------------------------- +connection master; +show status like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +Rpl_semi_sync_master_request_ack 2 +show status like 'Rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 2 +SET @@GLOBAL.DEBUG_DBUG="d,pause_ack_thread_on_next_ack"; +SELECT @@GLOBAL.DEBUG_DBUG; +@@GLOBAL.DEBUG_DBUG +d,pause_ack_thread_on_next_ack +create table t2(t2 int); +SET debug_sync='now WAIT_FOR pause_ack_reply_to_binlog'; +"Waited on master_request_ack" +include/save_master_gtid.inc +"Waited on Gtid_State_Sent be sent to all replicas +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-3 semi-sync active +2 localhost SLAVE_PORT 1 0-1-3 0-1-2 semi-sync active +# The test disables master +# Wait on master to be started. +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +# Check statuses on slave - should not be OFF +connection slave; +show variables like 'rpl_semi_sync_slave_status'; +Variable_name Value +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +connection slave2; +show variables like 'rpl_semi_sync_slave_status'; +Variable_name Value +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +connection master; +# Check that number of active transactions shouldn't be incremented yet +# Check that number of active transaction is not yet incremented +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 2 +# Check condition (get ack) before getting the ACK increment +show status like 'Rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 2 +SET debug_sync='now SIGNAL unpause_ack_reply_to_binlog'; +# ---- Send ACK ---- +# Wait on master's get_ACK incremented +# Get ack incremented after dbug point (it may be 3 or 4 so we used >=) +show status like 'Rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 4 +# Reset debug sync on primary +SET @@GLOBAL.debug_dbug= ""; +SET debug_sync='RESET'; +SELECT @@GLOBAL.debug_dbug; +@@GLOBAL.debug_dbug + +include/save_master_gtid.inc +# Waited on Gtid_State_Ack be obtained to single replica +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-3 0-1-3 semi-sync active +2 localhost SLAVE_PORT 1 0-1-3 0-1-3 semi-sync active +show status like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +Rpl_semi_sync_master_request_ack 3 +show status like 'Rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 4 +show status like "Slaves_connected"; +Variable_name Value +Slaves_connected 2 +connection slave; +# Check send ACKs on replica server_id=2 +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 3 +# Test 7: Simulate stop of the IO thread of replica +# Note 1: Stopping the IO thread will unregister replica from master info +# so for `server_id=2`, `rpl_semi_sync_slave_status` will be `OFF` +# and so should not be visible in show statement output. +# Note 2: New event will be created and successfully sent and acked by `server_id=3` +# Note 3: Starting the IO thread again for `server_id=2` will enable `rpl_semi_sync_slave_status`, +# but since there is no new transaction and `ack` counter is reseted, +# `Gtid_State_Sent` and `Gtid_State_Ack` will be empty. +# Note 4: When synching replica with primary, primary will resent the old +# transaction, so `Gtid_State_Sent` will be the same event group +# as `server_id=3`(replica that ACKed the transaction), but since +# there is no new transaction on primary `Gtid_State_Ack` will +# remain empty. +# ----------------------------------------------------------------------- +connection master; +# Check request_ack before stopping the slave +show variables like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +connection slave; +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +show variables like 'rpl_semi_sync_slave_status'; +Variable_name Value +STOP SLAVE IO_THREAD; +include/wait_for_slave_io_to_stop.inc +# Semi-sync disabled on server_id=2 +show variables like 'rpl_semi_sync_slave_status'; +Variable_name Value +# slave_send_ack should be reseted when replica IO thread starts. +# Here we are checking it holds the same value as before stopping the IO thread. +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 3 +connection master; +show status like "Slaves_connected"; +Variable_name Value +Slaves_connected 1 +# Check request_ack after stopping the slave +show variables like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +# Initial show statement, without server_id=2 +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-3 0-1-3 semi-sync active +connection master; +# Check master status before new event test 7 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +INSERT INTO t VALUES (10); +# Wait on transaction/request/ack and show them +show status like 'Rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 5 +show variables like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +# Transaction is not incremented and it should (TODO after MDEV-33615) +show variables like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +show variables like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-4 0-1-4 semi-sync active +connection slave; +START SLAVE IO_THREAD; +include/wait_for_slave_io_to_start.inc +show variables like 'rpl_semi_sync_slave_status'; +Variable_name Value +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +connection master; +show status like "Slaves_connected"; +Variable_name Value +Slaves_connected 2 +include/save_master_gtid.inc +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 2 +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 0-1-4 semi-sync stale +3 slave2 SLAVE_PORT 1 0-1-4 0-1-4 semi-sync active +"Sync replica with master" +connection slave; +connection master; +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 2 +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +2 localhost SLAVE_PORT 1 0-1-4 semi-sync stale +3 slave2 SLAVE_PORT 1 0-1-4 0-1-4 semi-sync active +show status like "Rpl_semi_sync_master_get_ack"; +Variable_name Value +Rpl_semi_sync_master_get_ack 5 +show status like "Rpl_semi_sync_master_request_ack"; +Variable_name Value +Rpl_semi_sync_master_request_ack 4 +# Test 8: Replica `server_id=2` failure with `corrupt_queue_event` +# Note 1: Simulate replicas failure by making replica busy. +# Consequence is that replica will be unregistered and that is why +# we need to wait that replica unregisters (`Slaves_connected`). +# By creating new event, only active replicas should respond +# (`server_id=3`) with ACK +# Note 2: In order not to show old result from `server_id=2`,from busy replica +# we have to *wait* that binlog_dump_thread_count shows status +# `Slaves_connected` decreased and after that check show statement. +# ----------------------------------------------------------------------- +connection slave; +SET @@GLOBAL.debug_dbug= "+d,corrupt_queue_event"; +connection master; +INSERT INTO t VALUES (3); +show status like "Rpl_semi_sync_master_get_ack"; +Variable_name Value +Rpl_semi_sync_master_get_ack 6 +show status like "Rpl_semi_sync_master_request_ack"; +Variable_name Value +Rpl_semi_sync_master_request_ack 5 +show status like "Slaves_connected"; +Variable_name Value +Slaves_connected 1 +include/save_master_gtid.inc +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-5 0-1-5 semi-sync active +connection slave; +SET @@GLOBAL.debug_dbug= ""; +connection master; +show status like "Slaves_connected"; +Variable_name Value +Slaves_connected 1 +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +connection master; +include/save_master_gtid.inc +# Test 9: Stop `server_id=3` +# Note: Check that no replicas get new generated event, so show statement +# is expected to be empty. +# ----------------------------------------------------------------------- +connection slave2; +include/stop_slave.inc +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 3 +include/reset_slave.inc +show status like "Rpl_semi_sync_slave_send_ack"; +Variable_name Value +Rpl_semi_sync_slave_send_ack 3 +connection master; +select @@global.rpl_semi_sync_master_timeout; +@@global.rpl_semi_sync_master_timeout +10000 +set @@global.rpl_semi_sync_master_timeout= 2000; +select @@global.rpl_semi_sync_master_timeout; +@@global.rpl_semi_sync_master_timeout +2000 +show status like "Slaves_connected"; +Variable_name Value +Slaves_connected 0 +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 1 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 4 +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 0 +show status like 'rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 6 +show status like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +Rpl_semi_sync_master_request_ack 5 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +INSERT INTO t VALUES (5); +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 2 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 4 +show status like 'Rpl_semi_sync_master_request_ack'; +Variable_name Value +Rpl_semi_sync_master_request_ack 6 +show status like 'rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 6 +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +# Start slaves again +connection slave; +include/start_slave.inc +show status like 'rpl_semi_sync_slave%'; +Variable_name Value +Rpl_semi_sync_slave_send_ack 1 +Rpl_semi_sync_slave_status ON +connection slave2; +include/start_slave.inc +show status like 'rpl_semi_sync_slave%'; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +Rpl_semi_sync_slave_status ON +# sync with master, should ENABLE master_status +connection master; +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 4 +# Test 10: Testing `rpl_semi_sync_master_timeout=0` +# Note 1: For asynchronous replication `Gtid_state_sent` is not null, +# but `Gtid_state_ack` is null. +# Note 2: We want that `rpl_semi_sync_master_timeout=0` be edge case, +# by mimicking asynchronous replication, as semi-sync stalled +# replication type, for which `Gtid_state_ack` should reflect +# the latest received transaction by the replica[s]. +# Also `rpl_semi_sync_master_status` has +# to remain `ON`, instead switching off, so instead of +# no waiting on ACK, primary must wait on ACK from replica. +# Note 3: With this option we want `Gtid_state_ack` to reflect +# the latest received transaction by the replica[s]. +# ----------------------------------------------------------------------- +# Initial number of ACK get/requests +show status like 'rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 7 +show status like 'rpl_semi_sync_master_request_ack'; +Variable_name Value +Rpl_semi_sync_master_request_ack 6 +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +show status like 'rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +set global rpl_semi_sync_master_timeout=0; +select @@global.rpl_semi_sync_master_timeout; +@@global.rpl_semi_sync_master_timeout +0 +show variables like 'rpl_semi_sync_master_timeout'; +Variable_name Value +rpl_semi_sync_master_timeout 0 +connection slave; +include/stop_slave.inc +SET @@GLOBAL.DEBUG_DBUG="d,synchronize_semisync_slave_reply"; +include/start_slave.inc +show status like 'rpl_semi_sync_slave%'; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +Rpl_semi_sync_slave_status ON +connection slave2; +include/stop_slave.inc +SET @@GLOBAL.DEBUG_DBUG="d,synchronize_semisync_slave_reply"; +include/start_slave.inc +show status like 'rpl_semi_sync_slave%'; +Variable_name Value +Rpl_semi_sync_slave_send_ack 0 +Rpl_semi_sync_slave_status ON +connection master; +INSERT INTO t values (1111); +# Both replicas are stopped with synchronization point after master's new event +connection slave; +SET debug_sync='now WAIT_FOR at_slave_reply'; +connection slave2; +SET debug_sync='now WAIT_FOR at_slave_reply'; +connection master; +show status like 'rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 7 +# `Gtid_State_Sent` event sent from primary +include/save_master_gtid.inc +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-7 semi-sync active +2 localhost SLAVE_PORT 1 0-1-7 semi-sync active +connection slave; +SET debug_sync='now SIGNAL reply_ack_to_master'; +# Replica server_2 has sent ACK +connection master; +include/save_master_gtid.inc +show status like 'rpl_semi_sync_master_get_ack'; +Variable_name Value +Rpl_semi_sync_master_get_ack 8 +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-7 semi-sync active +2 localhost SLAVE_PORT 1 0-1-7 0-1-7 semi-sync active +connection slave2; +SET debug_sync='now SIGNAL reply_ack_to_master'; +# Replica server_3 has sent ACK +connection master; +include/save_master_gtid.inc +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-7 0-1-7 semi-sync active +2 localhost SLAVE_PORT 1 0-1-7 0-1-7 semi-sync active +connection slave2; +# Sync server_3 with master should return the same result as before +connection master; +include/save_master_gtid.inc +SHOW REPLICA HOSTS; +Server_id Host Port Master_id Gtid_State_Sent Gtid_State_Ack Sync_Status +3 slave2 SLAVE_PORT 1 0-1-7 0-1-7 semi-sync active +2 localhost SLAVE_PORT 1 0-1-7 0-1-7 semi-sync active +# cleanup +# ------------------------------------------- +connection master; +SET @@GLOBAL.rpl_semi_sync_master_timeout= 10000; +SET GLOBAL rpl_semi_sync_master_enabled = 0; +drop table t; +drop table t2; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/stop_slave.inc +SET @@GLOBAL.debug_dbug= ""; +SET debug_sync='RESET'; +set global rpl_semi_sync_slave_enabled = 0; +include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled OFF +connection slave2; +include/sync_with_master_gtid.inc +include/stop_slave.inc +set global rpl_semi_sync_slave_enabled = 0; +SET @@GLOBAL.debug_dbug= ""; +SET debug_sync='RESET'; +include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled OFF +include/stop_slave.inc include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test index 84c5c215a08b0..750102bf2c2d7 100644 --- a/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test +++ b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test @@ -49,4 +49,786 @@ source include/wait_show_condition.inc; --replace_result $SLAVE_MYPORT SLAVE_PORT SHOW SLAVE HOSTS; + +--echo # +--echo # MDEV-21322: report slave progress to the primary +--echo # + +call mtr.add_suppression('Slave I/O: Relay log write failure: could not queue event from master.*'); +call mtr.add_suppression('Slave I/O: Replication event checksum verification failed while reading from network.*'); +call mtr.add_suppression('Replication event checksum verification failed'); +call mtr.add_suppression("Timeout waiting for reply of binlog*"); +call mtr.add_suppression('Found invalid event in binary log'); +call mtr.add_suppression('event read from binlog did not pass crc check'); +call mtr.add_suppression('Event crc check failed! Most likely there is event corruption'); +call mtr.add_suppression('Slave SQL: Error initializing relay log position: I/O error reading event at position .*, error.* 1593'); +call mtr.add_suppression("Semi-sync slave .* reply"); + +select @@global.rpl_semi_sync_master_wait_point; +reset master; + +--echo # Test 1: Primary has not enabled semisync +--echo # Note: even if not enabled semisync we are expecting to see following +--echo # columns: +--echo # `Server_id`,`Host Port`,`Master_id`,`Gtid_State_Sent`,`Gtid_State_Ack`,`Sync`, +--echo # where replica with `server_id=2` is already connected +--echo # ----------------------------------------------------------------------- +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW SLAVE HOSTS; + +--echo # Test 2: Primary enabled semisync +--echo # Note: it should be the same as test 1 +--echo # ----------------------------------------------------------------------- +set global rpl_semi_sync_master_enabled = 1; +show variables like 'rpl_semi_sync_master_enabled'; +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW SLAVE HOSTS; + + +--echo # Test 3: Replica (server_id=2) enabled semisync +--echo # Note: No new GTIDs, so expected empty `Gtid_State_Sent`,`Gtid_State_Ack` +--echo # ----------------------------------------------------------------------- +connection slave; +--source include/stop_slave.inc +--source include/reset_slave.inc +set global rpl_semi_sync_slave_enabled = 1; +--source include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +# Check on replica number of ACKs +show status like "Rpl_semi_sync_slave_send_ack"; + +connection master; +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + + +--echo # Test 4: Make new events - generate new GTID +--echo # Note 1: Create 2 events on primary. Replica is already connected +--echo # Note 2: `Gtid_State_Sent` and `Gtid_State_Ack` should have event group +--echo # ----------------------------------------------------------------------- +# Write 2 new events +create table t(t int); +insert into t values (1); + +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_no_tx'; +# There are 2 events +show status like 'Rpl_semi_sync_master_yes_tx'; +# Here we should get `Gtid_State_Sent` and `Gtid_State_Ack` +--source include/save_master_gtid.inc # Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Sent; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 1; +source include/wait_show_condition.inc; +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_request_ack'; +show status like 'Rpl_semi_sync_master_get_ack'; + +connection slave; +# Check the table on slave +--let $diff_tables=master:test.t,slave:test.t +--source include/diff_tables.inc + +# Check on replica number of ACKs +show status like "Rpl_semi_sync_slave_send_ack"; + +--echo # Test 5: Enable semi-sync for slave2 +--echo # Note 1: Replica (`server_id=3`) should be started and semi-sync enabled +--echo # Note 2: In semi-sync replication ACK thread (on primary), +--echo # waits only on single replica to respond about received events. +--echo # Note 3: Since `Gtid_State_Ack` is received for 2 events +--echo # from `server_id=2` in previous test and there is no new event +--echo # in this test, primary is resending old transactions, +--echo # we are expecting empty `Gtid_State_Ack` for `server_id=3` +--echo # in show statement (see Note 2). +--echo # ----------------------------------------------------------------------- +# Replica is already stopped +connection slave2; +set global rpl_semi_sync_slave_enabled = 1; +--source include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +show status like "Rpl_semi_sync_slave_send_ack"; + +connection master; +# - Check number of semi-sync replicas - 2 should be connected +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 2; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_clients'; +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +connection slave2; +# Check the table on slave2 +--let $diff_tables=master:test.t,slave:test.t,slave2:test.t +--source include/diff_tables.inc + +# Check on replica 2 number of ACKs (should be 0, since replica 1 already sent) +show status like "Rpl_semi_sync_slave_send_ack"; + +connection slave; +let $slave1_sent_ack= query_get_value(show status like 'Rpl_semi_sync_slave_send_ack', Value, 1); +# Check on replica 1 number of ACKs +show status like "Rpl_semi_sync_slave_send_ack"; + +--echo # Test 6: Create new transactions on primary +--echo # Note: New transactions on primary are sent to replicas +--echo # and connected replicas (`server_id=2` and `server_id=3`) +--echo # should sync to the GTID state on primary. +--echo # ----------------------------------------------------------------------- +connection master; +# Check old counters for _get_ack and _request_ack on primary +show status like 'Rpl_semi_sync_master_request_ack'; +show status like 'Rpl_semi_sync_master_get_ack'; +let $master_get_ack_num= query_get_value(show status like 'Rpl_semi_sync_master_get_ack', Value, 1); +let $master_request_ack_num= query_get_value(show status like 'Rpl_semi_sync_master_request_ack', Value, 1); + +# In this test there are 2 active replicas and 1 transactions. +# Using DBUG_SYNC(pause_ack_thread_on_next_ack) +# test will ensure that we should wait on single ACK from active replica. +--let $save_primary_dbug= `SELECT @@GLOBAL.DEBUG_DBUG` +SET @@GLOBAL.DEBUG_DBUG="d,pause_ack_thread_on_next_ack"; +SELECT @@GLOBAL.DEBUG_DBUG; + +# Write the new event +create table t2(t2 int); +# It may happen that rpl_semi_sync_master_no_transactions increments for above +# query. + +SET debug_sync='now WAIT_FOR pause_ack_reply_to_binlog'; + +# In this point master_request_ack should be incremented +# Check number of received transactions and requested ACKs +let $status_var= Rpl_semi_sync_master_request_ack; +let $status_var_value= `SELECT $master_request_ack_num + 1`; +source include/wait_for_status_var.inc; +--echo "Waited on master_request_ack" + +# In this test we did not check for `Rpl_semi_sync_master_get_ack`, since it gets +# incremented for each event that is sent to the replica, that needs an ack. +# Primary sends event to one replica and gets ACK, before the replica even tries +# sending the event to the other replica, after which other replica sends ACK +# for the same event, so increment for `$master_get_ack_num` below would be 4. +# However this can fail on bb, where increment can be 4 or 3. +# It was tried to add `Rpl_semi_sync_master_net_waits` but increment was 3, +# so could not create stable test. +# Instead use latest value obtained for the status `Rpl_semi_sync_master_get_ack`. + +# Result show statement +--source include/save_master_gtid.inc #Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Sent; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 1; +source include/wait_show_condition.inc; +--echo "Waited on Gtid_State_Sent be sent to all replicas +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +--echo # The test disables master +--echo # Wait on master to be started. +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_status'; +show variables like 'rpl_semi_sync_master_enabled'; + +--echo # Check statuses on slave - should not be OFF +connection slave; +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show variables like 'rpl_semi_sync_slave_status'; +show variables like 'rpl_semi_sync_slave_enabled'; + +connection slave2; +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show variables like 'rpl_semi_sync_slave_status'; +show variables like 'rpl_semi_sync_slave_enabled'; + +connection master; + +--echo # Check that number of active transactions shouldn't be incremented yet +let $status_var= Rpl_semi_sync_master_yes_tx; +let $status_var_comparsion= >=; +let $status_var_value= `SELECT $master_request_ack_num`; +source include/wait_for_status_var.inc; +--echo # Check that number of active transaction is not yet incremented +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # Check condition (get ack) before getting the ACK increment +show status like 'Rpl_semi_sync_master_get_ack'; + +SET debug_sync='now SIGNAL unpause_ack_reply_to_binlog'; + +--echo # ---- Send ACK ---- +--echo # Wait on master's get_ACK incremented +--echo # Get ack incremented after dbug point (it may be 3 or 4 so we used >=) +let $status_var= Rpl_semi_sync_master_get_ack; +let $status_var_comparsion= >=; +let $status_var_value= `SELECT $master_get_ack_num + 1`; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_get_ack'; + +--echo # Reset debug sync on primary +--eval SET @@GLOBAL.debug_dbug= "$save_primary_dbug" +SET debug_sync='RESET'; +SELECT @@GLOBAL.debug_dbug; + +# Here we know that there will be both active replicas, +# where at least one has sent ACK and master got the ack. +# If the transaction is not committed on primary we may get new master_get_ack_num +# from other replica +# Result show statement +--source include/save_master_gtid.inc #Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Ack; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 0; +# we have to reset comparision +let $status_var_comparsion= =; +source include/wait_show_condition.inc; +--echo # Waited on Gtid_State_Ack be obtained to single replica + +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +show status like 'Rpl_semi_sync_master_request_ack'; +show status like 'Rpl_semi_sync_master_get_ack'; +# Determine binlog_dump_thread_count, number of connected semi-sync replica +show status like "Slaves_connected"; + +# Update ACK get/request number +let $master_request_ack_num= `SELECT $master_request_ack_num + 1`; +# Here we may have get increment by 4 or by 3 for `rpl_semi_sync_master_get_ack`, +# so instead of manual increment, get the returned value of status. +let $master_get_ack_num= query_get_value(show status like 'Rpl_semi_sync_master_get_ack', Value, 1); + +connection slave; +# It may happen that `Rpl_semi_sync_slave_send_ack` of slave2's (server_id=3) +# is incremented instead of slave's (server_id=2), or both (as in our case). +# We will validate only incremente for slave (server_id=2) + +--echo # Check send ACKs on replica server_id=2 +let $status_var= Rpl_semi_sync_slave_send_ack; +let $status_var_value= `SELECT $slave1_sent_ack + 1`; +source include/wait_for_status_var.inc; +show status like "Rpl_semi_sync_slave_send_ack"; + +# Check ACKs on on replica server_id=3: +# 2 ACKs are already sent by server_id=2 +# On some bb slave2 increments send_ack by 1 instead of by 2 +# so let's not show it here. + +--echo # Test 7: Simulate stop of the IO thread of replica +--echo # Note 1: Stopping the IO thread will unregister replica from master info +--echo # so for `server_id=2`, `rpl_semi_sync_slave_status` will be `OFF` +--echo # and so should not be visible in show statement output. +--echo # Note 2: New event will be created and successfully sent and acked by `server_id=3` +--echo # Note 3: Starting the IO thread again for `server_id=2` will enable `rpl_semi_sync_slave_status`, +--echo # but since there is no new transaction and `ack` counter is reseted, +--echo # `Gtid_State_Sent` and `Gtid_State_Ack` will be empty. +--echo # Note 4: When synching replica with primary, primary will resent the old +--echo # transaction, so `Gtid_State_Sent` will be the same event group +--echo # as `server_id=3`(replica that ACKed the transaction), but since +--echo # there is no new transaction on primary `Gtid_State_Ack` will +--echo # remain empty. +--echo # ----------------------------------------------------------------------- +connection master; +--echo # Check request_ack before stopping the slave +show variables like 'Rpl_semi_sync_master_request_ack'; + +connection slave; +show variables like 'rpl_semi_sync_slave_enabled'; +show variables like 'rpl_semi_sync_slave_status'; + +STOP SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_stop.inc + +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= OFF; +source include/wait_for_status_var.inc; +--echo # Semi-sync disabled on server_id=2 + +show variables like 'rpl_semi_sync_slave_status'; +--echo # slave_send_ack should be reseted when replica IO thread starts. +--echo # Here we are checking it holds the same value as before stopping the IO thread. +# Check slave_send_ack is reseted when replica is stopped +show status like "Rpl_semi_sync_slave_send_ack"; + +connection master; +# Note: without waiting that master [un]registers replica, multiple rows (cached) for +# the same replica may be showed in show replica hosts statement +# in case if `Rpl_semi_sync_master_clients` is used, so use `Slaves_connected` +# for the wait condition. +let $status_var= Slaves_connected; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +show status like "Slaves_connected"; + +--echo # Check request_ack after stopping the slave +show variables like 'Rpl_semi_sync_master_request_ack'; + +--echo # Initial show statement, without server_id=2 +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +# Show statement should not show server_id=2 +SHOW REPLICA HOSTS; + +connection master; +--echo # Check master status before new event test 7 +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_status'; +show variables like 'rpl_semi_sync_master_enabled'; + +# Write the new event +INSERT INTO t VALUES (10); + +--echo # Wait on transaction/request/ack and show them + +let $status_var= Rpl_semi_sync_master_get_ack; +let $status_var_value= `SELECT $master_get_ack_num + 1`; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_get_ack'; + +let $status_var= Rpl_semi_sync_master_request_ack; +let $status_var_value= `SELECT $master_request_ack_num + 1`; +source include/wait_for_status_var.inc; +show variables like 'Rpl_semi_sync_master_request_ack'; + +--echo # Transaction is not incremented and it should (TODO after MDEV-33615) +# let $status_var= Rpl_semi_sync_master_yes_tx; +# let $status_var_value= `SELECT $master_request_ack_num + 1`; +# source include/wait_for_status_var.inc; +show variables like 'Rpl_semi_sync_master_yes_tx'; +show variables like 'Rpl_semi_sync_master_no_tx'; + + +# Update ACK get/request number +let $master_request_ack_num= `SELECT $master_request_ack_num + 1`; +let $master_get_ack_num= `SELECT $master_get_ack_num + 1`; + +# Result show statement +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +connection slave; +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +# Wait on the slave status change +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show variables like 'rpl_semi_sync_slave_status'; +show variables like 'rpl_semi_sync_slave_enabled'; +# Check slave_send_ack is still reseted +show status like "Rpl_semi_sync_slave_send_ack"; + +connection master; +let $status_var= Slaves_connected; +let $status_var_value= 2; +source include/wait_for_status_var.inc; +show status like "Slaves_connected"; + +# It may happen that primary does not resend the transaction and that +# `Slaves_connected` is 2 and `rpl_semi_sync_master_clients` is still 1 +# Ensure with waiting on ACK +--source include/save_master_gtid.inc #Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Sent; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 1; +source include/wait_show_condition.inc; + +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 2; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_clients'; + +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +--echo "Sync replica with master" +sync_slave_with_master; + +connection master; +# After sync slave with master, the number of semi_sync clients is incremented +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 2; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_clients'; + +# Primary did resend transactions: +# `Gtid_state_ack` for `server_id=2` should be NULL, since no new events are active +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +# Master's get ACK and request ACK should be the same as before +let $status_var= Rpl_semi_sync_master_get_ack; +let $status_var_value= $master_get_ack_num; +source include/wait_for_status_var.inc; +let $status_var= Rpl_semi_sync_master_request_ack; +let $status_var_value= $master_request_ack_num; +source include/wait_for_status_var.inc; +show status like "Rpl_semi_sync_master_get_ack"; +show status like "Rpl_semi_sync_master_request_ack"; + +--echo # Test 8: Replica `server_id=2` failure with `corrupt_queue_event` +--echo # Note 1: Simulate replicas failure by making replica busy. +--echo # Consequence is that replica will be unregistered and that is why +--echo # we need to wait that replica unregisters (`Slaves_connected`). +--echo # By creating new event, only active replicas should respond +--echo # (`server_id=3`) with ACK +--echo # Note 2: In order not to show old result from `server_id=2`,from busy replica +--echo # we have to *wait* that binlog_dump_thread_count shows status +--echo # `Slaves_connected` decreased and after that check show statement. +--echo # ----------------------------------------------------------------------- +connection slave; +--let $sav_server_2_dbug= `SELECT @@GLOBAL.debug_dbug` +SET @@GLOBAL.debug_dbug= "+d,corrupt_queue_event"; + +connection master; +# Write the new event +INSERT INTO t VALUES (3); + +# Wait on master's get/request ACK num +let $status_var= Rpl_semi_sync_master_get_ack; +let $status_var_value= `SELECT $master_get_ack_num + 1`; +source include/wait_for_status_var.inc; +let $status_var= Rpl_semi_sync_master_request_ack; +let $status_var_value= `SELECT $master_request_ack_num + 1`; +source include/wait_for_status_var.inc; +let $status_var= Slaves_connected; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +show status like "Rpl_semi_sync_master_get_ack"; +show status like "Rpl_semi_sync_master_request_ack"; +show status like "Slaves_connected"; +# Update get/request ACK number +let $master_request_ack_num= `SELECT $master_request_ack_num + 1`; +let $master_get_ack_num= `SELECT $master_get_ack_num + 1`; + +--source include/save_master_gtid.inc #Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Ack; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 1; +source include/wait_show_condition.inc; +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +# Setting the old value for debug_dbug will not start the slave +connection slave; +--eval SET @@GLOBAL.debug_dbug= "$sav_server_2_dbug" + +connection master; +let $status_var= Slaves_connected; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +show status like "Slaves_connected"; +show status like 'Rpl_semi_sync_master_clients'; +# Result show statement should be the same as before +--connection master +--source include/save_master_gtid.inc # Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Ack; +let $condition= LIKE '%$master_pos%'; +source include/wait_show_condition.inc; + +--echo # Test 9: Stop `server_id=3` +--echo # Note: Check that no replicas get new generated event, so show statement +--echo # is expected to be empty. +--echo # ----------------------------------------------------------------------- +connection slave2; +--source include/stop_slave.inc +# Check slave_send_ack is reseted when replica is stopped +show status like "Rpl_semi_sync_slave_send_ack"; +--source include/reset_slave.inc +# Check slave_send_ack is reseted when replica is reseted +show status like "Rpl_semi_sync_slave_send_ack"; + +connection master; +# Here both replicas are off and primary will wait on ACK timeout (default 10), +# and turn-off semi-sync status, so let's decrease timeout. +--let $save_default_master_timeout= `SELECT @@GLOBAL.rpl_semi_sync_master_timeout` +select @@global.rpl_semi_sync_master_timeout; +set @@global.rpl_semi_sync_master_timeout= 2000; +select @@global.rpl_semi_sync_master_timeout; + +let $status_var= Slaves_connected; +let $status_var_value= 0; +source include/wait_for_status_var.inc; +show status like "Slaves_connected"; + +# get_ack and request_ack stay the same +let $status_var= Rpl_semi_sync_master_get_ack; +let $status_var_value= $master_get_ack_num; +source include/wait_for_status_var.inc; + +let $status_var= Rpl_semi_sync_master_request_ack; +let $status_var_value= $master_request_ack_num; +source include/wait_for_status_var.inc; + +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'rpl_semi_sync_master_get_ack'; +show status like 'Rpl_semi_sync_master_request_ack'; +show status like 'Rpl_semi_sync_master_status'; + +# Write the new event +INSERT INTO t VALUES (5); + +# When there are no semi-sync replicas and new event, master will wait timeout, +# (set by 2[s]) and will disable master status, because commit ACK has not occured +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= OFF; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_request_ack'; +show status like 'rpl_semi_sync_master_get_ack'; + +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +--echo # Start slaves again +connection slave; +--source include/start_slave.inc +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_slave%'; +--sync_with_master + +connection slave2; +--source include/start_slave.inc +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_slave%'; +--sync_with_master + +--echo # sync with master, should ENABLE master_status +connection master; +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_status'; + +# There will be 2 get ACKS from 2 replicas for 1 event +let $status_var= Rpl_semi_sync_master_get_ack; +let $status_var_value= `SELECT $master_get_ack_num + 1`; +source include/wait_for_status_var.inc; + +let $status_var= Rpl_semi_sync_master_request_ack; +let $status_var_value= `SELECT $master_request_ack_num + 1`; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_yes_tx'; + +# Update ACK get/request number +let $master_request_ack_num= `SELECT $master_request_ack_num + 1`; +let $master_get_ack_num= `SELECT $master_get_ack_num + 1`; + +--echo # Test 10: Testing `rpl_semi_sync_master_timeout=0` +--echo # Note 1: For asynchronous replication `Gtid_state_sent` is not null, +--echo # but `Gtid_state_ack` is null. +--echo # Note 2: We want that `rpl_semi_sync_master_timeout=0` be edge case, +--echo # by mimicking asynchronous replication, as semi-sync stalled +--echo # replication type, for which `Gtid_state_ack` should reflect +--echo # the latest received transaction by the replica[s]. +--echo # Also `rpl_semi_sync_master_status` has +--echo # to remain `ON`, instead switching off, so instead of +--echo # no waiting on ACK, primary must wait on ACK from replica. +--echo # Note 3: With this option we want `Gtid_state_ack` to reflect +--echo # the latest received transaction by the replica[s]. +--echo # ----------------------------------------------------------------------- +# Test DBUG_SYNC by stopping the slave and testing the new sync point +# Note we need to stop both slaves in order to control sent ACK for new active transaction + +--echo # Initial number of ACK get/requests +show status like 'rpl_semi_sync_master_get_ack'; +show status like 'rpl_semi_sync_master_request_ack'; +show variables like 'rpl_semi_sync_master_enabled'; + +# Master status must be `ON` +let $status_var= rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_master_status'; + +set global rpl_semi_sync_master_timeout=0; +select @@global.rpl_semi_sync_master_timeout; +# here rpl_semi_sync_master_status=0 means async is taking place (no wait on ACK from slave) +show variables like 'rpl_semi_sync_master_timeout'; + +connection slave; +--source include/stop_slave.inc +--let $save_server_2_dbug= `SELECT @@GLOBAL.DEBUG_DBUG` +SET @@GLOBAL.DEBUG_DBUG="d,synchronize_semisync_slave_reply"; +--source include/start_slave.inc +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_slave%'; + +connection slave2; +--source include/stop_slave.inc +--let $save_server_3_dbug= `SELECT @@GLOBAL.DEBUG_DBUG` +SET @@GLOBAL.DEBUG_DBUG="d,synchronize_semisync_slave_reply"; +--source include/start_slave.inc +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_slave%'; + +connection master; +# Write event +INSERT INTO t values (1111); + +--echo # Both replicas are stopped with synchronization point after master's new event +--connection slave +SET debug_sync='now WAIT_FOR at_slave_reply'; + +--connection slave2 +SET debug_sync='now WAIT_FOR at_slave_reply'; + +--connection master +# There will be no GET ACK so good enough to check +# if the initial `rpl_semi_sync_master_get_ack` is observed +let $status_var= rpl_semi_sync_master_get_ack; +let $status_var_value= `SELECT $master_get_ack_num`; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_master_get_ack'; + +# Checking show statement: +# `Gtid_State_Sent` > `Gtid_State_Ack` (ACK is empty) +--echo # `Gtid_State_Sent` event sent from primary +--source include/save_master_gtid.inc # Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Sent; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 1; +source include/wait_show_condition.inc; +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +# Allow server_id= 2 to send the ACK +connection slave; +SET debug_sync='now SIGNAL reply_ack_to_master'; + +--echo # Replica server_2 has sent ACK +# It may be race condition, so wait on proper master GTID for replica 2 +# We have to ensure that at least 1 row has latest GTID as ACK +# Problem occured that `Gtid_State_Sent` was delayed record +# Note we need `wait_for_all` be 0 since +# not all rows will have condition fullfiled +--connection master +--source include/save_master_gtid.inc # Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Ack; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 0; +source include/wait_show_condition.inc; + +let $status_var= rpl_semi_sync_master_get_ack; +let $status_var_value= `SELECT $master_get_ack_num + 1`; +source include/wait_for_status_var.inc; +# Update master's get ACK number +let $master_get_ack_num= `SELECT $master_get_ack_num + 1`; +show status like 'rpl_semi_sync_master_get_ack'; +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +# Allow server_id= 3 to send the ACK +connection slave2; +SET debug_sync='now SIGNAL reply_ack_to_master'; + +--echo # Replica server_3 has sent ACK +# GTID_sent == GTID_ack (already sent by server_id=2) +# It may be race condition, so wait on proper master GTID for replica 3 +# We have to ensure that at least 1 row has latest GTID as ACK +--connection master +--source include/save_master_gtid.inc # Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Ack; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 0; +source include/wait_show_condition.inc; + +# Here we will not check the since primary may or may not receive the get ACK +# from second replica, if it already received the same number of requested ACKs. +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +sync_slave_with_master slave2; + +--echo # Sync server_3 with master should return the same result as before +connection master; +--source include/save_master_gtid.inc # Saves the gtid into $master_pos +let $show_statement= SHOW REPLICA HOSTS; +let $field= Gtid_State_Ack; +let $condition= LIKE '%$master_pos%'; +let $wait_for_all= 0; +source include/wait_show_condition.inc; +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW REPLICA HOSTS; + +--echo # cleanup +--echo # ------------------------------------------- +connection master; +--eval SET @@GLOBAL.rpl_semi_sync_master_timeout= $save_default_master_timeout +SET GLOBAL rpl_semi_sync_master_enabled = 0; +drop table t; +drop table t2; +--source include/save_master_gtid.inc +--save_master_pos + +connection slave; +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--eval SET @@GLOBAL.debug_dbug= "$save_server_2_dbug" +SET debug_sync='RESET'; +set global rpl_semi_sync_slave_enabled = 0; +--source include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; + +connection slave2; +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +set global rpl_semi_sync_slave_enabled = 0; +--eval SET @@GLOBAL.debug_dbug= "$save_server_3_dbug" +SET debug_sync='RESET'; +--source include/start_slave.inc +show variables like 'rpl_semi_sync_slave_enabled'; +--source include/stop_slave.inc + +# End of tests --source include/rpl_end.inc diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index d0285b549281b..c3be74e63b814 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -37,18 +37,7 @@ #include "rpl_filter.h" #include "log_event.h" #include - - -struct Slave_info -{ - uint32 server_id; - uint32 master_id; - char host[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; - char user[USERNAME_LENGTH+1]; - char password[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; - uint16 port; -}; - +#include "semisync_master.h" Atomic_counter binlog_dump_thread_count; ulong rpl_status=RPL_NULL; @@ -125,8 +114,11 @@ int THD::register_slave(uchar *packet, size_t packet_length) if (check_access(this, PRIV_COM_REGISTER_SLAVE, any_db.str, NULL,NULL,0,0)) return 1; if (!(si= (Slave_info*)my_malloc(key_memory_SLAVE_INFO, sizeof(Slave_info), - MYF(MY_WME)))) + MYF(MY_ZEROFILL)))) return 1; + memset(si->gtid_state_sent.log_file, '\0', FN_REFLEN); + memset(si->gtid_state_ack.log_file, '\0', FN_REFLEN); + si->semi_sync_trans_status= false; variables.server_id= si->server_id= uint4korr(p); p+= 4; @@ -179,7 +171,11 @@ static my_bool show_slave_hosts_callback(THD *thd, Protocol *protocol) { my_bool res= FALSE; mysql_mutex_lock(&thd->LOCK_thd_data); - if (auto si= thd->slave_info) + String gtid_sent[GTID_MAX_STR_LENGTH]; + String gtid_ack[GTID_MAX_STR_LENGTH]; + const char *sync_str_opt[]= {"asynchronous","semi-sync active","semi-sync stale"}; + char *sync_str= (char *)sync_str_opt[0]; + if (const Slave_info *si= thd->slave_info) { protocol->prepare_for_resend(); protocol->store(si->server_id); @@ -189,8 +185,20 @@ static my_bool show_slave_hosts_callback(THD *thd, Protocol *protocol) protocol->store(si->user, safe_strlen(si->user), &my_charset_bin); protocol->store(si->password, safe_strlen(si->password), &my_charset_bin); } + gtid_state_from_binlog_pos(si->gtid_state_sent.log_file, + (uint32)si->gtid_state_sent.log_pos, gtid_sent); + if (rpl_semi_sync_master_enabled && thd->semi_sync_slave) + { + gtid_state_from_binlog_pos(si->gtid_state_ack.log_file, + (uint32)si->gtid_state_ack.log_pos, gtid_ack); + sync_str= si->semi_sync_trans_status ? + (char *)sync_str_opt[1] :(char *)sync_str_opt[2]; + } protocol->store((uint32) si->port); protocol->store(si->master_id); + protocol->store(gtid_sent); + protocol->store(gtid_ack); + protocol->store(sync_str, safe_strlen(sync_str), &my_charset_bin); res= protocol->write(); } mysql_mutex_unlock(&thd->LOCK_thd_data); @@ -235,6 +243,18 @@ bool show_slave_hosts(THD* thd) Item_return_int(thd, "Master_id", 10, MYSQL_TYPE_LONG), thd->mem_root); + field_list.push_back(new (mem_root) + Item_empty_string(thd, "Gtid_State_Sent", GTID_MAX_STR_LENGTH), + thd->mem_root); + + field_list.push_back(new (mem_root) + Item_empty_string(thd, "Gtid_State_Ack", GTID_MAX_STR_LENGTH), + thd->mem_root); + + field_list.push_back(new (mem_root) + Item_empty_string(thd, "Sync_Status", GTID_MAX_STR_LENGTH), + thd->mem_root); + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc index aa1056c8c8f6f..306f7b03cdcfb 100644 --- a/sql/semisync_master.cc +++ b/sql/semisync_master.cc @@ -53,13 +53,6 @@ ulonglong rpl_semi_sync_master_trx_wait_time = 0; Repl_semi_sync_master repl_semisync_master; Ack_receiver ack_receiver; -/* - structure to save transaction log filename and position -*/ -typedef struct Trans_binlog_info { - my_off_t log_pos; - char log_file[FN_REFLEN]; -} Trans_binlog_info; static int get_wait_time(const struct timespec& start_ts); @@ -582,16 +575,7 @@ void Repl_semi_sync_master::remove_slave() unlock(); } - -/* - Check report package - - @retval 0 ok - @retval 1 Error - @retval -1 Slave is going down (ok) -*/ - -int Repl_semi_sync_master::report_reply_packet(uint32 server_id, +int Repl_semi_sync_master::report_reply_packet(THD *thd, uint32 server_id, const uchar *packet, ulong packet_len) { @@ -638,10 +622,8 @@ int Repl_semi_sync_master::report_reply_packet(uint32 server_id, DBUG_PRINT("semisync", ("%s: Got reply(%s, %lu) from server %u", "Repl_semi_sync_master::report_reply_packet", log_file_name, (ulong)log_file_pos, server_id)); - rpl_semi_sync_master_get_ack++; - report_reply_binlog(server_id, log_file_name, log_file_pos); - DBUG_RETURN(0); + report_reply_binlog(thd->slave_info, log_file_name, log_file_pos); l_end: { @@ -655,7 +637,7 @@ int Repl_semi_sync_master::report_reply_packet(uint32 server_id, DBUG_RETURN(result); } -int Repl_semi_sync_master::report_reply_binlog(uint32 server_id, +int Repl_semi_sync_master::report_reply_binlog(Slave_info *replica_thd_si, const char *log_file_name, my_off_t log_file_pos) { @@ -675,7 +657,7 @@ int Repl_semi_sync_master::report_reply_binlog(uint32 server_id, if (!is_on()) /* We check to see whether we can switch semi-sync ON. */ - try_switch_on(server_id, log_file_name, log_file_pos); + try_switch_on(replica_thd_si->server_id, log_file_name, log_file_pos); /* The position should increase monotonically, if there is only one * thread sending the binlog to the slave. @@ -721,6 +703,8 @@ int Repl_semi_sync_master::report_reply_binlog(uint32 server_id, log_file_name, (ulong)log_file_pos)); } + strncpy(replica_thd_si->gtid_state_ack.log_file, log_file_name, strlen(log_file_name)); + replica_thd_si->gtid_state_ack.log_pos= log_file_pos; l_end: unlock(); @@ -828,7 +812,7 @@ int Repl_semi_sync_master::dump_start(THD* thd, } add_slave(); - report_reply_binlog(thd->variables.server_id, + report_reply_binlog(thd->slave_info, log_file + dirname_length(log_file), log_pos); sql_print_information("Start semi-sync binlog_dump to slave " "(server_id: %ld), pos(%s, %lu)", @@ -858,7 +842,8 @@ int Repl_semi_sync_master::commit_trx(const char *trx_wait_binlog_name, bool success= 0; DBUG_ENTER("Repl_semi_sync_master::commit_trx"); - if (!rpl_semi_sync_master_clients && !rpl_semi_sync_master_wait_no_slave) + if (!rpl_semi_sync_master_clients && !rpl_semi_sync_master_wait_no_slave && + !m_wait_timeout) { rpl_semi_sync_master_no_transactions++; DBUG_RETURN(0); @@ -973,7 +958,17 @@ int Repl_semi_sync_master::commit_trx(const char *trx_wait_binlog_name, wait_result= mysql_cond_timedwait(&thd->COND_wakeup_ready, &LOCK_binlog, &abstime); rpl_semi_sync_master_wait_sessions--; - +#ifdef ENABLED_DEBUG_SYNC + /* + For debug symbol `pause_ack_thread_on_next_ack ` it will happen that + master status will be OFF so make sure to start it again. + */ + DBUG_EXECUTE_IF("pause_ack_thread_on_next_ack", + { + DBUG_PRINT("pause_ack_thread_on_next_ack", ("now")); + goto l_end; + }); +#endif if (wait_result != 0) { /* This is a real wait timeout. */ diff --git a/sql/semisync_master.h b/sql/semisync_master.h index 3978d21a61d31..b17539db463b4 100644 --- a/sql/semisync_master.h +++ b/sql/semisync_master.h @@ -21,6 +21,7 @@ #include "semisync.h" #include "semisync_master_ack_receiver.h" +#include "debug_sync.h" #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_LOCK_rpl_semi_sync_master_enabled; @@ -28,6 +29,36 @@ extern PSI_mutex_key key_LOCK_binlog; extern PSI_cond_key key_COND_binlog_send; #endif + +/* + structure to save transaction log filename and position +*/ +typedef struct Trans_binlog_info { + my_off_t log_pos; + char log_file[FN_REFLEN]; +} Trans_binlog_info; + + +struct Slave_info +{ + uint32 server_id; + uint32 master_id; + char host[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; + char user[USERNAME_LENGTH+1]; + char password[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; + uint16 port; +/* Following attributes are information of replica used during show_slave_hosts + command that is executed on primary. +*/ + Trans_binlog_info gtid_state_sent; + Trans_binlog_info gtid_state_ack; + /* semi_sync_trans_status is the status on the replica and represents + the status of the latest transaction event from the primary + */ + bool semi_sync_trans_status; +}; + + struct Tranx_node { char log_name[FN_REFLEN]; my_off_t log_pos; @@ -561,14 +592,14 @@ class Repl_semi_sync_master void remove_slave(); /* It parses a reply packet and call report_reply_binlog to handle it. */ - int report_reply_packet(uint32 server_id, const uchar *packet, + int report_reply_packet(THD *thd, uint32 server_id, const uchar *packet, ulong packet_len); /* In semi-sync replication, reports up to which binlog position we have * received replies from the slave indicating that it already get the events. * * Input: - * server_id - (IN) master server id number + * replica_thd - (IN) replica thread slave info * log_file_name - (IN) binlog file name * end_offset - (IN) the offset in the binlog file up to which we have * the replies from the slave @@ -576,8 +607,7 @@ class Repl_semi_sync_master * Return: * 0: success; non-zero: error */ - int report_reply_binlog(uint32 server_id, - const char* log_file_name, + int report_reply_binlog(Slave_info *replica_thd_si, const char* log_file_name, my_off_t end_offset); /* Commit a transaction in the final step. This function is called from diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc index 29fa5fd5328f9..62ad5b1970c74 100644 --- a/sql/semisync_master_ack_receiver.cc +++ b/sql/semisync_master_ack_receiver.cc @@ -353,7 +353,20 @@ void Ack_receiver::run() if (likely(len != packet_error)) { int res; - res= repl_semisync_master.report_reply_packet(slave->server_id(), +#ifdef ENABLED_DEBUG_SYNC + /* + A (+d,pause_ack_thread_on_next_ack)-test is supposed to + be run to check `Gtid_state_ack` in show replica hosts + for cases where there are multiple active replicas. + */ + DBUG_EXECUTE_IF("pause_ack_thread_on_next_ack", + { + const char act[]= "now SIGNAL pause_ack_reply_to_binlog WAIT_FOR unpause_ack_reply_to_binlog"; + DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); + DBUG_SET("-d,pause_ack_thread_on_next_ack"); + };); +#endif + res= repl_semisync_master.report_reply_packet(slave->thd, slave->server_id(), net.read_pos, len); if (unlikely(res < 0)) { diff --git a/sql/slave.cc b/sql/slave.cc index 8e1747e1e2457..2607402dcba87 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -5116,6 +5116,18 @@ Stopping slave I/O thread due to out-of-memory error from master"); { DBUG_EXECUTE_IF("simulate_delay_semisync_slave_reply", my_sleep(800000);); +#ifdef ENABLED_DEBUG_SYNC + /* + A (+d,synchronize_semisync_slave_reply)-test is supposed to + be run to check Gtid_state_sent and Gtid_state_ack in show replica hosts + */ + DBUG_EXECUTE_IF("synchronize_semisync_slave_reply", + { + const char act[]= "now SIGNAL at_slave_reply WAIT_FOR reply_ack_to_master"; + DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); + DBUG_SET("-d,synchronize_semisync_slave_reply"); + };); +#endif if (repl_semisync_slave.slave_reply(mi)) { /* diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c2d1776f24100..1f075840c1bea 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2065,6 +2065,19 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type, info->error= ER_UNKNOWN_ERROR; return "Failed to run hook 'after_send_event'"; } + /* + We want to store data slave_info on primary that will be used for + show_slave_hosts_callback. + We are interested in GTID sent by primary to replica. + */ + if (info->thd->semi_sync_slave) + { + strncpy(info->thd->slave_info->gtid_state_sent.log_file, + info->log_file_name + info->dirlen, + strlen(info->log_file_name)-info->dirlen); + info->thd->slave_info->gtid_state_sent.log_pos= pos; + info->thd->slave_info->semi_sync_trans_status= need_sync; + } return NULL; /* Success */ } @@ -2748,7 +2761,6 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo, ((info->errmsg= send_event_to_slave(info, event_type, log, ev_offset, &info->error_gtid)))) return 1; - if (unlikely(info->send_fake_gtid_list) && info->gtid_skip_group == GTID_SKIP_NOT) {