/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.artemis.tests.stress.paging; import java.util.ArrayList; import java.util.HashMap; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; 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; import org.apache.activemq.artemis.api.core.client.ServerLocator; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.core.server.impl.QueueImpl; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class MultipleConsumersPageStressTest extends ActiveMQTestBase { private final UnitTestLogger log = UnitTestLogger.LOGGER; // Constants ----------------------------------------------------- // Attributes ---------------------------------------------------- private static final int TIME_TO_RUN = 60 * 1000; private static final SimpleString ADDRESS = new SimpleString("page-adr"); private int numberOfProducers; private int numberOfConsumers; private QueueImpl pagedServerQueue; private boolean shareConnectionFactory = true; private boolean openConsumerOnEveryLoop = true; private ActiveMQServer server; private ServerLocator sharedLocator; private ClientSessionFactory sharedSf; final AtomicInteger messagesAvailable = new AtomicInteger(0); private volatile boolean runningProducer = true; private volatile boolean runningConsumer = true; ArrayList<TestProducer> producers = new ArrayList<>(); ArrayList<TestConsumer> consumers = new ArrayList<>(); ArrayList<Throwable> exceptions = new ArrayList<>(); @Test public void testOpenConsumerEveryTimeDefaultFlowControl0() throws Throwable { shareConnectionFactory = true; openConsumerOnEveryLoop = true; numberOfProducers = 1; numberOfConsumers = 1; sharedLocator = createInVMNonHALocator().setConsumerWindowSize(0); sharedSf = createSessionFactory(sharedLocator); internalMultipleConsumers(); } @Override @Before public void setUp() throws Exception { super.setUp(); HashMap<String, AddressSettings> settings = new HashMap<>(); server = createServer(true, createDefaultInVMConfig(), 10024, 200024, settings); server.start(); pagedServerQueue = (QueueImpl) server.createQueue(ADDRESS, RoutingType.ANYCAST, ADDRESS, null, true, false); } @Test public void testOpenConsumerEveryTimeDefaultFlowControl() throws Throwable { shareConnectionFactory = true; openConsumerOnEveryLoop = true; numberOfProducers = 1; numberOfConsumers = 1; sharedLocator = createInVMNonHALocator(); sharedSf = createSessionFactory(sharedLocator); System.out.println(pagedServerQueue.debug()); internalMultipleConsumers(); } @Test public void testReuseConsumersFlowControl0() throws Throwable { shareConnectionFactory = true; openConsumerOnEveryLoop = false; numberOfProducers = 1; numberOfConsumers = 1; sharedLocator = createInVMNonHALocator().setConsumerWindowSize(0); sharedSf = createSessionFactory(sharedLocator); try { internalMultipleConsumers(); } catch (Throwable e) { TestConsumer tstConsumer = consumers.get(0); System.out.println("first retry: " + tstConsumer.consumer.receive(1000)); System.out.println(pagedServerQueue.debug()); pagedServerQueue.forceDelivery(); System.out.println("Second retry: " + tstConsumer.consumer.receive(1000)); System.out.println(pagedServerQueue.debug()); tstConsumer.session.commit(); System.out.println("Third retry:" + tstConsumer.consumer.receive(1000)); tstConsumer.close(); ClientSession session = sharedSf.createSession(); session.start(); ClientConsumer consumer = session.createConsumer(ADDRESS); pagedServerQueue.forceDelivery(); System.out.println("Fourth retry: " + consumer.receive(1000)); System.out.println(pagedServerQueue.debug()); throw e; } } public void internalMultipleConsumers() throws Throwable { for (int i = 0; i < numberOfProducers; i++) { producers.add(new TestProducer()); } for (int i = 0; i < numberOfConsumers; i++) { consumers.add(new TestConsumer()); } for (Tester test : producers) { test.start(); } Thread.sleep(2000); for (Tester test : consumers) { test.start(); } for (Tester test : consumers) { test.join(); } runningProducer = false; for (Tester test : producers) { test.join(); } for (Throwable e : exceptions) { throw e; } } // Static -------------------------------------------------------- // Constructors -------------------------------------------------- // Public -------------------------------------------------------- // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- abstract class Tester extends Thread { Random random = new Random(); public abstract void close(); protected abstract boolean enabled(); protected void exceptionHappened(final Throwable e) { runningConsumer = false; runningProducer = false; e.printStackTrace(); exceptions.add(e); } public int getNumberOfMessages() throws Exception { int numberOfMessages = random.nextInt(20); if (numberOfMessages <= 0) { return 1; } else { return numberOfMessages; } } } class TestConsumer extends Tester { public ClientConsumer consumer = null; public ClientSession session = null; public ServerLocator locator = null; public ClientSessionFactory sf = null; @Override public void close() { try { if (!openConsumerOnEveryLoop) { consumer.close(); } session.rollback(); session.close(); if (!shareConnectionFactory) { sf.close(); locator.close(); } } catch (Exception ignored) { } } @Override protected boolean enabled() { return runningConsumer; } @Override public int getNumberOfMessages() throws Exception { while (enabled()) { int numberOfMessages = super.getNumberOfMessages(); int resultMessages = messagesAvailable.addAndGet(-numberOfMessages); if (resultMessages < 0) { messagesAvailable.addAndGet(-numberOfMessages); numberOfMessages = 0; System.out.println("Negative, giving a little wait"); Thread.sleep(1000); } if (numberOfMessages > 0) { return numberOfMessages; } } return 0; } @Override public void run() { try { if (shareConnectionFactory) { session = sharedSf.createSession(false, false); } else { locator = createInVMNonHALocator(); sf = createSessionFactory(locator); session = sf.createSession(false, false); } long timeOut = System.currentTimeMillis() + MultipleConsumersPageStressTest.TIME_TO_RUN; session.start(); if (!openConsumerOnEveryLoop) { consumer = session.createConsumer(MultipleConsumersPageStressTest.ADDRESS); } int count = 0; while (enabled() && timeOut > System.currentTimeMillis()) { if (openConsumerOnEveryLoop) { consumer = session.createConsumer(MultipleConsumersPageStressTest.ADDRESS); } int numberOfMessages = getNumberOfMessages(); for (int i = 0; i < numberOfMessages; i++) { ClientMessage msg = consumer.receive(10000); if (msg == null) { log.warn("msg " + count + " was null, currentBatchSize=" + numberOfMessages + ", current msg being read=" + i); } Assert.assertNotNull("msg " + count + " was null, currentBatchSize=" + numberOfMessages + ", current msg being read=" + i, msg); if (numberOfConsumers == 1 && numberOfProducers == 1) { Assert.assertEquals(count, msg.getIntProperty("count").intValue()); } count++; msg.acknowledge(); } session.commit(); if (openConsumerOnEveryLoop) { consumer.close(); } } } catch (Throwable e) { exceptionHappened(e); } } } class TestProducer extends Tester { ClientSession session = null; ClientSessionFactory sf = null; ServerLocator locator = null; @Override public void close() { try { session.rollback(); session.close(); } catch (Exception ignored) { } } @Override protected boolean enabled() { return runningProducer; } @Override public void run() { try { if (shareConnectionFactory) { session = sharedSf.createSession(false, false); } else { locator = createInVMNonHALocator(); sf = createSessionFactory(locator); session = sf.createSession(false, false); } ClientProducer prod = session.createProducer(MultipleConsumersPageStressTest.ADDRESS); int count = 0; while (enabled()) { int numberOfMessages = getNumberOfMessages(); for (int i = 0; i < numberOfMessages; i++) { ClientMessage msg = session.createMessage(true); msg.putStringProperty("Test", "This is a simple test"); msg.putIntProperty("count", count++); prod.send(msg); } messagesAvailable.addAndGet(numberOfMessages); session.commit(); } } catch (Throwable e) { exceptionHappened(e); } } } }