/*
* JBoss, Home of Professional Open Source Copyright 2005-2008, Red Hat
* Middleware LLC, and individual contributors by the @authors tag. See the
* copyright.txt in the distribution for a full listing of individual
* contributors.
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
* site: http://www.fsf.org.
*/
package org.jboss.messaging.tests.unit.core.journal.impl;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.jboss.messaging.core.journal.PreparedTransactionInfo;
import org.jboss.messaging.core.journal.RecordInfo;
import org.jboss.messaging.core.journal.impl.JournalImpl;
import org.jboss.messaging.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory;
import org.jboss.messaging.tests.unit.core.journal.impl.fakes.SimpleEncoding;
import org.jboss.messaging.tests.util.UnitTestCase;
public class JournalAsyncTest extends UnitTestCase
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
private FakeSequentialFileFactory factory;
JournalImpl journalImpl = null;
private ArrayList<RecordInfo> records = null;
private ArrayList<PreparedTransactionInfo> transactions = null;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
public void testAsynchronousCommit() throws Exception
{
final int JOURNAL_SIZE = 20000;
setupJournal(JOURNAL_SIZE, 100, 5);
factory.setHoldCallbacks(true);
final CountDownLatch latch = new CountDownLatch(1);
class LocalThread extends Thread
{
Exception e;
@Override
public void run()
{
try
{
for (int i = 0; i < 10; i++)
{
journalImpl.appendAddRecordTransactional(1l, i, (byte)1, new SimpleEncoding(1, (byte)0));
}
latch.countDown();
factory.setHoldCallbacks(false);
journalImpl.appendCommitRecord(1l);
}
catch (Exception e)
{
e.printStackTrace();
this.e = e;
}
}
};
LocalThread t = new LocalThread();
t.start();
assertTrue(latch.await(5, TimeUnit.SECONDS));
Thread.yield();
assertTrue(t.isAlive());
factory.flushAllCallbacks();
t.join();
if (t.e != null)
{
throw t.e;
}
}
public void testAsynchronousRollbackWithError() throws Exception
{
final int JOURNAL_SIZE = 20000;
setupJournal(JOURNAL_SIZE, 100, 5);
factory.setHoldCallbacks(true);
final CountDownLatch latch = new CountDownLatch(1);
class LocalThread extends Thread
{
Exception e;
@Override
public void run()
{
try
{
for (int i = 0; i < 10; i++)
{
journalImpl.appendAddRecordTransactional(1l, i, (byte)1, new SimpleEncoding(1, (byte)0));
}
latch.countDown();
journalImpl.appendRollbackRecord(1l);
}
catch (Exception e)
{
this.e = e;
}
}
};
LocalThread t = new LocalThread();
t.start();
latch.await();
Thread.yield();
assertTrue(t.isAlive());
factory.setCallbackAsError(0);
factory.flushCallback(0);
Thread.yield();
assertTrue(t.isAlive());
factory.flushAllCallbacks();
t.join();
assertNotNull(t.e);
}
public void testAsynchronousCommitWithError() throws Exception
{
final int JOURNAL_SIZE = 20000;
setupJournal(JOURNAL_SIZE, 100, 5);
factory.setHoldCallbacks(true);
final CountDownLatch latch = new CountDownLatch(1);
class LocalThread extends Thread
{
Exception e;
@Override
public void run()
{
try
{
for (int i = 0; i < 10; i++)
{
journalImpl.appendAddRecordTransactional(1l, i, (byte)1, new SimpleEncoding(1, (byte)0));
}
latch.countDown();
journalImpl.appendCommitRecord(1l);
}
catch (Exception e)
{
this.e = e;
}
}
};
LocalThread t = new LocalThread();
t.start();
latch.await();
Thread.yield();
assertTrue(t.isAlive());
factory.setCallbackAsError(0);
factory.flushCallback(0);
Thread.yield();
assertTrue(t.isAlive());
factory.flushAllCallbacks();
t.join();
assertNotNull(t.e);
try
{
journalImpl.appendRollbackRecord(1l);
fail("Supposed to throw an exception");
}
catch (Exception e)
{
}
}
// If a callback error already arrived, we should just throw the exception
// right away
public void testPreviousError() throws Exception
{
final int JOURNAL_SIZE = 20000;
setupJournal(JOURNAL_SIZE, 100, 5);
factory.setHoldCallbacks(true);
factory.setGenerateErrors(true);
journalImpl.appendAddRecordTransactional(1l, 1, (byte)1, new SimpleEncoding(1, (byte)0));
factory.flushAllCallbacks();
factory.setGenerateErrors(false);
factory.setHoldCallbacks(false);
try
{
journalImpl.appendAddRecordTransactional(1l, 2, (byte)1, new SimpleEncoding(1, (byte)0));
fail("Exception expected"); // An exception already happened in one
// of the elements on this transaction.
// We can't accept any more elements on
// the transaction
}
catch (Exception ignored)
{
}
}
public void testSyncNonTransaction() throws Exception
{
final int JOURNAL_SIZE = 20000;
setupJournal(JOURNAL_SIZE, 100, 5);
factory.setGenerateErrors(true);
try
{
journalImpl.appendAddRecord(1l, (byte)0, new SimpleEncoding(1, (byte)0));
fail("Exception expected");
}
catch (Exception ignored)
{
}
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
@Override
protected void setUp() throws Exception
{
super.setUp();
records = new ArrayList<RecordInfo>();
transactions = new ArrayList<PreparedTransactionInfo>();
factory = null;
journalImpl = null;
}
@Override
protected void tearDown() throws Exception
{
super.tearDown();
if (journalImpl != null)
{
try
{
journalImpl.stop();
}
catch (Throwable ignored)
{
}
}
}
// Private -------------------------------------------------------
private void setupJournal(final int journalSize, final int alignment, final int numberOfMinimalFiles) throws Exception
{
if (factory == null)
{
factory = new FakeSequentialFileFactory(alignment, true);
}
if (journalImpl != null)
{
journalImpl.stop();
}
journalImpl = new JournalImpl(journalSize, numberOfMinimalFiles, true, true, factory, "tt", "tt", 1000, 0);
journalImpl.start();
records.clear();
transactions.clear();
journalImpl.load(records, transactions);
}
// Inner classes -------------------------------------------------
}