Package org.hornetq.tests.integration.journal

Source Code of org.hornetq.tests.integration.journal.ValidateTransactionHealthTest$LocalThread

/*
* 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.integration.journal;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import junit.framework.Assert;

import org.hornetq.core.asyncio.impl.AsynchronousFileImpl;
import org.hornetq.core.config.impl.ConfigurationImpl;
import org.hornetq.core.journal.Journal;
import org.hornetq.core.journal.LoaderCallback;
import org.hornetq.core.journal.PreparedTransactionInfo;
import org.hornetq.core.journal.RecordInfo;
import org.hornetq.core.journal.SequentialFileFactory;
import org.hornetq.core.journal.impl.AIOSequentialFileFactory;
import org.hornetq.core.journal.impl.JournalImpl;
import org.hornetq.core.journal.impl.NIOSequentialFileFactory;
import org.hornetq.core.logging.Logger;
import org.hornetq.tests.util.SpawnedVMSupport;
import org.hornetq.tests.util.UnitTestCase;

/**
*
* This test spawns a remote VM, as we want to "crash" the VM right after the journal is filled with data
*
* @author <a href="mailto:clebert.suconic@jboss.com">Clebert Suconic</a>
*
*/
public class ValidateTransactionHealthTest extends UnitTestCase
{

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

   private static final Logger log = Logger.getLogger(ValidateTransactionHealthTest.class);

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

   private static final int OK = 10;

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

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

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

   public void testAIO() throws Exception
   {
      internalTest("aio", getTestDir(), 10000, 100, true, true, 1);
   }

   public void testAIOHugeTransaction() throws Exception
   {
      internalTest("aio", getTestDir(), 10000, 10000, true, true, 1);
   }

   public void testAIOMultiThread() throws Exception
   {
      internalTest("aio", getTestDir(), 1000, 100, true, true, 10);
   }

   public void testAIONonTransactionalNoExternalProcess() throws Exception
   {
      internalTest("aio", getTestDir(), 1000, 0, true, false, 10);
   }

   public void testNIO() throws Exception
   {
      internalTest("nio", getTestDir(), 10000, 100, true, true, 1);
   }

   public void testNIOHugeTransaction() throws Exception
   {
      internalTest("nio", getTestDir(), 10000, 10000, true, true, 1);
   }

   public void testNIOMultiThread() throws Exception
   {
      internalTest("nio", getTestDir(), 1000, 100, true, true, 10);
   }

   public void testNIONonTransactional() throws Exception
   {
      internalTest("nio", getTestDir(), 10000, 0, true, true, 1);
   }

   public void testNIO2() throws Exception
   {
      internalTest("nio2", getTestDir(), 10000, 100, true, true, 1);
   }

   public void testNIO2HugeTransaction() throws Exception
   {
      internalTest("nio2", getTestDir(), 10000, 10000, true, true, 1);
   }

   public void testNIO2MultiThread() throws Exception
   {
      internalTest("nio2", getTestDir(), 1000, 100, true, true, 10);
   }

   public void testNIO2NonTransactional() throws Exception
   {
      internalTest("nio2", getTestDir(), 10000, 0, true, true, 1);
   }

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

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

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

