Package org.hornetq.tests.stress.journal

Source Code of org.hornetq.tests.stress.journal.NIOMultiThreadCompactorStressTest$ConsumerThread

/*
* Copyright 2009 Red Hat, Inc.
* Red Hat 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.hornetq.tests.stress.journal;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import junit.framework.Assert;

import org.hornetq.api.core.HornetQException;
import org.hornetq.api.core.SimpleString;
import org.hornetq.api.core.client.ClientConsumer;
import org.hornetq.api.core.client.ClientMessage;
import org.hornetq.api.core.client.ClientProducer;
import org.hornetq.api.core.client.ClientSession;
import org.hornetq.api.core.client.ClientSessionFactory;
import org.hornetq.core.asyncio.impl.AsynchronousFileImpl;
import org.hornetq.core.config.Configuration;
import org.hornetq.core.config.impl.ConfigurationImpl;
import org.hornetq.core.journal.PreparedTransactionInfo;
import org.hornetq.core.journal.RecordInfo;
import org.hornetq.core.journal.impl.JournalImpl;
import org.hornetq.core.journal.impl.NIOSequentialFileFactory;
import org.hornetq.core.server.HornetQServer;
import org.hornetq.core.server.JournalType;
import org.hornetq.tests.util.ServiceTestBase;

/**
* A MultiThreadConsumerStressTest
*
* @author <mailto:clebert.suconic@jboss.org">Clebert Suconic</a>
*
*
*/
public class NIOMultiThreadCompactorStressTest extends ServiceTestBase
{

   // Constants -----------------------------------------------------

   // Attributes ----------------------------------------------------

   final SimpleString ADDRESS = new SimpleString("SomeAddress");

   final SimpleString QUEUE = new SimpleString("SomeQueue");

   private HornetQServer server;

   private ClientSessionFactory sf;

   protected int getNumberOfIterations()
   {
      return 3;
   }

   @Override
   protected void setUp() throws Exception
   {
      super.setUp();
   }

   @Override
   protected void tearDown() throws Exception
   {
      stopServer();
      super.tearDown();
   }

   public void testMultiThreadCompact() throws Throwable
   {
      setupServer(getJournalType());
      for (int i = 0; i < getNumberOfIterations(); i++)
      {
         System.out.println("######################################");
         System.out.println("test # " + i);

         internalTestProduceAndConsume();
         stopServer();

         NIOSequentialFileFactory factory = new NIOSequentialFileFactory(getJournalDir());
         JournalImpl journal = new JournalImpl(ConfigurationImpl.DEFAULT_JOURNAL_FILE_SIZE,
                                               2,
                                               0,
                                               0,
                                               factory,
                                               "hornetq-data",
                                               "hq",
                                               100);

         List<RecordInfo> committedRecords = new ArrayList<RecordInfo>();
         List<PreparedTransactionInfo> preparedTransactions = new ArrayList<PreparedTransactionInfo>();

         journal.start();
         journal.load(committedRecords, preparedTransactions, null);

         Assert.assertEquals(0, committedRecords.size());
         Assert.assertEquals(0, preparedTransactions.size());

         System.out.println("DataFiles = " + journal.getDataFilesCount());

         if (i % 2 == 0 && i > 0)
         {
            System.out.println("DataFiles = " + journal.getDataFilesCount());
            journal.forceMoveNextFile();
            if (journal.getDataFilesCount() != 0)
            {
               System.out.println("DebugJournal:"  + journal.debug());
            }
            Assert.assertEquals(0, journal.getDataFilesCount());
         }

         journal.stop();
         journal = null;

         setupServer(getJournalType());

      }
   }

   /**
    * @return
    */
   protected JournalType getJournalType()
   {
      return JournalType.NIO;
   }

   /**
    * @param xid
    * @throws HornetQException
    * @throws XAException
    */
   private void addEmptyTransaction(final Xid xid) throws HornetQException, XAException
   {
      ClientSessionFactory sf = createInVMFactory();
      sf.setBlockOnNonDurableSend(false);
      sf.setBlockOnAcknowledge(false);
      ClientSession session = sf.createSession(true, false, false);
      session.start(xid, XAResource.TMNOFLAGS);
      session.end(xid, XAResource.TMSUCCESS);
      session.prepare(xid);
      session.close();
      sf.close();
   }

   private void checkEmptyXID(final Xid xid) throws HornetQException, XAException
   {
      ClientSessionFactory sf = createInVMFactory();
      sf.setBlockOnNonDurableSend(false);
      sf.setBlockOnAcknowledge(false);
      ClientSession session = sf.createSession(true, false, false);

      Xid[] xids = session.recover(XAResource.TMSTARTRSCAN);
      Assert.assertEquals(1, xids.length);
      Assert.assertEquals(xid, xids[0]);

      session.rollback(xid);

      session.close();
      sf.close();
   }

