/** * 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.bugs; import javax.jms.Connection; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.ObjectMessage; import javax.jms.Session; import junit.framework.TestCase; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerService; import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; import org.apache.activemq.usage.SystemUsage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * Try and replicate: * Caused by: java.io.IOException: Could not locate data file data--188 * at org.apache.activemq.kaha.impl.async.AsyncDataManager.getDataFile(AsyncDataManager.java:302) * at org.apache.activemq.kaha.impl.async.AsyncDataManager.read(AsyncDataManager.java:614) * at org.apache.activemq.store.amq.AMQPersistenceAdapter.readCommand(AMQPersistenceAdapter.java:523) */ public class MissingDataFileTest extends TestCase { private static final Logger LOG = LoggerFactory.getLogger(MissingDataFileTest.class); private static int counter = 500; private static int hectorToHaloCtr; private static int xenaToHaloCtr; private static int troyToHaloCtr; private static int haloToHectorCtr; private static int haloToXenaCtr; private static int haloToTroyCtr; private final String hectorToHalo = "hectorToHalo"; private final String xenaToHalo = "xenaToHalo"; private final String troyToHalo = "troyToHalo"; private final String haloToHector = "haloToHector"; private final String haloToXena = "haloToXena"; private final String haloToTroy = "haloToTroy"; private BrokerService broker; private Connection hectorConnection; private Connection xenaConnection; private Connection troyConnection; private Connection haloConnection; private final Object lock = new Object(); final boolean useTopic = false; final boolean useSleep = true; protected static final String payload = new String(new byte[500]); public Connection createConnection() throws JMSException { ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); return factory.createConnection(); } public Session createSession(Connection connection, boolean transacted) throws JMSException { return connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); } public void startBroker() throws Exception { broker = new BrokerService(); broker.setDeleteAllMessagesOnStartup(true); broker.setPersistent(true); broker.setUseJmx(true); broker.addConnector("tcp://localhost:61616").setName("Default"); SystemUsage systemUsage; systemUsage = new SystemUsage(); systemUsage.getMemoryUsage().setLimit(10 * 1024 * 1024); // Just a few messags broker.setSystemUsage(systemUsage); KahaDBPersistenceAdapter kahaDBPersistenceAdapter = new KahaDBPersistenceAdapter(); kahaDBPersistenceAdapter.setJournalMaxFileLength(16*1024); kahaDBPersistenceAdapter.setCleanupInterval(500); broker.setPersistenceAdapter(kahaDBPersistenceAdapter); broker.start(); LOG.info("Starting broker.."); } @Override public void tearDown() throws Exception { hectorConnection.close(); xenaConnection.close(); troyConnection.close(); haloConnection.close(); broker.stop(); } public void testForNoDataFoundError() throws Exception { startBroker(); hectorConnection = createConnection(); Thread hectorThread = buildProducer(hectorConnection, hectorToHalo, false, useTopic); Receiver hHectorReceiver = new Receiver() { @Override public void receive(String s) throws Exception { haloToHectorCtr++; if (haloToHectorCtr >= counter) { synchronized (lock) { lock.notifyAll(); } } possiblySleep(haloToHectorCtr); } }; buildReceiver(hectorConnection, haloToHector, false, hHectorReceiver, useTopic); troyConnection = createConnection(); Thread troyThread = buildProducer(troyConnection, troyToHalo); Receiver hTroyReceiver = new Receiver() { @Override public void receive(String s) throws Exception { haloToTroyCtr++; if (haloToTroyCtr >= counter) { synchronized (lock) { lock.notifyAll(); } } possiblySleep(haloToTroyCtr); } }; buildReceiver(hectorConnection, haloToTroy, false, hTroyReceiver, false); xenaConnection = createConnection(); Thread xenaThread = buildProducer(xenaConnection, xenaToHalo); Receiver hXenaReceiver = new Receiver() { @Override public void receive(String s) throws Exception { haloToXenaCtr++; if (haloToXenaCtr >= counter) { synchronized (lock) { lock.notifyAll(); } } possiblySleep(haloToXenaCtr); } }; buildReceiver(xenaConnection, haloToXena, false, hXenaReceiver, false); haloConnection = createConnection(); final MessageSender hectorSender = buildTransactionalProducer(haloToHector, haloConnection, false); final MessageSender troySender = buildTransactionalProducer(haloToTroy, haloConnection, false); final MessageSender xenaSender = buildTransactionalProducer(haloToXena, haloConnection, false); Receiver hectorReceiver = new Receiver() { @Override public void receive(String s) throws Exception { hectorToHaloCtr++; troySender.send(payload); if (hectorToHaloCtr >= counter) { synchronized (lock) { lock.notifyAll(); } possiblySleep(hectorToHaloCtr); } } }; Receiver xenaReceiver = new Receiver() { @Override public void receive(String s) throws Exception { xenaToHaloCtr++; hectorSender.send(payload); if (xenaToHaloCtr >= counter) { synchronized (lock) { lock.notifyAll(); } } possiblySleep(xenaToHaloCtr); } }; Receiver troyReceiver = new Receiver() { @Override public void receive(String s) throws Exception { troyToHaloCtr++; xenaSender.send(payload); if (troyToHaloCtr >= counter) { synchronized (lock) { lock.notifyAll(); } } } }; buildReceiver(haloConnection, hectorToHalo, true, hectorReceiver, false); buildReceiver(haloConnection, xenaToHalo, true, xenaReceiver, false); buildReceiver(haloConnection, troyToHalo, true, troyReceiver, false); haloConnection.start(); troyConnection.start(); troyThread.start(); xenaConnection.start(); xenaThread.start(); hectorConnection.start(); hectorThread.start(); waitForMessagesToBeDelivered(); // number of messages received should match messages sent assertEquals(hectorToHaloCtr, counter); LOG.info("hectorToHalo received " + hectorToHaloCtr + " messages"); assertEquals(xenaToHaloCtr, counter); LOG.info("xenaToHalo received " + xenaToHaloCtr + " messages"); assertEquals(troyToHaloCtr, counter); LOG.info("troyToHalo received " + troyToHaloCtr + " messages"); assertEquals(haloToHectorCtr, counter); LOG.info("haloToHector received " + haloToHectorCtr + " messages"); assertEquals(haloToXenaCtr, counter); LOG.info("haloToXena received " + haloToXenaCtr + " messages"); assertEquals(haloToTroyCtr, counter); LOG.info("haloToTroy received " + haloToTroyCtr + " messages"); } protected void possiblySleep(int count) throws InterruptedException { if (useSleep) { if (count % 100 == 0) { Thread.sleep(5000); } } } protected void waitForMessagesToBeDelivered() { // let's give the listeners enough time to read all messages long maxWaitTime = counter * 1000; long waitTime = maxWaitTime; long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); synchronized (lock) { boolean hasMessages = true; while (hasMessages && waitTime >= 0) { try { lock.wait(200); } catch (InterruptedException e) { LOG.error(e.toString()); } // check if all messages have been received hasMessages = hectorToHaloCtr < counter || xenaToHaloCtr < counter || troyToHaloCtr < counter || haloToHectorCtr < counter || haloToXenaCtr < counter || haloToTroyCtr < counter; waitTime = maxWaitTime - (System.currentTimeMillis() - start); } } } public MessageSender buildTransactionalProducer(String queueName, Connection connection, boolean isTopic) throws Exception { return new MessageSender(queueName, connection, true, isTopic); } public Thread buildProducer(Connection connection, final String queueName) throws Exception { return buildProducer(connection, queueName, false, false); } public Thread buildProducer(Connection connection, final String queueName, boolean transacted, boolean isTopic) throws Exception { final MessageSender producer = new MessageSender(queueName, connection, transacted, isTopic); Thread thread = new Thread() { @Override public synchronized void run() { for (int i = 0; i < counter; i++) { try { producer.send(payload ); } catch (Exception e) { throw new RuntimeException("on " + queueName + " send", e); } } } }; return thread; } public void buildReceiver(Connection connection, final String queueName, boolean transacted, final Receiver receiver, boolean isTopic) throws Exception { final Session session = transacted ? connection.createSession(true, Session.SESSION_TRANSACTED) : connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer inputMessageConsumer = session.createConsumer(isTopic ? session.createTopic(queueName) : session.createQueue(queueName)); MessageListener messageListener = new MessageListener() { @Override public void onMessage(Message message) { try { ObjectMessage objectMessage = (ObjectMessage)message; String s = (String)objectMessage.getObject(); receiver.receive(s); if (session.getTransacted()) { session.commit(); } } catch (Exception e) { e.printStackTrace(); } } }; inputMessageConsumer.setMessageListener(messageListener); } }