From cf749c488ba1beab49d4617ec95819eb24898d4c Mon Sep 17 00:00:00 2001 From: sywu14 Date: Tue, 26 May 2026 13:41:05 +0800 Subject: [PATCH] [ISSUE #9926] Avoid redundant list allocation in parsePublishMessageQueues When namespace is empty (the common case for most users), the method previously allocated a new ArrayList and N new MessageQueue objects on every send call, copying identical data. Under high throughput (50K+ TPS), this creates significant GC pressure from short-lived objects. This change: - Returns the original list directly when namespace is empty (zero alloc) - Pre-allocates ArrayList capacity when namespace stripping is needed Signed-off-by: sywu14 --- .../rocketmq/client/impl/MQAdminImpl.java | 9 ++++-- .../rocketmq/client/impl/MQAdminImplTest.java | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java index 729e917eed4..328aedaef9a 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQAdminImpl.java @@ -157,9 +157,14 @@ public List fetchPublishMessageQueues(String topic) throws MQClien } public List parsePublishMessageQueues(List messageQueueList) { - List resultQueues = new ArrayList<>(); + String namespace = this.mQClientFactory.getClientConfig().getNamespace(); + if (namespace == null || namespace.isEmpty()) { + return messageQueueList; + } + + List resultQueues = new ArrayList<>(messageQueueList.size()); for (MessageQueue queue : messageQueueList) { - String userTopic = NamespaceUtil.withoutNamespace(queue.getTopic(), this.mQClientFactory.getClientConfig().getNamespace()); + String userTopic = NamespaceUtil.withoutNamespace(queue.getTopic(), namespace); resultQueues.add(new MessageQueue(userTopic, queue.getBrokerName(), queue.getQueueId())); } diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/MQAdminImplTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/MQAdminImplTest.java index f52aba2dc00..79c58299552 100644 --- a/client/src/test/java/org/apache/rocketmq/client/impl/MQAdminImplTest.java +++ b/client/src/test/java/org/apache/rocketmq/client/impl/MQAdminImplTest.java @@ -44,6 +44,7 @@ import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -51,6 +52,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -215,6 +217,34 @@ private TopicRouteData createRouteData() { return result; } + @Test + public void assertParsePublishMessageQueuesReturnsOriginalListWhenNoNamespace() { + ClientConfig clientConfig = mock(ClientConfig.class); + when(clientConfig.getNamespace()).thenReturn(null); + when(mQClientFactory.getClientConfig()).thenReturn(clientConfig); + MQAdminImpl adminNoNs = new MQAdminImpl(mQClientFactory); + + List original = new ArrayList<>(); + original.add(new MessageQueue("TopicA", "broker-0", 0)); + original.add(new MessageQueue("TopicA", "broker-0", 1)); + + List result = adminNoNs.parsePublishMessageQueues(original); + assertSame(original, result); + } + + @Test + public void assertParsePublishMessageQueuesStripsNamespace() { + List original = new ArrayList<>(); + original.add(new MessageQueue("namespace%TopicA", "broker-0", 0)); + original.add(new MessageQueue("namespace%TopicA", "broker-0", 1)); + + List result = mqAdminImpl.parsePublishMessageQueues(original); + assertEquals(2, result.size()); + for (MessageQueue mq : result) { + assertEquals("TopicA", mq.getTopic()); + } + } + private List createBrokerData() { HashMap brokerAddrs = new HashMap<>(); brokerAddrs.put(MixAll.MASTER_ID, defaultBrokerAddr);