   public void internalTestProduceAndConsume() throws Throwable
   {

      addBogusData(100, "LAZY-QUEUE");

      Xid xid = null;
      xid = newXID();
      addEmptyTransaction(xid);

      System.out.println(getTemporaryDir());
      boolean transactionalOnConsume = true;
      boolean transactionalOnProduce = true;
      int numberOfConsumers = 30;
      // this test assumes numberOfConsumers == numberOfProducers
      int numberOfProducers = numberOfConsumers;
      int produceMessage = 5000;
      int commitIntervalProduce = 100;
      int consumeMessage = (int)(produceMessage * 0.9);
      int commitIntervalConsume = 100;

      System.out.println("ConsumeMessages = " + consumeMessage + " produceMessage = " + produceMessage);

      // Number of messages expected to be received after restart
      int numberOfMessagesExpected = (produceMessage - consumeMessage) * numberOfConsumers;

      CountDownLatch latchReady = new CountDownLatch(numberOfConsumers + numberOfProducers);

      CountDownLatch latchStart = new CountDownLatch(1);

      ArrayList<BaseThread> threads = new ArrayList<BaseThread>();

      ProducerThread[] prod = new ProducerThread[numberOfProducers];
      for (int i = 0; i < numberOfProducers; i++)
      {
         prod[i] = new ProducerThread(i,
                                      latchReady,
                                      latchStart,
                                      transactionalOnConsume,
                                      produceMessage,
                                      commitIntervalProduce);
         prod[i].start();
         threads.add(prod[i]);
      }

      ConsumerThread[] cons = new ConsumerThread[numberOfConsumers];

      for (int i = 0; i < numberOfConsumers; i++)
      {
         cons[i] = new ConsumerThread(i,
                                      latchReady,
                                      latchStart,
                                      transactionalOnProduce,
                                      consumeMessage,
                                      commitIntervalConsume);
         cons[i].start();
         threads.add(cons[i]);
      }

      latchReady.await();
      latchStart.countDown();

      for (BaseThread t : threads)
      {
         t.join();
         if (t.e != null)
         {
            throw t.e;
         }
      }

      server.stop();

      setupServer(getJournalType());

      drainQueue(numberOfMessagesExpected, QUEUE);
      drainQueue(100, new SimpleString("LAZY-QUEUE"));

      server.stop();

      setupServer(getJournalType());
      drainQueue(0, QUEUE);
      drainQueue(0, new SimpleString("LAZY-QUEUE"));

      checkEmptyXID(xid);

   }

   /**
    * @param numberOfMessagesExpected
    * @param queue
    * @throws HornetQException
    */
   private void drainQueue(final int numberOfMessagesExpected, final SimpleString queue) throws HornetQException
   {
      ClientSession sess = sf.createSession(true, true);

      ClientConsumer consumer = sess.createConsumer(queue);

      sess.start();

      for (int i = 0; i < numberOfMessagesExpected; i++)
      {
         ClientMessage msg = consumer.receive(5000);
         Assert.assertNotNull(msg);

         if (i % 100 == 0)
         {
            // System.out.println("Received #" + i + "  on thread after start");
         }
         msg.acknowledge();
      }

      Assert.assertNull(consumer.receiveImmediate());

      sess.close();
   }

   /**
    * @throws HornetQException
    */
   private void addBogusData(final int nmessages, final String queue) throws HornetQException
   {
      ClientSession session = sf.createSession(false, false);
      try
      {
         session.createQueue(queue, queue, true);
      }
      catch (Exception ignored)
      {
      }

      ClientProducer prod = session.createProducer(queue);
      for (int i = 0; i < nmessages; i++)
      {
         ClientMessage msg = session.createMessage(true);
         msg.getBodyBuffer().writeBytes(new byte[1024]);
         prod.send(msg);
      }
      session.commit();

      session.start();

      ClientConsumer cons = session.createConsumer(queue);
      Assert.assertNotNull(cons.receive(1000));
      session.rollback();
      session.close();
   }

   protected void stopServer() throws Exception
   {
      try
      {
         if (server != null && server.isStarted())
         {
            server.stop();
         }
      }
      catch (Throwable e)
      {
         e.printStackTrace(System.out); // System.out => junit reports
      }

      sf = null;
   }