      File file = new File(getTestDir());
      deleteDirectory(file);
      file.mkdir();
   }

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

   private void internalTest(final String type,
                             final String journalDir,
                             final long numberOfRecords,
                             final int transactionSize,
                             final boolean append,
                             final boolean externalProcess,
                             final int numberOfThreads) throws Exception
   {
      try
      {
         if (type.equals("aio") && !AsynchronousFileImpl.isLoaded())
         {
            // Using System.out as this output will go towards junit report
            System.out.println("AIO not found, test being ignored on this platform");
            return;
         }

         // This property could be set to false for debug purposes.
         if (append)
         {
            if (externalProcess)
            {
               Process process = SpawnedVMSupport.spawnVM(ValidateTransactionHealthTest.class.getCanonicalName(),
                                                          type,
                                                          journalDir,
                                                          Long.toString(numberOfRecords),
                                                          Integer.toString(transactionSize),
                                                          Integer.toString(numberOfThreads));
               process.waitFor();
               Assert.assertEquals(ValidateTransactionHealthTest.OK, process.exitValue());
            }
            else
            {
               JournalImpl journal = ValidateTransactionHealthTest.appendData(type,
                                                                              journalDir,
                                                                              numberOfRecords,
                                                                              transactionSize,
                                                                              numberOfThreads);
               journal.stop();
            }
         }

         reload(type, journalDir, numberOfRecords, numberOfThreads);
      }
      finally
      {
         File file = new File(journalDir);
         deleteDirectory(file);
      }
   }

   private void reload(final String type, final String journalDir, final long numberOfRecords, final int numberOfThreads) throws Exception
   {
      JournalImpl journal = ValidateTransactionHealthTest.createJournal(type, journalDir);

      journal.start();
      Loader loadTest = new Loader(numberOfRecords);
      journal.load(loadTest);
      Assert.assertEquals(numberOfRecords * numberOfThreads, loadTest.numberOfAdds);
      Assert.assertEquals(0, loadTest.numberOfPreparedTransactions);
      Assert.assertEquals(0, loadTest.numberOfUpdates);
      Assert.assertEquals(0, loadTest.numberOfDeletes);

      journal.stop();

      if (loadTest.ex != null)
      {
         throw loadTest.ex;
      }
   }

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

   class Loader implements LoaderCallback
   {
      int numberOfPreparedTransactions = 0;

      int numberOfAdds = 0;

      int numberOfDeletes = 0;

      int numberOfUpdates = 0;

      long expectedRecords = 0;

      Exception ex = null;

      long lastID = 0;

      public Loader(final long expectedRecords)
      {
         this.expectedRecords = expectedRecords;
      }

      public void addPreparedTransaction(final PreparedTransactionInfo preparedTransaction)
      {
         numberOfPreparedTransactions++;

      }

      public void addRecord(final RecordInfo info)
      {
         if (info.id == lastID)
         {
            System.out.println("id = " + info.id + " last id = " + lastID);
         }

         ByteBuffer buffer = ByteBuffer.wrap(info.data);
         long recordValue = buffer.getLong();

         if (recordValue != info.id)
         {
            ex = new Exception("Content not as expected (" + recordValue + " != " + info.id + ")");

         }

         lastID = info.id;
         numberOfAdds++;

      }

      public void deleteRecord(final long id)
      {
         numberOfDeletes++;

      }

      public void updateRecord(final RecordInfo info)
      {
         numberOfUpdates++;

      }

      /* (non-Javadoc)
       * @see org.hornetq.core.journal.TransactionFailureCallback#failedTransaction(long, java.util.List, java.util.List)
       */
      public void failedTransaction(final long transactionID,
                                    final List<RecordInfo> records,
                                    final List<RecordInfo> recordsToDelete)
      {
      }

   }

   // Remote part of the test =================================================================

   public static void main(final String args[]) throws Exception
   {

      if (args.length != 5)
      {
         System.err.println("Use: java -cp <classpath> " + ValidateTransactionHealthTest.class.getCanonicalName() +
                            " aio|nio <journalDirectory> <NumberOfElements> <TransactionSize> <NumberOfThreads>");
         System.exit(-1);
      }
      System.out.println("Running");
      String journalType = args[0];
      String journalDir = args[1];
      long numberOfElements = Long.parseLong(args[2]);
      int transactionSize = Integer.parseInt(args[3]);
      int numberOfThreads = Integer.parseInt(args[4]);

      try
      {
         Journal journal = ValidateTransactionHealthTest.appendData(journalType,
                                                                    journalDir,
                                                                    numberOfElements,
                                                                    transactionSize,
                                                                    numberOfThreads);

         // We don't stop the journal on the case of an external process...
         // The test is making sure that committed data can be reloaded fine...
         // i.e. committs are sync on disk as stated on the transaction.
         // The journal shouldn't leave any state impeding reloading the server
      }
      catch (Exception e)
      {
         e.printStackTrace(System.out);
         System.exit(-1);
      }

      // Simulating a crash on the system right after the data was committed.
      Runtime.getRuntime().halt(ValidateTransactionHealthTest.OK);
   }

   public static JournalImpl appendData(final String journalType,
                                        final String journalDir,
                                        final long numberOfElements,
                                        final int transactionSize,
                                        final int numberOfThreads) throws Exception
   {
      final JournalImpl journal = ValidateTransactionHealthTest.createJournal(journalType, journalDir);

      journal.start();
      journal.load(new LoaderCallback()
      {

         public void addPreparedTransaction(final PreparedTransactionInfo preparedTransaction)
         {
         }

         public void addRecord(final RecordInfo info)
         {
         }

         public void deleteRecord(final long id)
         {
         }

         public void updateRecord(final RecordInfo info)
         {
         }

         public void failedTransaction(final long transactionID,
                                       final List<RecordInfo> records,
                                       final List<RecordInfo> recordsToDelete)
         {
         }
      });

      LocalThread threads[] = new LocalThread[numberOfThreads];
      final AtomicLong sequenceTransaction = new AtomicLong();

      for (int i = 0; i < numberOfThreads; i++)
      {
         threads[i] = new LocalThread(journal, numberOfElements, transactionSize, sequenceTransaction);
         threads[i].start();
      }

      Exception e = null;
      for (LocalThread t : threads)
      {
         t.join();

         if (t.e != null)
         {
            e = t.e;
         }
      }

      if (e != null)
      {
         throw e;
      }

      return journal;
   }

   public static JournalImpl createJournal(final String journalType, final String journalDir)
   {
      JournalImpl journal = new JournalImpl(10485760,
                                            2,
                                            0,
                                            0,
                                            ValidateTransactionHealthTest.getFactory(journalType, journalDir),
                                            "journaltst",
                                            "tst",
                                            500);
      return journal;
   }

   public static SequentialFileFactory getFactory(final String factoryType, final String directory)
   {
      if (factoryType.equals("aio"))
      {
         return new AIOSequentialFileFactory(directory,
                                             ConfigurationImpl.DEFAULT_JOURNAL_BUFFER_SIZE_AIO,
                                             ConfigurationImpl.DEFAULT_JOURNAL_BUFFER_TIMEOUT_AIO,
                                             false);
      }
      else if (factoryType.equals("nio2"))
      {
         return new NIOSequentialFileFactory(directory, true);
      }
      else
      {
         return new NIOSequentialFileFactory(directory, false);
      }
   }

   static class LocalThread extends Thread
   {
      final JournalImpl journal;

      final long numberOfElements;

      final int transactionSize;

      final AtomicLong nextID;

      Exception e;

      public LocalThread(final JournalImpl journal,
                         final long numberOfElements,
                         final int transactionSize,
                         final AtomicLong nextID)
      {
         super();
         this.journal = journal;
         this.numberOfElements = numberOfElements;
         this.transactionSize = transactionSize;
         this.nextID = nextID;
      }

      @Override
      public void run()
      {
         try
         {
            int transactionCounter = 0;

            long transactionId = nextID.incrementAndGet();

            for (long i = 0; i < numberOfElements; i++)
            {

               long id = nextID.incrementAndGet();

               ByteBuffer buffer = ByteBuffer.allocate(512 * 3);
               buffer.putLong(id);

               if (transactionSize != 0)
               {
                  journal.appendAddRecordTransactional(transactionId, id, (byte)99, buffer.array());

                  if (++transactionCounter == transactionSize)
                  {
                     System.out.println("Commit transaction " + transactionId);
                     journal.appendCommitRecord(transactionId, true);
                     transactionCounter = 0;
                     transactionId = nextID.incrementAndGet();
                  }
               }
               else
               {
                  journal.appendAddRecord(id, (byte)99, buffer.array(), false);
               }
            }

            if (transactionCounter != 0)
            {
               journal.appendCommitRecord(transactionId, true);
            }

            if (transactionSize == 0)
            {
               journal.debugWait();
            }
         }
         catch (Exception e)
         {
            this.e = e;
         }

      }
   }

}
TOP

Related Classes of org.hornetq.tests.integration.journal.ValidateTransactionHealthTest$LocalThread

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.