From 1c03eddd7bea2b405975cbcb1e75b9ec866ff9f6 Mon Sep 17 00:00:00 2001 From: Warrick <1016weicheng@gmail.com> Date: Wed, 20 May 2026 20:19:48 +0800 Subject: [PATCH 1/2] [fix] replace server.propagate_in_transaction by server.gtid_dbid_at_multi deps/xredis-gtid/xredis/xredis_gtid_rs.c tests/unit/moduleapi/propagate-gtid.tcl runtest-moduleapi Case: module auto-wrapped RedisModule_Replicate maps to one GTID Issue: one module auto-wrapped MULTI/EXEC could be mis-mapped into multiple GTIDs and crash in gtidSeqAppend because server.propagate_in_transaction was cleared before queued propagate() drained. Fix: use server.gtid_dbid_at_multi for the GTID in-multi check, and add a propagate-test.simple guard test plus moduleapi runner coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- deps/xredis-gtid | 2 +- runtest-moduleapi | 1 + tests/unit/moduleapi/propagate-gtid.tcl | 54 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/unit/moduleapi/propagate-gtid.tcl diff --git a/deps/xredis-gtid b/deps/xredis-gtid index 52841a2297b..e642bd25ac3 160000 --- a/deps/xredis-gtid +++ b/deps/xredis-gtid @@ -1 +1 @@ -Subproject commit 52841a2297b0efae5f0175a4dbd7c4b9539d3801 +Subproject commit e642bd25ac3a282b04472834dcb2928b8cbbcf47 diff --git a/runtest-moduleapi b/runtest-moduleapi index 56d149609d8..f76aaf6242e 100755 --- a/runtest-moduleapi +++ b/runtest-moduleapi @@ -21,6 +21,7 @@ $TCLSH tests/test_helper.tcl \ --single unit/moduleapi/testrdb \ --single unit/moduleapi/infotest \ --single unit/moduleapi/propagate \ +--single unit/moduleapi/propagate-gtid \ --single unit/moduleapi/hooks \ --single unit/moduleapi/misc \ --single unit/moduleapi/blockonkeys \ diff --git a/tests/unit/moduleapi/propagate-gtid.tcl b/tests/unit/moduleapi/propagate-gtid.tcl new file mode 100644 index 00000000000..f104d6e5ff4 --- /dev/null +++ b/tests/unit/moduleapi/propagate-gtid.tcl @@ -0,0 +1,54 @@ +set testmodule [file normalize tests/modules/propagate.so] + +tags {"modules" "gtid"} { + test {module auto-wrapped RedisModule_Replicate maps to one GTID} { + # This guards the cc178563b0281843 fix: module commands enqueue + # internal writes plus EXEC, so GTID must still treat the whole + # auto-wrapped MULTI/EXEC block as exactly one GTID. + start_server [list overrides [list gtid-enabled yes loadmodule "$testmodule"]] { + set replica [srv 0 client] + set replica_host [srv 0 host] + set replica_port [srv 0 port] + + start_server [list overrides [list gtid-enabled yes loadmodule "$testmodule"]] { + set master [srv 0 client] + set master_host [srv 0 host] + set master_port [srv 0 port] + + $replica replicaof $master_host $master_port + wait_for_sync $replica + + set master_repl [attach_to_replication_stream] + set replica_repl [attach_to_replication_stream] + + set uuid [status $master gtid_uuid] + set before_gno [status $master gtid_executed_gno_count] + set before_master_gtidset [status $master gtid_set] + set before_replica_gtidset [status $replica gtid_set] + set before_master_reploff [status $master master_repl_offset] + set before_replica_reploff [status $replica master_repl_offset] + + $master propagate-test.simple + wait_for_gtid_sync $master $replica + + set expected_gno [expr {$before_gno + 1}] + set expected_gtid "$uuid:$expected_gno" + + assert_equal $expected_gno [status $master gtid_executed_gno_count] + assert_equal 1 [$replica get counter-1] + assert_equal 1 [$replica get counter-2] + assert {[gtid_set_is_equal [status $master gtid_set] [status $replica gtid_set]]} + + assert_replication_stream $master_repl [list {select *} {multi} {incr counter-1} {incr counter-2} "gtid $expected_gtid * EXEC"] + assert_replication_stream $replica_repl [list {select *} {multi} {incr counter-1} {incr counter-2} "gtid $expected_gtid * EXEC"] + + assert_equal [expr {$before_master_reploff + 1}] [lindex [$master GTIDX SEQ LOCATE $before_master_gtidset] 0] + assert_equal $expected_gtid [lindex [$master GTIDX SEQ LOCATE $before_master_gtidset] 1] + assert_equal $expected_gtid [lindex [$replica GTIDX SEQ LOCATE $before_replica_gtidset] 1] + + close_replication_stream $master_repl + close_replication_stream $replica_repl + } + } + } +} From 1871fcacd0107f56217ecf24b5481ef7de21acdc Mon Sep 17 00:00:00 2001 From: "gd.zhou" Date: Wed, 20 May 2026 14:39:08 +0800 Subject: [PATCH 2/2] [hotfix] smove crash bug --- src/ctrip_swap_cmd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ctrip_swap_cmd.c b/src/ctrip_swap_cmd.c index 3b2b876d8e9..6d6453a6b23 100644 --- a/src/ctrip_swap_cmd.c +++ b/src/ctrip_swap_cmd.c @@ -1666,9 +1666,10 @@ int getKeyRequestSmove(int dbid, struct redisCommand *cmd, robj **argv, int argc SWAP_IN, SWAP_IN_DEL, cmd->flags, dbid); incrRefCount(argv[2]); - incrRefCount(argv[3]); + subkeys = zmalloc(sizeof(robj*)); - subkeys[0] = argv[3]; + /* must copy argv[3], setSwapAna use incrRefCount (in swap thread) */ + subkeys[0] = dupStringObject(argv[3]); getKeyRequestsAppendSubkeyResult(result,REQUEST_LEVEL_KEY,argv[2], 1, subkeys, SWAP_IN, 0, cmd->flags, dbid);