   private void setupServer(JournalType journalType) throws Exception, HornetQException
   {
      if (!AsynchronousFileImpl.isLoaded())
      {
         journalType = JournalType.NIO;
      }
      if (server == null)
      {
         Configuration config = createDefaultConfig(true);
         config.setJournalFileSize(ConfigurationImpl.DEFAULT_JOURNAL_FILE_SIZE);

         config.setJournalType(journalType);
         config.setJMXManagementEnabled(false);

         config.setJournalFileSize(ConfigurationImpl.DEFAULT_JOURNAL_FILE_SIZE);
         config.setJournalMinFiles(ConfigurationImpl.DEFAULT_JOURNAL_MIN_FILES);

         config.setJournalCompactMinFiles(ConfigurationImpl.DEFAULT_JOURNAL_COMPACT_MIN_FILES);
         config.setJournalCompactPercentage(ConfigurationImpl.DEFAULT_JOURNAL_COMPACT_PERCENTAGE);

         // This test is supposed to not sync.. All the ACKs are async, and it was supposed to not sync
         config.setJournalSyncNonTransactional(false);

         // config.setJournalCompactMinFiles(0);
         // config.setJournalCompactPercentage(0);

         server = createServer(true, config);
      }

      server.start();

      sf = createNettyFactory();
      sf.setBlockOnDurableSend(false);
      sf.setBlockOnAcknowledge(false);

      ClientSession sess = sf.createSession();

      try
      {
         sess.createQueue(ADDRESS, QUEUE, true);
      }
      catch (Exception ignored)
      {
      }

      sess.close();

      sf = createInVMFactory();
   }

   // Static --------------------------------------------------------

   // Constructors --------------------------------------------------

   // Public --------------------------------------------------------

   class BaseThread extends Thread
   {
      Throwable e;

      final CountDownLatch latchReady;

      final CountDownLatch latchStart;

      final int numberOfMessages;

      final int commitInterval;

      final boolean transactional;

      BaseThread(final String name,
                 final CountDownLatch latchReady,
                 final CountDownLatch latchStart,
                 final boolean transactional,
                 final int numberOfMessages,
                 final int commitInterval)
      {
         super(name);
         this.transactional = transactional;
         this.latchReady = latchReady;
         this.latchStart = latchStart;
         this.commitInterval = commitInterval;
         this.numberOfMessages = numberOfMessages;
      }

   }

   class ProducerThread extends BaseThread
   {
      ProducerThread(final int id,
                     final CountDownLatch latchReady,
                     final CountDownLatch latchStart,
                     final boolean transactional,
                     final int numberOfMessages,
                     final int commitInterval)
      {
         super("ClientProducer:" + id, latchReady, latchStart, transactional, numberOfMessages, commitInterval);
      }

      @Override
      public void run()
      {
         ClientSession session = null;
         latchReady.countDown();
         try
         {
            latchStart.await();
            session = sf.createSession(!transactional, !transactional);
            ClientProducer prod = session.createProducer(ADDRESS);
            for (int i = 0; i < numberOfMessages; i++)
            {
               if (transactional)
               {
                  if (i % commitInterval == 0)
                  {
                     session.commit();
                  }
               }
               if (i % 100 == 0)
               {
                  // System.out.println(Thread.currentThread().getName() + "::sent #" + i);
               }
               ClientMessage msg = session.createMessage(true);

               prod.send(msg);
            }

            if (transactional)
            {
               session.commit();
            }

            System.out.println("Thread " + Thread.currentThread().getName() +
                               " sent " +
                               numberOfMessages +
                               "  messages");
         }
         catch (Throwable e)
         {
            e.printStackTrace();
            this.e = e;
         }
         finally
         {
            try
            {
               session.close();
            }
            catch (Throwable e)
            {
               this.e = e;
            }
         }
      }
   }

   class ConsumerThread extends BaseThread
   {
      ConsumerThread(final int id,
                     final CountDownLatch latchReady,
                     final CountDownLatch latchStart,
                     final boolean transactional,
                     final int numberOfMessages,
                     final int commitInterval)
      {
         super("ClientConsumer:" + id, latchReady, latchStart, transactional, numberOfMessages, commitInterval);
      }

      @Override
      public void run()
      {
         ClientSession session = null;
         latchReady.countDown();
         try
         {
            latchStart.await();
            session = sf.createSession(!transactional, !transactional);
            session.start();
            ClientConsumer cons = session.createConsumer(QUEUE);
            for (int i = 0; i < numberOfMessages; i++)
            {
               ClientMessage msg = cons.receive(60 * 1000);
               msg.acknowledge();
               if (i % commitInterval == 0)
               {
                  session.commit();
               }
               if (i % 100 == 0)
               {
                  // System.out.println(Thread.currentThread().getName() + "::received #" + i);
               }
            }

            System.out.println("Thread " + Thread.currentThread().getName() +
                               " received " +
                               numberOfMessages +
                               " messages");

            session.commit();
         }
         catch (Throwable e)
         {
            this.e = e;
         }
         finally
         {
            try
            {
               session.close();
            }
            catch (Throwable e)
            {
               this.e = e;
            }
         }
      }
   }

   // Package protected ---------------------------------------------

   // Protected -----------------------------------------------------

   // Private -------------------------------------------------------

   // Inner classes -------------------------------------------------

}
TOP

Related Classes of org.hornetq.tests.stress.journal.NIOMultiThreadCompactorStressTest$ConsumerThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.