From 39a001a6027aa88c86b6653b4338f88babe6c81f Mon Sep 17 00:00:00 2001 From: Domenico Francesco Bruscino Date: Tue, 26 May 2026 16:16:02 +0200 Subject: [PATCH] ARTEMIS-6076 Prevent auto delete for non-empty addresses When an address has no direct bindings but the address size is > 0, it means queues on other addresses have one or more message references pointing to this address (e.g., queues bound to wildcard addresses). --- .../core/postoffice/impl/PostOfficeImpl.java | 8 +++++++- .../client/AutoDeleteAddressTest.java | 20 +++++++++++++------ .../client/TransientQueueTest.java | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java index bb2d9a398e9..5a4e660e3c3 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java @@ -1068,7 +1068,13 @@ private void deleteDuplicateCache(SimpleString address) throws Exception { @Override public boolean isAddressBound(final SimpleString address) throws Exception { Collection bindings = getDirectBindings(address); - return bindings != null && !bindings.isEmpty(); + PagingStore pagingStore = pagingManager.getPageStore(address); + return (bindings != null && !bindings.isEmpty()) || + // When an address has no direct bindings but the address size is > 0, it means queues on other addresses + // have one or more message references pointing to this address (e.g., queues bound to wildcard addresses). + // The address must be considered bound because these message references keep it in use, preventing + // operations like auto-deletion that should only occur when the address is truly unused. + (pagingStore != null && pagingStore.getAddressSize() > 0); } @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoDeleteAddressTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoDeleteAddressTest.java index 003ea2bc617..10eabeb5058 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoDeleteAddressTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoDeleteAddressTest.java @@ -18,18 +18,16 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import org.apache.activemq.artemis.api.core.QueueConfiguration; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.client.ClientConsumer; +import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; @@ -122,13 +120,11 @@ public void testAutoDeleteAddressWithWildcardAddress() throws Exception { String wildcardAddress = prefix + ".#"; String queue = RandomUtil.randomUUIDString(); final int MESSAGE_COUNT = 10; - final CountDownLatch latch = new CountDownLatch(MESSAGE_COUNT); server.createQueue(QueueConfiguration.of(queue).setAddress(wildcardAddress).setRoutingType(RoutingType.ANYCAST).setAutoCreated(true)); ClientSession consumerSession = cf.createSession(); ClientConsumer consumer = consumerSession.createConsumer(queue); - consumer.setMessageHandler(message -> latch.countDown()); consumerSession.start(); ClientSession producerSession = cf.createSession(); @@ -143,7 +139,19 @@ public void testAutoDeleteAddressWithWildcardAddress() throws Exception { } producerSession.close(); - assertTrue(latch.await(2, TimeUnit.SECONDS)); + PostOfficeTestAccessor.sweepAndReapAddresses((PostOfficeImpl) server.getPostOffice()); + + for (String address : addresses) { + assertNotNull(server.getAddressInfo(SimpleString.of(address))); + Wait.assertTrue(() -> Arrays.asList(server.getPagingManager().getStoreNames()).contains(SimpleString.of(address)), 2000, 100); + } + + for (int i = 0; i < MESSAGE_COUNT; i++) { + ClientMessage message = consumer.receive(3000); + assertNotNull(message); + message.acknowledge(); + } + consumer.close(); for (String address : addresses) { assertNotNull(server.getAddressInfo(SimpleString.of(address))); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/TransientQueueTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/TransientQueueTest.java index 2f54e290e5a..f160ec41d8c 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/TransientQueueTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/TransientQueueTest.java @@ -78,7 +78,7 @@ public void testMultipleConsumers() throws Exception { ServerLocator locator2 = createLocator(); ClientSessionFactory sf2 = locator2.createSessionFactory(); - ClientSession session2 = sf2.createSession(false, false); + ClientSession session2 = sf2.createSession(true, true); // At this point this has no effect, other than making sure the queue exists... // the JMS implementation will certainly create the queue again when dealing with