Bug #121666 START REPLICA UNTIL SQL_AFTER_GTIDS stops late for tagged GTIDs
Description:
START REPLICA SQL_THREAD UNTIL SQL_AFTER_GTIDS does not stop after the last
target transaction when the target set contains tagged GTIDs (UUID:tag:N).
The applier keeps applying later transactions, then logs
ER_REPLICA_SQL_THREAD_STOPPED_AFTER_GTIDS_REACHED as if it had stopped at
the target.
Until_after_gtids::check_before_dispatching_event()
(sql/rpl_replica_until_options.cc) only matches GTID_LOG_EVENT. A tagged GTID
is written as GTID_TAGGED_LOG_EVENT, so it is never added to
m_gtids_known_to_channel and the exact stop never fires. The applier stops
later: at a following transaction's COMMIT for DML, or only after the whole
relay log is read for DDL.
Untagged GTIDs and SQL_BEFORE_GTIDS are not affected.
How to repeat:
Save the test below as `mysql-test/suite/rpl_gtid/t/rpl_gtid_until_after_tagged.test` and run:
```
./mtr rpl_gtid.rpl_gtid_until_after_tagged --mysqld=--binlog-format=row
```
```
--source include/rpl/init_source_replica.inc
CREATE TABLE t1 (c1 INT PRIMARY KEY);
--let $uuid= `SELECT @@global.server_uuid`
--source include/rpl/sync_to_replica.inc
# DML: 4 tagged inserts, stop after the first 2
--source include/rpl/connection_replica.inc
--source include/rpl/stop_applier.inc
--source include/rpl/connection_source.inc
SET gtid_next = 'AUTOMATIC:tag1';
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (3);
INSERT INTO t1 VALUES (4);
SET gtid_next = 'AUTOMATIC';
--source include/rpl/sync_to_replica_received.inc
--replace_result $uuid UUID
eval START REPLICA SQL_THREAD UNTIL SQL_AFTER_GTIDS = '$uuid:tag1:1-2';
--source include/rpl/wait_for_applier_to_stop.inc
--let $assert_text= Applier stopped exactly after tag1:1-2
--let $assert_cond= [SELECT COUNT(*) FROM t1] = 2
--source include/assert.inc
--source include/rpl/start_applier.inc
--source include/rpl/connection_source.inc
--source include/rpl/sync_to_replica.inc
# DDL: 4 tagged CREATE TABLE, stop after the first 2
--source include/rpl/connection_replica.inc
--source include/rpl/stop_applier.inc
--source include/rpl/connection_source.inc
SET gtid_next = 'AUTOMATIC:tag2';
CREATE TABLE v1 (a INT);
CREATE TABLE v2 (a INT);
CREATE TABLE v3 (a INT);
CREATE TABLE v4 (a INT);
SET gtid_next = 'AUTOMATIC';
--source include/rpl/sync_to_replica_received.inc
--replace_result $uuid UUID
eval START REPLICA SQL_THREAD UNTIL SQL_AFTER_GTIDS = '$uuid:tag2:1-2';
--source include/rpl/wait_for_applier_to_stop.inc
--let $assert_text= Applier stopped exactly after tag2:1-2
--let $assert_cond= [SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = "test" AND table_name LIKE "v_"] = 2
--source include/assert.inc
--source include/rpl/start_applier.inc
--source include/rpl/connection_source.inc
DROP TABLE t1, v1, v2, v3, v4;
--source include/rpl/deinit.inc
```
Suggested fix:
In `Until_after_gtids::check_before_dispatching_event()`, match both GTID event types with `Log_event_type_helper::is_assigned_gtid_event()`, as `Until_before_gtids::check_before_dispatching_event()` already does:
```diff
--- a/sql/rpl_replica_until_options.cc
+++ b/sql/rpl_replica_until_options.cc
@@ -264,7 +264,8 @@ bool Until_after_gtids::check_at_start_slave() {
bool Until_after_gtids::check_before_dispatching_event(const Log_event *ev) {
DBUG_TRACE;
- if (ev->get_type_code() == mysql::binlog::event::GTID_LOG_EVENT) {
+ if (mysql::binlog::event::Log_event_type_helper::is_assigned_gtid_event(
+ ev->get_type_code())) {
global_tsid_lock->wrlock();
```
The `down_cast<const Gtid_log_event *>` below the check stays valid, because a tagged GTID event is also built as a `Gtid_log_event`. Anonymous GTIDs stay excluded. With the fix, the test above passes, and the existing UNTIL tests in `rpl_gtid`, `rpl` and `rpl_nogtid` pass with row, mixed and statement formats.
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.037 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: START REPLICA SQL_THREAD UNTIL SQL_AFTER_GTIDS does not stop after the last target transaction when the target set contains tagged GTIDs (UUID:tag:N). The applier keeps applying later transactions, then logs ER_REPLICA_SQL_THREAD_STOPPED_AFTER_GTIDS_REACHED as if it had stopped at the target. Until_after_gtids::check_before_dispatching_event() (sql/rpl_replica_until_options.cc) only matches GTID_LOG_EVENT. A tagged GTID is written as GTID_TAGGED_LOG_EVENT, so it is never added to m_gtids_known_to_channel and the exact stop never fires. The applier stops later: at a following transaction's COMMIT for DML, or only after the whole relay log is read for DDL. Untagged GTIDs and SQL_BEFORE_GTIDS are not affected. How to repeat: Save the test below as `mysql-test/suite/rpl_gtid/t/rpl_gtid_until_after_tagged.test` and run: ``` ./mtr rpl_gtid.rpl_gtid_until_after_tagged --mysqld=--binlog-format=row ``` ``` --source include/rpl/init_source_replica.inc CREATE TABLE t1 (c1 INT PRIMARY KEY); --let $uuid= `SELECT @@global.server_uuid` --source include/rpl/sync_to_replica.inc # DML: 4 tagged inserts, stop after the first 2 --source include/rpl/connection_replica.inc --source include/rpl/stop_applier.inc --source include/rpl/connection_source.inc SET gtid_next = 'AUTOMATIC:tag1'; INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); SET gtid_next = 'AUTOMATIC'; --source include/rpl/sync_to_replica_received.inc --replace_result $uuid UUID eval START REPLICA SQL_THREAD UNTIL SQL_AFTER_GTIDS = '$uuid:tag1:1-2'; --source include/rpl/wait_for_applier_to_stop.inc --let $assert_text= Applier stopped exactly after tag1:1-2 --let $assert_cond= [SELECT COUNT(*) FROM t1] = 2 --source include/assert.inc --source include/rpl/start_applier.inc --source include/rpl/connection_source.inc --source include/rpl/sync_to_replica.inc # DDL: 4 tagged CREATE TABLE, stop after the first 2 --source include/rpl/connection_replica.inc --source include/rpl/stop_applier.inc --source include/rpl/connection_source.inc SET gtid_next = 'AUTOMATIC:tag2'; CREATE TABLE v1 (a INT); CREATE TABLE v2 (a INT); CREATE TABLE v3 (a INT); CREATE TABLE v4 (a INT); SET gtid_next = 'AUTOMATIC'; --source include/rpl/sync_to_replica_received.inc --replace_result $uuid UUID eval START REPLICA SQL_THREAD UNTIL SQL_AFTER_GTIDS = '$uuid:tag2:1-2'; --source include/rpl/wait_for_applier_to_stop.inc --let $assert_text= Applier stopped exactly after tag2:1-2 --let $assert_cond= [SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = "test" AND table_name LIKE "v_"] = 2 --source include/assert.inc --source include/rpl/start_applier.inc --source include/rpl/connection_source.inc DROP TABLE t1, v1, v2, v3, v4; --source include/rpl/deinit.inc ``` Suggested fix: In `Until_after_gtids::check_before_dispatching_event()`, match both GTID event types with `Log_event_type_helper::is_assigned_gtid_event()`, as `Until_before_gtids::check_before_dispatching_event()` already does: ```diff --- a/sql/rpl_replica_until_options.cc +++ b/sql/rpl_replica_until_options.cc @@ -264,7 +264,8 @@ bool Until_after_gtids::check_at_start_slave() { bool Until_after_gtids::check_before_dispatching_event(const Log_event *ev) { DBUG_TRACE; - if (ev->get_type_code() == mysql::binlog::event::GTID_LOG_EVENT) { + if (mysql::binlog::event::Log_event_type_helper::is_assigned_gtid_event( + ev->get_type_code())) { global_tsid_lock->wrlock(); ``` The `down_cast<const Gtid_log_event *>` below the check stays valid, because a tagged GTID event is also built as a `Gtid_log_event`. Anonymous GTIDs stay excluded. With the fix, the test above passes, and the existing UNTIL tests in `rpl_gtid`, `rpl` and `rpl_nogtid` pass with row, mixed and statement formats.