From 743e72f1f4d81a8184d76fb45900b73ecead7be1 Mon Sep 17 00:00:00 2001 From: "wangjiahua.wjh" Date: Tue, 30 Jun 2026 10:38:30 +0800 Subject: [PATCH] [ISSUE #9633] Enable retry topic V2 by default to prevent name collision V1 retry topic naming uses underscore as separator (%RETRY%{cid}_{topic}), which is ambiguous because both topic and group names may contain underscores. This causes different (group, topic) pairs to map to the same retry topic, leading to cross-topic consumption and potential data leakage. V2 naming (using '+' separator) already exists but was disabled by default. This commit changes enableRetryTopicV2 default from false to true. Existing V1 retry topics are still readable because retrieveMessageFromPopRetryTopicV1 remains true (backward compatible). Changes: - BrokerConfig: enableRetryTopicV2 default false -> true - KeyBuilderTest: 3 new tests demonstrating V1 collision and V2 correctness --- .../apache/rocketmq/common/BrokerConfig.java | 2 +- .../rocketmq/common/KeyBuilderTest.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java index 38644659e10..e5d7cfa7a3a 100644 --- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java +++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java @@ -237,7 +237,7 @@ public class BrokerConfig extends BrokerIdentity { private boolean initPopOffsetByCheckMsgInMem = true; // read message from pop retry topic v1, for the compatibility, will be removed in the future version private boolean retrieveMessageFromPopRetryTopicV1 = true; - private boolean enableRetryTopicV2 = false; + private boolean enableRetryTopicV2 = true; private int popFromRetryProbability = 20; // pop retry probability for priority mode private int popFromRetryProbabilityForPriority = 0; diff --git a/common/src/test/java/org/apache/rocketmq/common/KeyBuilderTest.java b/common/src/test/java/org/apache/rocketmq/common/KeyBuilderTest.java index 47191c907fe..41c38f75003 100644 --- a/common/src/test/java/org/apache/rocketmq/common/KeyBuilderTest.java +++ b/common/src/test/java/org/apache/rocketmq/common/KeyBuilderTest.java @@ -60,4 +60,27 @@ public void testIsPopRetryTopicV2() { String popRetryTopicV1 = KeyBuilder.buildPopRetryTopicV1(topic, group); assertThat(KeyBuilder.isPopRetryTopicV2(popRetryTopicV1)).isEqualTo(false); } + + @Test + public void testV1CollisionExample() { + // Demonstrates the V1 naming collision: different (group, topic) pairs produce the same retry topic + // group="A_B" topic="C" vs group="A" topic="B_C" both produce %RETRY%A_B_C + String collision1 = KeyBuilder.buildPopRetryTopicV1("C", "A_B"); + String collision2 = KeyBuilder.buildPopRetryTopicV1("B_C", "A"); + assertThat(collision1).isEqualTo(collision2); // both are %RETRY%A_B_C + } + + @Test + public void testV2NoCollision() { + // V2 uses '+' separator which is not allowed in topic/group names, so no collision + String v2a = KeyBuilder.buildPopRetryTopicV2("C", "A_B"); + String v2b = KeyBuilder.buildPopRetryTopicV2("B_C", "A"); + assertThat(v2a).isNotEqualTo(v2b); // %RETRY%A_B+C vs %RETRY%A+B_C + } + + @Test + public void testDefaultEnableRetryTopicV2IsTrue() { + BrokerConfig config = new BrokerConfig(); + assertThat(config.isEnableRetryTopicV2()).isTrue(); + } } \ No newline at end of file