[jboss-cvs] JBoss Messaging SVN: r4174 - in trunk: src/etc and 21 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Mon May 12 17:53:05 EDT 2008
Author: clebert.suconic at jboss.com
Date: 2008-05-12 17:53:04 -0400 (Mon, 12 May 2008)
New Revision: 4174
Added:
trunk/src/main/org/jboss/messaging/core/journal/EncodingSupport.java
trunk/src/main/org/jboss/messaging/util/VariableLatch.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeCallback.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakeBinding.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakePostOffice.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/impl/
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/impl/timing/
trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/impl/timing/StorageManagerTimingTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/util/VariableLatchTest.java
Modified:
trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h
trunk/src/etc/jbm-configuration.xml
trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java
trunk/src/main/org/jboss/messaging/core/config/impl/ConfigurationImpl.java
trunk/src/main/org/jboss/messaging/core/journal/Journal.java
trunk/src/main/org/jboss/messaging/core/journal/RecordInfo.java
trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java
trunk/src/main/org/jboss/messaging/core/journal/SequentialFileFactory.java
trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java
trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java
trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java
trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFile.java
trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFileFactory.java
trunk/src/main/org/jboss/messaging/core/message/Message.java
trunk/src/main/org/jboss/messaging/core/message/impl/MessageImpl.java
trunk/src/main/org/jboss/messaging/core/persistence/impl/journal/JournalStorageManager.java
trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ProducerSendMessage.java
trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ReceiveMessage.java
trunk/src/main/org/jboss/messaging/util/ByteBufferWrapper.java
trunk/src/main/org/jboss/messaging/util/TypedProperties.java
trunk/tests/jms-tests/src/
trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/MultiThreadWriteNativeTest.java
trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/SingleThreadWriteNativeTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/AIOSequentialFileFactoryTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestBase.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestUnit.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/JournalImplTestUnit.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplAIOTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/message/impl/MessageTest.java
Log:
JBMESSAGING-1283 - More improvements on AIO
Modified: trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h
===================================================================
--- trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h 2008-05-12 21:53:04 UTC (rev 4174)
@@ -9,6 +9,7 @@
#endif
/* Inaccessible static: log */
/* Inaccessible static: loaded */
+/* Inaccessible static: totalMaxIO */
/*
* Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
* Method: init
Modified: trunk/src/etc/jbm-configuration.xml
===================================================================
--- trunk/src/etc/jbm-configuration.xml 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/etc/jbm-configuration.xml 2008-05-12 21:53:04 UTC (rev 4174)
@@ -22,7 +22,7 @@
<remoting-host>localhost</remoting-host>
<!-- timeout in seconds -->
- <remoting-timeout>5</remoting-timeout>
+ <remoting-timeout>5000</remoting-timeout>
<!-- true to disable invm communication when the client and the server are in the same JVM. -->
<!-- it is not allowed to disable invm communication when the remoting-transport is set to INVM -->
@@ -67,9 +67,9 @@
<journal-sync>true</journal-sync>
- <journal-file-size>10485760</journal-file-size>
+ <journal-file-size>104857600</journal-file-size>
- <journal-min-files>10</journal-min-files>
+ <journal-min-files>2</journal-min-files>
<journal-task-period>5000</journal-task-period>
Modified: trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -9,6 +9,7 @@
import java.nio.ByteBuffer;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -17,6 +18,7 @@
import org.jboss.messaging.core.asyncio.AsynchronousFile;
import org.jboss.messaging.core.logging.Logger;
+
/**
*
* @author clebert.suconic at jboss.com
@@ -32,6 +34,19 @@
private static boolean loaded = false;
private int maxIO;
+ private static AtomicInteger totalMaxIO = new AtomicInteger(0);
+
+ static void addMax(int io)
+ {
+ totalMaxIO.addAndGet(io);
+ }
+
+ /** For test purposes */
+ public static int getTotalMaxIO()
+ {
+ return totalMaxIO.get();
+ }
+
Semaphore writeSemaphore;
ReadWriteLock lock = new ReentrantReadWriteLock();
@@ -108,6 +123,7 @@
opened = true;
this.fileName=fileName;
handler = init (fileName, maxIO, log);
+ addMax(maxIO);
startPoller();
}
finally
@@ -148,6 +164,7 @@
{
pollerSemaphore.acquire();
closeInternal(handler);
+ addMax(maxIO * -1);
opened = false;
handler = 0;
}
Modified: trunk/src/main/org/jboss/messaging/core/config/impl/ConfigurationImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/config/impl/ConfigurationImpl.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/config/impl/ConfigurationImpl.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -350,6 +350,11 @@
{
return journalType;
}
+
+ public void setJournalType(JournalType type)
+ {
+ this.journalType = type;
+ }
public boolean isJournalSync()
{
Added: trunk/src/main/org/jboss/messaging/core/journal/EncodingSupport.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/EncodingSupport.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/core/journal/EncodingSupport.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,12 @@
+package org.jboss.messaging.core.journal;
+
+import org.jboss.messaging.util.MessagingBuffer;
+
+/**
+ * This class provides encoding support for the Journal.
+ * */
+public interface EncodingSupport
+{
+ int encodeSize();
+ void encode(MessagingBuffer buffer);
+}
Modified: trunk/src/main/org/jboss/messaging/core/journal/Journal.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/Journal.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/Journal.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -36,22 +36,23 @@
{
// Non transactional operations
- // TODO: Implement callbacks
- void appendAddRecord(long id, byte[] record, IOCallback callback) throws Exception;
+ void appendAddRecord(long id, byte recordType, EncodingSupport record) throws Exception;
+
+ void appendAddRecord(long id, byte recordType, byte[] record) throws Exception;
- void appendAddRecord(long id, byte[] record) throws Exception;
+ void appendUpdateRecord(long id, byte recordType, byte[] record) throws Exception;
- void appendUpdateRecord(long id, byte[] record) throws Exception;
-
void appendDeleteRecord(long id) throws Exception;
// Transactional operations
long getTransactionID();
- void appendAddRecordTransactional(long txID, long id, byte[] record) throws Exception;
+ void appendAddRecordTransactional(long txID, byte recordType, long id, EncodingSupport record) throws Exception;
+
+ void appendAddRecordTransactional(long txID, byte recordType, long id, byte[] record) throws Exception;
- void appendUpdateRecordTransactional(long txID, long id, byte[] record) throws Exception;
+ void appendUpdateRecordTransactional(long txID, byte recordType, long id, byte[] record) throws Exception;
void appendDeleteRecordTransactional(long txID, long id) throws Exception;
Modified: trunk/src/main/org/jboss/messaging/core/journal/RecordInfo.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/RecordInfo.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/RecordInfo.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -10,10 +10,12 @@
*/
public class RecordInfo
{
- public RecordInfo(final long id, final byte[] data, final boolean isUpdate)
+ public RecordInfo(final long id, byte userRecordType, final byte[] data, final boolean isUpdate)
{
this.id = id;
+ this.userRecordType = userRecordType;
+
this.data = data;
this.isUpdate = isUpdate;
@@ -21,10 +23,17 @@
public final long id;
+ public final byte userRecordType;
+
public final byte[] data;
public boolean isUpdate;
+ public byte getUserRecordType()
+ {
+ return userRecordType;
+ }
+
public int hashCode()
{
return (int)((id >>> 32) ^ id);
Modified: trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -1,24 +1,24 @@
/*
- * JBoss, Home of Professional Open Source
- * Copyright 2005, JBoss Inc., and individual contributors as indicated
- * 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.
- */
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * 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.core.journal;
import java.nio.ByteBuffer;
@@ -28,38 +28,36 @@
* A SequentialFile
*
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>Journal
- *
+ *
*/
public interface SequentialFile
{
- /*
- * Creates the file if it doesn't already exist, then opens it
- */
- void open() throws Exception;
-
- int getAlignment() throws Exception;
-
- int calculateBlockStart(int position) throws Exception;
-
- String getFileName();
-
- void fill(int position, int size, byte fillCharacter) throws Exception;
-
- void delete() throws Exception;
-
- int write(ByteBuffer bytes, boolean sync, IOCallback callback) throws Exception;
-
- int write(ByteBuffer bytes, boolean sync) throws Exception;
-
- int read(ByteBuffer bytes, IOCallback callback) throws Exception;
-
- int read(ByteBuffer bytes) throws Exception;
-
- void position(int pos) throws Exception;
-
- void close() throws Exception;
-
- ByteBuffer newBuffer(int size);
-
- ByteBuffer wrapBuffer(byte bytes[]);
+ /*
+ * Creates the file if it doesn't already exist, then opens it
+ */
+ void open() throws Exception;
+
+ int getAlignment() throws Exception;
+
+ int calculateBlockStart(int position) throws Exception;
+
+ String getFileName();
+
+ void fill(int position, int size, byte fillCharacter) throws Exception;
+
+ void delete() throws Exception;
+
+ int write(ByteBuffer bytes, boolean sync, IOCallback callback)
+ throws Exception;
+
+ int write(ByteBuffer bytes, boolean sync) throws Exception;
+
+ int read(ByteBuffer bytes, IOCallback callback) throws Exception;
+
+ int read(ByteBuffer bytes) throws Exception;
+
+ void position(int pos) throws Exception;
+
+ void close() throws Exception;
+
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/SequentialFileFactory.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/SequentialFileFactory.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/SequentialFileFactory.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -21,6 +21,7 @@
*/
package org.jboss.messaging.core.journal;
+import java.nio.ByteBuffer;
import java.util.List;
/**
@@ -32,7 +33,15 @@
*/
public interface SequentialFileFactory
{
- SequentialFile createSequentialFile(String fileName, boolean sync) throws Exception;
+ SequentialFile createSequentialFile(String fileName, boolean sync, int maxIO) throws Exception;
List<String> listFiles(String extension) throws Exception;
+
+ boolean supportsCallbacks();
+
+ ByteBuffer newBuffer(int size);
+
+ // Avoid using this method in production as it creates an unecessary copy
+ ByteBuffer wrapBuffer(byte[] bytes);
+
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -10,28 +10,40 @@
import java.io.File;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.TimeUnit;
import org.jboss.messaging.core.asyncio.AsynchronousFile;
import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
import org.jboss.messaging.core.exception.MessagingException;
import org.jboss.messaging.core.journal.IOCallback;
import org.jboss.messaging.core.journal.SequentialFile;
+import org.jboss.messaging.core.logging.Logger;
public class AIOSequentialFile implements SequentialFile
{
-
- String journalDir;
+ private static final Logger log = Logger.getLogger(AIOSequentialFile.class);
+
+ String journalDir;
String fileName;
+ boolean opened = false;
+ int maxIO;
AsynchronousFile aioFile;
AtomicLong position = new AtomicLong(0);
+
+ // A context switch on AIO would make it to synchronize the disk before switching to the new thread, what would cuase
+ // serious performance problems. Because of that we make all the writes on AIO using a single thread.
+ ExecutorService executor;
- public AIOSequentialFile(String journalDir, String fileName) throws Exception
+ public AIOSequentialFile(String journalDir, String fileName, int maxIO) throws Exception
{
this.journalDir = journalDir;
this.fileName = fileName;
+ this.maxIO = maxIO;
}
public int getAlignment() throws Exception
@@ -51,9 +63,12 @@
- public void close() throws Exception
+ public synchronized void close() throws Exception
{
checkOpened();
+ opened = false;
+ executor.shutdown();
+ executor.awaitTermination(120, TimeUnit.SECONDS);
aioFile.close();
aioFile = null;
@@ -107,7 +122,6 @@
{
position = ((position / aioFile.getBlockSize()) + 1) * aioFile.getBlockSize();
}
- //System.out.println("filling " + blocks + " blocks with blockSize=" + blockSize + " on file=" + this.getFileName());
aioFile.fill((long)position, blocks, blockSize, (byte)fillCharacter);
}
@@ -117,10 +131,12 @@
return fileName;
}
- public void open() throws Exception
+ public synchronized void open() throws Exception
{
+ opened = true;
+ executor = Executors.newSingleThreadExecutor();
aioFile = new AsynchronousFileImpl();
- aioFile.open(journalDir + "/" + fileName, 1000);
+ aioFile.open(journalDir + "/" + fileName, maxIO);
position.set(0);
}
@@ -157,38 +173,69 @@
return bytesRead;
}
- public int write(ByteBuffer bytes, boolean sync, IOCallback callback)
+
+ public int write(final ByteBuffer bytes, boolean sync, final IOCallback callback)
throws Exception
{
- int bytesToWrite = bytes.limit();
- long positionToWrite = position.getAndAdd(bytesToWrite);
+ final int bytesToWrite = bytes.limit();
+ final long positionToWrite = position.getAndAdd(bytesToWrite);
- aioFile.write(positionToWrite, bytesToWrite, bytes, callback);
+ execWrite(bytes, callback, bytesToWrite, positionToWrite);
+
return bytesToWrite;
}
+
+ private void execWrite(final ByteBuffer bytes, final IOCallback callback,
+ final int bytesToWrite, final long positionToWrite)
+ {
+ executor.execute(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ aioFile.write(positionToWrite, bytesToWrite, bytes, callback);
+ }
+ catch (Exception e)
+ {
+ log.warn (e.getMessage(), e);
+ if (callback != null)
+ {
+ callback.onError(-1, e.getMessage());
+ }
+ }
+ }
+ });
+
+ }
public int write(ByteBuffer bytes, boolean sync) throws Exception
{
- WaitCompletion waitCompletion = new WaitCompletion();
- int bytesWritten = write (bytes, sync, waitCompletion);
-
- waitCompletion.waitLatch();
-
- if (waitCompletion.errorMessage != null)
- {
- throw new MessagingException(waitCompletion.errorCode, waitCompletion.errorMessage);
- }
-
- return bytesWritten;
+ return write (bytes, sync, DummyCallback.instance);
}
private void checkOpened() throws Exception
{
- if (aioFile == null)
+ if (aioFile == null || !opened)
{
throw new IllegalStateException ("File not opened");
}
}
+
+ static class DummyCallback implements IOCallback
+ {
+
+ static DummyCallback instance = new DummyCallback();
+
+ public void done()
+ {
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ }
+
+ }
class WaitCompletion implements IOCallback
{
@@ -205,7 +252,6 @@
public void onError(int errorCode, String errorMessage)
{
- System.out.println("OK Error!");
this.errorCode = errorCode;
this.errorMessage = errorMessage;
@@ -220,20 +266,4 @@
}
- public ByteBuffer newBuffer(int size)
- {
- if (size % aioFile.getBlockSize() != 0)
- {
- size = ((size / aioFile.getBlockSize()) + 1) * aioFile.getBlockSize();
- }
- return ByteBuffer.allocateDirect(size);
- }
-
- public ByteBuffer wrapBuffer(byte[] bytes)
- {
- ByteBuffer newbuffer = newBuffer(bytes.length);
- newbuffer.put(bytes);
- return newbuffer;
- };
-
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -7,6 +7,8 @@
package org.jboss.messaging.core.journal.impl;
+import java.nio.ByteBuffer;
+
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
@@ -18,14 +20,36 @@
super(journalDir);
}
- public SequentialFile createSequentialFile(String fileName, boolean sync) throws Exception
+ public SequentialFile createSequentialFile(String fileName, boolean sync, int maxIO) throws Exception
{
- return new AIOSequentialFile(journalDir, fileName);
+ return new AIOSequentialFile(journalDir, fileName, maxIO);
}
+ public boolean supportsCallbacks()
+ {
+ return true;
+ }
+
public static boolean isSupported()
{
return AsynchronousFileImpl.isLoaded();
}
+ public ByteBuffer newBuffer(int size)
+ {
+ if (size % 512 != 0)
+ {
+ size = (size / 512 + 1) * 512;
+ }
+ return ByteBuffer.allocateDirect(size);
+ }
+
+ // For tests only
+ public ByteBuffer wrapBuffer(byte[] bytes)
+ {
+ ByteBuffer newbuffer = newBuffer(bytes.length);
+ newbuffer.put(bytes);
+ return newbuffer;
+ };
+
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -30,15 +30,20 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
+import org.jboss.messaging.core.journal.EncodingSupport;
import org.jboss.messaging.core.journal.IOCallback;
import org.jboss.messaging.core.journal.PreparedTransactionInfo;
import org.jboss.messaging.core.journal.RecordInfo;
@@ -46,7 +51,9 @@
import org.jboss.messaging.core.journal.SequentialFileFactory;
import org.jboss.messaging.core.journal.TestableJournal;
import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.util.ByteBufferWrapper;
import org.jboss.messaging.util.Pair;
+import org.jboss.messaging.util.VariableLatch;
/**
*
@@ -83,11 +90,11 @@
public static final int SIZE_HEADER = 8;
- public static final int SIZE_ADD_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_INT + SIZE_BYTE;
+ public static final int SIZE_ADD_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_BYTE + SIZE_INT + SIZE_BYTE; // + record.length
public static final byte ADD_RECORD = 11;
- public static final byte SIZE_UPDATE_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_INT + SIZE_BYTE;
+ public static final byte SIZE_UPDATE_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_BYTE + SIZE_INT + SIZE_BYTE; // + record.length;
public static final byte UPDATE_RECORD = 12;
@@ -97,11 +104,10 @@
public static final byte ADD_RECORD_TX = 14;
- public static final int SIZE_ADD_RECORD_TX = SIZE_BYTE + SIZE_LONG + SIZE_LONG + SIZE_INT + SIZE_BYTE; // Add the size of Bytes on this
+ public static final int SIZE_ADD_RECORD_TX = SIZE_BYTE + SIZE_LONG + SIZE_BYTE + SIZE_LONG + SIZE_INT + SIZE_BYTE; // Add the size of Bytes on this
+ public static final int SIZE_UPDATE_RECORD_TX = SIZE_BYTE + SIZE_LONG + SIZE_BYTE + SIZE_LONG + SIZE_INT + SIZE_BYTE; // Add the size of Bytes on this
- public static final int SIZE_UPDATE_RECORD_TX = SIZE_BYTE + SIZE_LONG + SIZE_LONG + SIZE_INT + SIZE_BYTE; // Add the size of Bytes on this
-
public static final byte UPDATE_RECORD_TX = 15;
public static final int SIZE_DELETE_RECORD_TX = SIZE_BYTE + SIZE_LONG + SIZE_LONG + SIZE_BYTE;
@@ -126,6 +132,9 @@
public static final byte FILL_CHARACTER = 74; // Letter 'J'
+ // used for Asynchronous IO only (ignored on NIO).
+ private final int maxAIO;
+
private final int fileSize;
private final int minFiles;
@@ -148,8 +157,13 @@
private Map<Long, PosFiles> posFilesMap = new ConcurrentHashMap<Long, PosFiles>();
private Map<Long, TransactionNegPos> transactionInfos = new ConcurrentHashMap<Long, TransactionNegPos>();
+
+ private final ConcurrentMap<Long, TransactionCallback> transactionCallbacks = new ConcurrentHashMap<Long, TransactionCallback>();
+ private boolean shouldUseCallback = false;
+
+
/*
* We use a semaphore rather than synchronized since it performs better when contended
*/
@@ -173,7 +187,7 @@
public JournalImpl(final int fileSize, final int minFiles,
final boolean sync, final SequentialFileFactory fileFactory, final long taskPeriod,
- final String filePrefix, final String fileExtension)
+ final String filePrefix, final String fileExtension, final int maxAIO)
{
if (fileSize < MIN_FILE_SIZE)
{
@@ -199,6 +213,10 @@
{
throw new NullPointerException("fileExtension is null");
}
+ if (maxAIO <= 0)
+ {
+ throw new IllegalStateException("maxAIO should aways be a positive number");
+ }
this.fileSize = fileSize;
@@ -213,68 +231,93 @@
this.filePrefix = filePrefix;
this.fileExtension = fileExtension;
+
+ this.maxAIO = maxAIO;
+
+ shouldUseCallback = fileFactory.supportsCallbacks() && sync;
}
// Journal implementation ----------------------------------------------------------------
-
- /*public ByteBuffer allocateBuffer(final int size) throws Exception
+
+ public void appendAddRecord(long id, byte recordType, EncodingSupport record) throws Exception
{
- return ByteBuffer.allocateDirect(size);
- }*/
+ if (state != STATE_LOADED)
+ {
+ throw new IllegalStateException("Journal must be loaded first");
+ }
+
+ int recordLength = record.encodeSize();
+
+ int size = SIZE_ADD_RECORD + recordLength;
+
+ ByteBufferWrapper bb = new ByteBufferWrapper(fileFactory.newBuffer(size));
+
+ bb.putByte(ADD_RECORD);
+ bb.putLong(id);
+ bb.putByte(recordType);
+ bb.putInt(recordLength);
+ record.encode(bb);
+ bb.putByte(DONE);
+ bb.rewind();
+
+ JournalFile usedFile;
+
+ if (shouldUseCallback)
+ {
+ SimpleCallback callback = new SimpleCallback();
+ usedFile = appendRecord(bb.getBuffer(), true, callback);
+ callback.waitCompletion();
+ }
+ else
+ {
+ usedFile = appendRecord(bb.getBuffer(), true);
+ }
+
+ posFilesMap.put(id, new PosFiles(usedFile));
+ }
- public void appendAddRecord(long id, byte[] record, IOCallback callback) throws Exception
+ public void appendAddRecord(long id, byte recordType, byte[] record) throws Exception
{
if (state != STATE_LOADED)
{
throw new IllegalStateException("Journal must be loaded first");
}
- int size = SIZE_BYTE + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE;
+ int size = SIZE_ADD_RECORD + record.length;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(ADD_RECORD);
- bb.putLong(id);
+ bb.putLong(id);
+ bb.put(recordType);
bb.putInt(record.length);
bb.put(record);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, true, callback);
+ JournalFile usedFile;
+ if (shouldUseCallback)
+ {
+
+ SimpleCallback callback = new SimpleCallback();
+ usedFile = appendRecord(bb, true, callback);
+ callback.waitCompletion();
+ }
+ else
+ {
+ usedFile = appendRecord(bb, true);
+ }
- posFilesMap.put(id, new PosFiles(currentFile));
+ posFilesMap.put(id, new PosFiles(usedFile));
}
- public void appendAddRecord(final long id, final byte[] record) throws Exception
+ public void appendUpdateRecord(final long id, final byte recordType, final byte[] record) throws Exception
{
if (state != STATE_LOADED)
{
throw new IllegalStateException("Journal must be loaded first");
}
- int size = SIZE_BYTE + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE;
-
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
-
- bb.put(ADD_RECORD);
- bb.putLong(id);
- bb.putInt(record.length);
- bb.put(record);
- bb.put(DONE);
- bb.rewind();
-
- appendRecord(bb, true);
-
- posFilesMap.put(id, new PosFiles(currentFile));
- }
-
- public void appendUpdateRecord(final long id, final byte[] record) throws Exception
- {
- if (state != STATE_LOADED)
- {
- throw new IllegalStateException("Journal must be loaded first");
- }
-
PosFiles posFiles = posFilesMap.get(id);
if (posFiles == null)
@@ -284,18 +327,30 @@
int size = SIZE_UPDATE_RECORD + record.length;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(UPDATE_RECORD);
bb.putLong(id);
+ bb.put(recordType);
bb.putInt(record.length);
bb.put(record);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, true);
+ JournalFile usedFile;
+ if (shouldUseCallback)
+ {
+ SimpleCallback callback = new SimpleCallback();
+ usedFile = appendRecord(bb, true, callback);
+ callback.waitCompletion();
+ }
+ else
+ {
+ usedFile = appendRecord(bb, true);
+ }
+
- posFiles.addUpdateFile(currentFile);
+ posFiles.addUpdateFile(usedFile);
}
public void appendDeleteRecord(long id) throws Exception
@@ -316,14 +371,24 @@
int size = SIZE_DELETE_RECORD;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(DELETE_RECORD);
bb.putLong(id);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, true);
+ if (shouldUseCallback)
+ {
+ SimpleCallback callback = new SimpleCallback();
+ appendRecord(bb, true, callback);
+ callback.waitCompletion();
+ }
+ else
+ {
+ appendRecord(bb, true);
+ }
+
}
public long getTransactionID()
@@ -331,59 +396,109 @@
return transactionIDSequence.getAndIncrement();
}
- public void appendAddRecordTransactional(final long txID, final long id,
- final byte[] record) throws Exception
- {
- if (state != STATE_LOADED)
- {
- throw new IllegalStateException("Journal must be loaded first");
- }
-
- int size = SIZE_ADD_RECORD_TX + record.length;
-
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
-
- bb.put(ADD_RECORD_TX);
- bb.putLong(txID);
- bb.putLong(id);
- bb.putInt(record.length);
- bb.put(record);
- bb.put(DONE);
- bb.rewind();
-
- appendRecord(bb, false);
-
- TransactionNegPos tx = getTransactionInfo(txID);
-
- tx.addPos(currentFile, id);
- }
+ public void appendAddRecordTransactional(final long txID, final byte recordType, final long id,
+ final EncodingSupport record) throws Exception
+ {
+ if (state != STATE_LOADED)
+ {
+ throw new IllegalStateException("Journal must be loaded first");
+ }
+
+
+ int recordLength = record.encodeSize();
+
+ int size = SIZE_ADD_RECORD_TX + recordLength;
+
+ ByteBufferWrapper bb = new ByteBufferWrapper(fileFactory.newBuffer(size));
+
+ bb.putByte(ADD_RECORD_TX);
+ bb.putLong(txID);
+ bb.putByte(recordType);
+ bb.putLong(id);
+ bb.putInt(recordLength);
+ record.encode(bb);
+ bb.putByte(DONE);
+ bb.rewind();
+
+ JournalFile usedFile;
+
+ if (shouldUseCallback)
+ {
+ TransactionCallback callback = getTransactionCallback(txID);
+ callback.countUp();
+ usedFile = appendRecord(bb.getBuffer(), false, callback);
+ }
+ else
+ {
+ usedFile = appendRecord(bb.getBuffer(), false);
+ }
+
+ TransactionNegPos tx = getTransactionInfo(txID);
+
+ tx.addPos(usedFile, id);
+ }
+
+ public void appendAddRecordTransactional(final long txID, final byte recordType, final long id,
+ final byte[] record) throws Exception
+ {
+ if (state != STATE_LOADED)
+ {
+ throw new IllegalStateException("Journal must be loaded first");
+ }
+
+ TransactionCallback callback = getTransactionCallback(txID);
+ callback.countUp();
+
+ int size = SIZE_ADD_RECORD_TX + record.length;
+
+ ByteBuffer bb = fileFactory.newBuffer(size);
+
+ bb.put(ADD_RECORD_TX);
+ bb.putLong(txID);
+ bb.put(recordType);
+ bb.putLong(id);
+ bb.putInt(record.length);
+ bb.put(record);
+ bb.put(DONE);
+ bb.rewind();
+
+ JournalFile usedFile = appendRecord(bb, false, callback);
+
+ TransactionNegPos tx = getTransactionInfo(txID);
+
+ tx.addPos(usedFile, id);
+ }
- public void appendUpdateRecordTransactional(final long txID, final long id,
+ public void appendUpdateRecordTransactional(final long txID, byte recordType, final long id,
final byte[] record) throws Exception
- {
+ {
if (state != STATE_LOADED)
{
throw new IllegalStateException("Journal must be loaded first");
}
+ TransactionCallback callback = getTransactionCallback(txID);
+ callback.countUp();
+
int size = SIZE_UPDATE_RECORD_TX + record.length;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(UPDATE_RECORD_TX);
- bb.putLong(txID);
+ bb.putLong(txID);
+ bb.put(recordType);
bb.putLong(id);
bb.putInt(record.length);
bb.put(record);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, false);
+ JournalFile usedFile = appendRecord(bb, false, callback);
TransactionNegPos tx = getTransactionInfo(txID);
- tx.addPos(currentFile, id);
- }
+ tx.addPos(usedFile, id);
+ }
public void appendDeleteRecordTransactional(final long txID, final long id) throws Exception
{
@@ -392,9 +507,12 @@
throw new IllegalStateException("Journal must be loaded first");
}
+ TransactionCallback callback = getTransactionCallback(txID);
+ callback.countUp();
+
int size = SIZE_DELETE_RECORD_TX;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(DELETE_RECORD_TX);
bb.putLong(txID);
@@ -402,11 +520,11 @@
bb.put(DONE);
bb.rewind();
- appendRecord(bb, false);
+ JournalFile usedFile = appendRecord(bb, false, callback);
TransactionNegPos tx = getTransactionInfo(txID);
- tx.addNeg(currentFile, id);
+ tx.addNeg(usedFile, id);
}
public void appendPrepareRecord(final long txID) throws Exception
@@ -416,6 +534,9 @@
throw new IllegalStateException("Journal must be loaded first");
}
+ TransactionCallback callback = getTransactionCallback(txID);
+ callback.countUp();
+
TransactionNegPos tx = transactionInfos.get(txID);
if (tx == null)
@@ -425,16 +546,16 @@
int size = SIZE_PREPARE_RECORD;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(PREPARE_RECORD);
bb.putLong(txID);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, true);
+ JournalFile usedFile = appendRecord(bb, true, callback);
- tx.prepare(currentFile);
+ tx.prepare(usedFile);
}
public void appendCommitRecord(final long txID) throws Exception
@@ -444,6 +565,9 @@
throw new IllegalStateException("Journal must be loaded first");
}
+ TransactionCallback callback = getTransactionCallback(txID);
+ callback.countUp();
+
TransactionNegPos tx = transactionInfos.remove(txID);
if (tx == null)
@@ -453,16 +577,20 @@
int size = SIZE_COMMIT_RECORD;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(COMMIT_RECORD);
bb.putLong(txID);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, true);
+ JournalFile usedFile = appendRecord(bb, true, callback);
- tx.commit(currentFile);
+ callback.waitCompletion();
+ transactionCallbacks.remove(txID);
+
+ tx.commit(usedFile);
+
}
public void appendRollbackRecord(final long txID) throws Exception
@@ -481,549 +609,563 @@
int size = SIZE_ROLLBACK_RECORD;
- ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ ByteBuffer bb = fileFactory.newBuffer(size);
bb.put(ROLLBACK_RECORD);
bb.putLong(txID);
bb.put(DONE);
bb.rewind();
- appendRecord(bb, true);
+ SimpleCallback callback = new SimpleCallback();
- tx.rollback(currentFile);
+ JournalFile usedFile = appendRecord(bb, true, callback);
+
+ callback.waitCompletion();
+
+ tx.rollback(usedFile);
}
- public synchronized long load(final List<RecordInfo> committedRecords,
- final List<PreparedTransactionInfo> preparedTransactions) throws Exception
- {
- if (state != STATE_STARTED)
- {
- throw new IllegalStateException("Journal must be in started state");
- }
-
- Set<Long> recordsToDelete = new HashSet<Long>();
-
- Map<Long, TransactionHolder> transactions = new LinkedHashMap<Long, TransactionHolder>();
-
- List<RecordInfo> records = new ArrayList<RecordInfo>();
-
- List<String> fileNames = fileFactory.listFiles(fileExtension);
-
- List<JournalFile> orderedFiles = new ArrayList<JournalFile>(fileNames.size());
-
- for (String fileName: fileNames)
- {
- SequentialFile file = fileFactory.createSequentialFile(fileName, sync);
-
- file.open();
-
- ByteBuffer bb = file.newBuffer(SIZE_LONG);
-
- file.read(bb);
-
- long orderingID = bb.getLong();
-
- orderedFiles.add(new JournalFileImpl(file, orderingID));
-
- file.close();
- }
-
- //Now order them by ordering id - we can't use the file name for ordering since we can re-use dataFiles
-
- class JournalFileComparator implements Comparator<JournalFile>
- {
- public int compare(JournalFile f1, JournalFile f2)
- {
- long id1 = f1.getOrderingID();
- long id2 = f2.getOrderingID();
-
- return (id1 < id2 ? -1 : (id1 == id2 ? 0 : 1));
- }
- }
-
- Collections.sort(orderedFiles, new JournalFileComparator());
-
- int lastDataPos = -1;
-
- long maxTransactionID = -1;
-
- long maxMessageID = -1;
-
- for (JournalFile file: orderedFiles)
- {
- file.getFile().open();
-
- ByteBuffer bb = file.getFile().newBuffer(fileSize);
-
- int bytesRead = file.getFile().read(bb);
-
- if (bytesRead != fileSize)
- {
- //deal with this better
-
- throw new IllegalStateException("File is wrong size " + bytesRead +
- " expected " + fileSize + " : " + file.getFile().getFileName());
- }
-
- //First long is the ordering timestamp, we just jump its position
- bb.position(file.getFile().calculateBlockStart(SIZE_LONG));
-
- boolean hasData = false;
-
- while (bb.hasRemaining())
- {
- int pos = bb.position();
-
- byte recordType = bb.get();
-
- switch(recordType)
- {
- case ADD_RECORD:
- {
- long id = bb.getLong();
-
- maxMessageID = Math.max(maxMessageID, id);
-
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- records.add(new RecordInfo(id, record, false));
- hasData = true;
-
- posFilesMap.put(id, new PosFiles(file));
- }
-
- break;
- }
- case UPDATE_RECORD:
- {
- long id = bb.getLong();
+ public synchronized long load(final List<RecordInfo> committedRecords,
+ final List<PreparedTransactionInfo> preparedTransactions) throws Exception
+ {
+ if (state != STATE_STARTED)
+ {
+ throw new IllegalStateException("Journal must be in started state");
+ }
+
+ Set<Long> recordsToDelete = new HashSet<Long>();
+
+ Map<Long, TransactionHolder> transactions = new LinkedHashMap<Long, TransactionHolder>();
+
+ List<RecordInfo> records = new ArrayList<RecordInfo>();
+
+ List<String> fileNames = fileFactory.listFiles(fileExtension);
+
+ List<JournalFile> orderedFiles = new ArrayList<JournalFile>(fileNames.size());
+
+ for (String fileName: fileNames)
+ {
+ SequentialFile file = fileFactory.createSequentialFile(fileName, sync, maxAIO);
+
+ file.open();
+
+ ByteBuffer bb = fileFactory.newBuffer(SIZE_LONG);
+
+ file.read(bb);
+
+ long orderingID = bb.getLong();
+
+ orderedFiles.add(new JournalFileImpl(file, orderingID));
+
+ file.close();
+ }
+
+ //Now order them by ordering id - we can't use the file name for ordering since we can re-use dataFiles
+
+ class JournalFileComparator implements Comparator<JournalFile>
+ {
+ public int compare(JournalFile f1, JournalFile f2)
+ {
+ long id1 = f1.getOrderingID();
+ long id2 = f2.getOrderingID();
+
+ return (id1 < id2 ? -1 : (id1 == id2 ? 0 : 1));
+ }
+ }
+
+ Collections.sort(orderedFiles, new JournalFileComparator());
+
+ int lastDataPos = -1;
+
+ long maxTransactionID = -1;
+
+ long maxMessageID = -1;
+
+ for (JournalFile file: orderedFiles)
+ {
+ file.getFile().open();
+
+ ByteBuffer bb = fileFactory.newBuffer(fileSize);
+
+ int bytesRead = file.getFile().read(bb);
+
+ if (bytesRead != fileSize)
+ {
+ //deal with this better
+
+ throw new IllegalStateException("File is wrong size " + bytesRead +
+ " expected " + fileSize + " : " + file.getFile().getFileName());
+ }
+
+ //First long is the ordering timestamp, we just jump its position
+ bb.position(file.getFile().calculateBlockStart(SIZE_LONG));
+
+ boolean hasData = false;
+
+ while (bb.hasRemaining())
+ {
+ int pos = bb.position();
+
+ byte recordType = bb.get();
+
+ switch(recordType)
+ {
+ case ADD_RECORD:
+ {
+ long id = bb.getLong();
+
+ maxMessageID = Math.max(maxMessageID, id);
+
+ byte userRecordType = bb.get();
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ records.add(new RecordInfo(id, userRecordType, record, false));
+ hasData = true;
+
+ posFilesMap.put(id, new PosFiles(file));
+ }
+
+ break;
+ }
+ case UPDATE_RECORD:
+ {
+ long id = bb.getLong();
- maxMessageID = Math.max(maxMessageID, id);
-
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- records.add(new RecordInfo(id, record, true));
- hasData = true;
- file.incPosCount();
-
- PosFiles posFiles = posFilesMap.get(id);
-
- if (posFiles != null)
- {
- //It's legal for this to be null. The file(s) with the may have been deleted
- //just leaving some updates in this file
-
- posFiles.addUpdateFile(file);
- }
- }
-
- break;
- }
- case DELETE_RECORD:
- {
- long id = bb.getLong();
-
- maxMessageID = Math.max(maxMessageID, id);
-
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- recordsToDelete.add(id);
- hasData = true;
-
- PosFiles posFiles = posFilesMap.remove(id);
-
- if (posFiles != null)
- {
- posFiles.addDelete(file);
- }
- }
-
- break;
- }
- case ADD_RECORD_TX:
- {
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- long id = bb.getLong();
- maxMessageID = Math.max(maxMessageID, id);
-
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- TransactionHolder tx = transactions.get(txID);
-
- if (tx == null)
- {
- tx = new TransactionHolder(txID);
- transactions.put(txID, tx);
- }
-
- tx.recordInfos.add(new RecordInfo(id, record, false));
-
- TransactionNegPos tnp = transactionInfos.get(txID);
-
- if (tnp == null)
- {
- tnp = new TransactionNegPos();
-
- transactionInfos.put(txID, tnp);
- }
-
- tnp.addPos(file, id);
-
- hasData = true;
- }
-
- break;
- }
- case UPDATE_RECORD_TX:
- {
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- long id = bb.getLong();
- maxMessageID = Math.max(maxMessageID, id);
-
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- TransactionHolder tx = transactions.get(txID);
-
- if (tx == null)
- {
- tx = new TransactionHolder(txID);
- transactions.put(txID, tx);
- }
-
- tx.recordInfos.add(new RecordInfo(id, record, true));
-
- TransactionNegPos tnp = transactionInfos.get(txID);
-
- if (tnp == null)
- {
- tnp = new TransactionNegPos();
-
- transactionInfos.put(txID, tnp);
- }
-
- tnp.addPos(file, id);
-
- hasData = true;
- }
-
- break;
- }
- case DELETE_RECORD_TX:
- {
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- long id = bb.getLong();
- maxMessageID = Math.max(maxMessageID, id);
+ maxMessageID = Math.max(maxMessageID, id);
+
+ byte userRecordType = bb.get();
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ records.add(new RecordInfo(id, userRecordType, record, true));
+ hasData = true;
+ file.incPosCount();
+
+ PosFiles posFiles = posFilesMap.get(id);
+
+ if (posFiles != null)
+ {
+ //It's legal for this to be null. The file(s) with the may have been deleted
+ //just leaving some updates in this file
+
+ posFiles.addUpdateFile(file);
+ }
+ }
+
+ break;
+ }
+ case DELETE_RECORD:
+ {
+ long id = bb.getLong();
+
+ maxMessageID = Math.max(maxMessageID, id);
+
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ recordsToDelete.add(id);
+ hasData = true;
+
+ PosFiles posFiles = posFilesMap.remove(id);
+
+ if (posFiles != null)
+ {
+ posFiles.addDelete(file);
+ }
+ }
+
+ break;
+ }
+ case ADD_RECORD_TX:
+ {
+ long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+
+ byte userRecordType = bb.get();
+
+ long id = bb.getLong();
+ maxMessageID = Math.max(maxMessageID, id);
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ TransactionHolder tx = transactions.get(txID);
+
+ if (tx == null)
+ {
+ tx = new TransactionHolder(txID);
+ transactions.put(txID, tx);
+ }
+
+ tx.recordInfos.add(new RecordInfo(id, userRecordType, record, false));
+
+ TransactionNegPos tnp = transactionInfos.get(txID);
+
+ if (tnp == null)
+ {
+ tnp = new TransactionNegPos();
+
+ transactionInfos.put(txID, tnp);
+ }
+
+ tnp.addPos(file, id);
+
+ hasData = true;
+ }
+
+ break;
+ }
+ case UPDATE_RECORD_TX:
+ {
+ long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+
+ byte userRecordType = bb.get();
+
+ long id = bb.getLong();
+ maxMessageID = Math.max(maxMessageID, id);
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ TransactionHolder tx = transactions.get(txID);
+
+ if (tx == null)
+ {
+ tx = new TransactionHolder(txID);
+ transactions.put(txID, tx);
+ }
+
+ tx.recordInfos.add(new RecordInfo(id, userRecordType, record, true));
+
+ TransactionNegPos tnp = transactionInfos.get(txID);
+
+ if (tnp == null)
+ {
+ tnp = new TransactionNegPos();
+
+ transactionInfos.put(txID, tnp);
+ }
+
+ tnp.addPos(file, id);
+
+ hasData = true;
+ }
+
+ break;
+ }
+ case DELETE_RECORD_TX:
+ {
+ long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ long id = bb.getLong();
+ maxMessageID = Math.max(maxMessageID, id);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- TransactionHolder tx = transactions.get(txID);
-
- if (tx == null)
- {
- tx = new TransactionHolder(txID);
- transactions.put(txID, tx);
- }
-
- tx.recordsToDelete.add(id);
-
- TransactionNegPos tnp = transactionInfos.get(txID);
-
- if (tnp == null)
- {
- tnp = new TransactionNegPos();
-
- transactionInfos.put(txID, tnp);
- }
-
- tnp.addNeg(file, id);
-
- hasData = true;
- }
-
- break;
- }
- case PREPARE_RECORD:
- {
- long txID = bb.getLong();
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ TransactionHolder tx = transactions.get(txID);
+
+ if (tx == null)
+ {
+ tx = new TransactionHolder(txID);
+ transactions.put(txID, tx);
+ }
+
+ tx.recordsToDelete.add(id);
+
+ TransactionNegPos tnp = transactionInfos.get(txID);
+
+ if (tnp == null)
+ {
+ tnp = new TransactionNegPos();
+
+ transactionInfos.put(txID, tnp);
+ }
+
+ tnp.addNeg(file, id);
+
+ hasData = true;
+ }
+
+ break;
+ }
+ case PREPARE_RECORD:
+ {
+ long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- TransactionHolder tx = transactions.get(txID);
-
- if (tx == null)
- {
- throw new IllegalStateException("Cannot find tx with id " + txID);
- }
-
- tx.prepared = true;
-
- TransactionNegPos tnp = transactionInfos.get(txID);
-
- if (tnp == null)
- {
- throw new IllegalStateException("Cannot find tx " + txID);
- }
-
- tnp.prepare(file);
-
- hasData = true;
- }
-
- break;
- }
- case COMMIT_RECORD:
- {
- long txID = bb.getLong();
-
- maxTransactionID = Math.max(maxTransactionID, txID);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- TransactionHolder tx = transactions.remove(txID);
-
- if (tx != null)
- {
- records.addAll(tx.recordInfos);
- recordsToDelete.addAll(tx.recordsToDelete);
-
- TransactionNegPos tnp = transactionInfos.remove(txID);
-
- if (tnp == null)
- {
- throw new IllegalStateException("Cannot find tx " + txID);
- }
-
- tnp.commit(file);
-
- hasData = true;
- }
- }
-
- break;
- }
- case ROLLBACK_RECORD:
- {
- long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ TransactionHolder tx = transactions.get(txID);
+
+ if (tx == null)
+ {
+ throw new IllegalStateException("Cannot find tx with id " + txID);
+ }
+
+ tx.prepared = true;
+
+ TransactionNegPos tnp = transactionInfos.get(txID);
+
+ if (tnp == null)
+ {
+ throw new IllegalStateException("Cannot find tx " + txID);
+ }
+
+ tnp.prepare(file);
+
+ hasData = true;
+ }
+
+ break;
+ }
+ case COMMIT_RECORD:
+ {
+ long txID = bb.getLong();
+
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ TransactionHolder tx = transactions.remove(txID);
+
+ if (tx != null)
+ {
+ records.addAll(tx.recordInfos);
+ recordsToDelete.addAll(tx.recordsToDelete);
+
+ TransactionNegPos tnp = transactionInfos.remove(txID);
+
+ if (tnp == null)
+ {
+ throw new IllegalStateException("Cannot find tx " + txID);
+ }
+
+ tnp.commit(file);
+
+ hasData = true;
+ }
+ }
+
+ break;
+ }
+ case ROLLBACK_RECORD:
+ {
+ long txID = bb.getLong();
+
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ byte end = bb.get();
+
+ if (end != DONE)
+ {
+ repairFrom(pos, file);
+ }
+ else
+ {
+ TransactionHolder tx = transactions.remove(txID);
+
+ if (tx != null)
+ {
+ TransactionNegPos tnp = transactionInfos.remove(txID);
+
+ if (tnp == null)
+ {
+ throw new IllegalStateException("Cannot find tx " + txID);
+ }
+
+ tnp.rollback(file);
+
+ hasData = true;
+ }
+ }
+
+ break;
+ }
+ case FILL_CHARACTER:
+ {
+ //End of records in file - we check the file only contains fill characters from this point
+ while (bb.hasRemaining())
+ {
+ byte b = bb.get();
+
+ if (b != FILL_CHARACTER)
+ {
+ throw new IllegalStateException("Corrupt file " + file.getFile().getFileName() +
+ " contains non fill character at position " + pos);
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ throw new IllegalStateException("Journal " + file.getFile().getFileName() +
+ " is corrupt, invalid record type " + recordType);
+ }
+ }
+
+ bb.position(file.getFile().calculateBlockStart(bb.position()));
+
+ if (recordType != FILL_CHARACTER)
+ {
+ lastDataPos = bb.position();
+ }
+ }
+
+ if (hasData)
+ {
+ dataFiles.add(file);
+
+ file.getFile().close();
+ }
+ else
+ {
+ //Empty dataFiles with no data
+ freeFiles.add(file);
+
+ //Position it ready for writing
+ file.getFile().position(file.getFile().calculateBlockStart(SIZE_LONG));
+ }
+ }
+
+ transactionIDSequence.set(maxTransactionID + 1);
+
+ //Create any more files we need
+
+ //FIXME - size() involves a scan
+ int filesToCreate = minFiles - (dataFiles.size() + freeFiles.size());
+
+ for (int i = 0; i < filesToCreate; i++)
+ {
+ // Keeping all files opened can be very costly (mainly on AIO)
+ freeFiles.add(createFile());
+ }
+
+ //The current file is the last one
+
+ Iterator<JournalFile> iter = dataFiles.iterator();
+
+ while (iter.hasNext())
+ {
+ currentFile = iter.next();
+
+ if (!iter.hasNext())
+ {
+ iter.remove();
+ }
+ }
+
+ if (currentFile != null)
+ {
+ currentFile.getFile().open();
+
+ currentFile.getFile().position(lastDataPos);
+
+ currentFile.setOffset(lastDataPos);
+ }
+ else
+ {
+ currentFile = freeFiles.remove();
+ }
+
+ for (RecordInfo record: records)
+ {
+ if (!recordsToDelete.contains(record.id))
+ {
+ committedRecords.add(record);
+ }
+ }
+
+ for (TransactionHolder transaction: transactions.values())
+ {
+ if (!transaction.prepared)
+ {
+ log.warn("Uncommitted transaction with id " + transaction.transactionID + " found and discarded");
+
+ TransactionNegPos transactionInfo = this.transactionInfos.get(transaction.transactionID);
+
+ if (transactionInfo == null)
+ {
+ throw new IllegalStateException("Cannot find tx " + transaction.transactionID);
+ }
+
+ //Reverse the refs
+ transactionInfo.forget();
+ }
+ else
+ {
+ PreparedTransactionInfo info = new PreparedTransactionInfo(transaction.transactionID);
+
+ info.records.addAll(transaction.recordInfos);
+
+ info.recordsToDelete.addAll(transaction.recordsToDelete);
+
+ preparedTransactions.add(info);
+ }
+ }
+
+ state = STATE_LOADED;
+
+ return maxMessageID;
+ }
- maxTransactionID = Math.max(maxTransactionID, txID);
- byte end = bb.get();
-
- if (end != DONE)
- {
- repairFrom(pos, file);
- }
- else
- {
- TransactionHolder tx = transactions.remove(txID);
-
- if (tx != null)
- {
- TransactionNegPos tnp = transactionInfos.remove(txID);
-
- if (tnp == null)
- {
- throw new IllegalStateException("Cannot find tx " + txID);
- }
-
- tnp.rollback(file);
-
- hasData = true;
- }
- }
-
- break;
- }
- case FILL_CHARACTER:
- {
- //End of records in file - we check the file only contains fill characters from this point
- while (bb.hasRemaining())
- {
- byte b = bb.get();
-
- if (b != FILL_CHARACTER)
- {
- throw new IllegalStateException("Corrupt file " + file.getFile().getFileName() +
- " contains non fill character at position " + pos);
- }
- }
-
- break;
- }
- default:
- {
- throw new IllegalStateException("Journal " + file.getFile().getFileName() +
- " is corrupt, invalid record type " + recordType);
- }
- }
-
- bb.position(file.getFile().calculateBlockStart(bb.position()));
-
- if (recordType != FILL_CHARACTER)
- {
- lastDataPos = bb.position();
- }
- }
-
- if (hasData)
- {
- dataFiles.add(file);
-
- file.getFile().close();
- }
- else
- {
- //Empty dataFiles with no data
- freeFiles.add(file);
-
- //Position it ready for writing
- file.getFile().position(file.getFile().calculateBlockStart(SIZE_LONG));
- }
- }
-
- transactionIDSequence.set(maxTransactionID + 1);
-
- //Create any more files we need
-
- //FIXME - size() involves a scan
- int filesToCreate = minFiles - (dataFiles.size() + freeFiles.size());
-
- for (int i = 0; i < filesToCreate; i++)
- {
- // Keeping all files opened can be very costly (mainly on AIO)
- freeFiles.add(createFile());
- }
-
- //The current file is the last one
-
- Iterator<JournalFile> iter = dataFiles.iterator();
-
- while (iter.hasNext())
- {
- currentFile = iter.next();
-
- if (!iter.hasNext())
- {
- iter.remove();
- }
- }
-
- if (currentFile != null)
- {
- currentFile.getFile().open();
-
- currentFile.getFile().position(lastDataPos);
-
- currentFile.setOffset(lastDataPos);
- }
- else
- {
- currentFile = freeFiles.remove();
- }
-
- for (RecordInfo record: records)
- {
- if (!recordsToDelete.contains(record.id))
- {
- committedRecords.add(record);
- }
- }
-
- for (TransactionHolder transaction: transactions.values())
- {
- if (!transaction.prepared)
- {
- log.warn("Uncommitted transaction with id " + transaction.transactionID + " found and discarded");
-
- TransactionNegPos transactionInfo = this.transactionInfos.get(transaction.transactionID);
-
- if (transactionInfo == null)
- {
- throw new IllegalStateException("Cannot find tx " + transaction.transactionID);
- }
-
- //Reverse the refs
- transactionInfo.forget();
- }
- else
- {
- PreparedTransactionInfo info = new PreparedTransactionInfo(transaction.transactionID);
-
- info.records.addAll(transaction.recordInfos);
-
- info.recordsToDelete.addAll(transaction.recordsToDelete);
-
- preparedTransactions.add(info);
- }
- }
-
- state = STATE_LOADED;
-
- return maxMessageID;
- }
-
public int getAlignment() throws Exception
{
return this.currentFile.getFile().getAlignment();
@@ -1037,7 +1179,30 @@
}
- // TestableJournal implementation --------------------------------------------------------------
+ public String debug() throws Exception
+ {
+ this.checkReclaimStatus();
+
+ StringBuilder builder = new StringBuilder();
+
+ for (JournalFile file: dataFiles)
+ {
+ builder.append("DataFile:" + file + " posCounter = " + file.getPosCount() + " reclaimStatus = " + file.isCanReclaim() + "\n");
+ if (file instanceof JournalFileImpl)
+ {
+ builder.append(((JournalFileImpl)file).debug());
+
+ }
+ }
+
+ builder.append("CurrentFile:" + currentFile+ " posCounter = " + currentFile.getPosCount() + "\n");
+ builder.append(((JournalFileImpl)currentFile).debug());
+
+
+ return builder.toString();
+ }
+
+ // TestableJournal implementation --------------------------------------------------------------
public synchronized void checkAndReclaimFiles() throws Exception
{
@@ -1064,7 +1229,7 @@
sf.open();
- ByteBuffer bb = sf.newBuffer(SIZE_LONG);
+ ByteBuffer bb = fileFactory.newBuffer(SIZE_LONG);
bb.putLong(newOrderingID);
@@ -1178,7 +1343,7 @@
// Private -----------------------------------------------------------------------------
- private void appendRecord(ByteBuffer bb, boolean sync) throws Exception
+ private JournalFile appendRecord(ByteBuffer bb, boolean sync) throws Exception
{
lock.acquire();
@@ -1189,6 +1354,7 @@
checkFile(size);
currentFile.getFile().write(bb, sync);
currentFile.extendOffset(size);
+ return currentFile;
}
finally
{
@@ -1196,7 +1362,7 @@
}
}
- private void appendRecord(ByteBuffer bb, boolean sync, IOCallback callback) throws Exception
+ private JournalFile appendRecord(ByteBuffer bb, boolean sync, IOCallback callback) throws Exception
{
lock.acquire();
@@ -1207,6 +1373,7 @@
checkFile(size);
currentFile.getFile().write(bb, sync, callback);
currentFile.extendOffset(size);
+ return currentFile;
}
finally
{
@@ -1233,13 +1400,13 @@
if (trace) log.trace("Creating file " + fileName);
- SequentialFile sequentialFile = fileFactory.createSequentialFile(fileName, sync);
+ SequentialFile sequentialFile = fileFactory.createSequentialFile(fileName, sync, maxAIO);
sequentialFile.open();
sequentialFile.fill(0, fileSize, FILL_CHARACTER);
- ByteBuffer bb = sequentialFile.newBuffer(SIZE_LONG);
+ ByteBuffer bb = fileFactory.newBuffer(SIZE_LONG);
bb.putLong(orderingID);
@@ -1295,15 +1462,15 @@
dataFiles.add(currentFile);
- //FIXME - isEmpty() involves a scan!!
- if (!freeFiles.isEmpty())
+ try
{
- currentFile = freeFiles.remove();
+ currentFile = freeFiles.remove();
}
- else
+ catch (NoSuchElementException e)
{
- currentFile = createFile();
+ currentFile = createFile();
}
+
}
}
@@ -1321,7 +1488,99 @@
return tx;
}
+ private TransactionCallback getTransactionCallback(long transactionId)
+ {
+ TransactionCallback callback = this.transactionCallbacks.get(transactionId);
+
+ if (callback == null)
+ {
+ callback = new TransactionCallback();
+ transactionCallbacks.put(transactionId, callback);
+ }
+
+ return callback;
+ }
+
+ private void removeTransactionCallback(long transactionId)
+ {
+ transactionCallbacks.remove(transactionId);
+ }
+
+
+
// Inner classes ---------------------------------------------------------------------------
+
+ class SimpleCallback implements IOCallback
+ {
+
+ String errorMessage;
+ int errorCode;
+ CountDownLatch latch = new CountDownLatch(1);
+
+ public void done()
+ {
+ latch.countDown();
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ this.errorMessage = errorMessage;
+ this.errorCode = errorCode;
+ latch.countDown();
+
+ }
+
+ public void waitCompletion() throws InterruptedException
+ {
+ // TODO: Variable Timeout?
+ if (!latch.await(30, TimeUnit.SECONDS))
+ {
+ throw new IllegalStateException("Timeout!");
+ }
+ if (errorMessage != null)
+ {
+ throw new IllegalStateException("Error on Transaction: " + errorCode + " - " + errorMessage);
+ }
+ }
+
+ }
+
+ class TransactionCallback implements IOCallback
+ {
+
+ VariableLatch countLatch = new VariableLatch();
+
+ String errorMessage = null;
+ int errorCode = 0;
+
+ public void countUp()
+ {
+ countLatch.up();
+ }
+
+ public void done()
+ {
+ countLatch.down();
+ }
+
+ public void waitCompletion() throws InterruptedException
+ {
+ countLatch.waitCompletion(90);
+
+ if (errorMessage != null)
+ {
+ throw new IllegalStateException("Error on Transaction: " + errorCode + " - " + errorMessage);
+ }
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ this.errorMessage = errorMessage;
+ this.errorCode = errorCode;
+ countLatch.down();
+ }
+
+ }
private class ReclaimerTask extends TimerTask
{
@@ -1510,28 +1769,5 @@
}
}
}
-
- public String debug() throws Exception
- {
- this.checkReclaimStatus();
-
- StringBuilder builder = new StringBuilder();
-
- for (JournalFile file: dataFiles)
- {
- builder.append("DataFile:" + file + " posCounter = " + file.getPosCount() + " reclaimStatus = " + file.isCanReclaim() + "\n");
- if (file instanceof JournalFileImpl)
- {
- builder.append(((JournalFileImpl)file).debug());
-
- }
- }
-
- builder.append("CurrentFile:" + currentFile+ " posCounter = " + currentFile.getPosCount() + "\n");
- builder.append(((JournalFileImpl)currentFile).debug());
-
-
- return builder.toString();
- }
-
+
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFile.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFile.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFile.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -183,13 +183,4 @@
channel.position(pos);
}
- public ByteBuffer newBuffer(int size)
- {
- return ByteBuffer.allocate(size);
- }
-
- public ByteBuffer wrapBuffer(byte[] bytes)
- {
- return ByteBuffer.wrap(bytes);
- }
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFileFactory.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFileFactory.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFileFactory.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -21,6 +21,8 @@
*/
package org.jboss.messaging.core.journal.impl;
+import java.nio.ByteBuffer;
+
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.journal.SequentialFileFactory;
@@ -38,9 +40,25 @@
super(journalDir);
}
- public SequentialFile createSequentialFile(final String fileName, final boolean sync)
+ public SequentialFile createSequentialFile(final String fileName, final boolean sync, int maxIO)
{
return new NIOSequentialFile(journalDir, fileName, sync);
}
+ public boolean supportsCallbacks()
+ {
+ return false;
+ }
+
+ public ByteBuffer newBuffer(int size)
+ {
+ return ByteBuffer.allocate(size);
+ }
+
+ public ByteBuffer wrapBuffer(byte[] bytes)
+ {
+ return ByteBuffer.wrap(bytes);
+ }
+
+
}
Modified: trunk/src/main/org/jboss/messaging/core/message/Message.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/message/Message.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/message/Message.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -23,6 +23,7 @@
import java.util.Set;
+import org.jboss.messaging.core.journal.EncodingSupport;
import org.jboss.messaging.util.MessagingBuffer;
import org.jboss.messaging.util.SimpleString;
@@ -37,7 +38,7 @@
*
* $Id: Message.java 3341 2007-11-19 14:34:57Z timfox $
*/
-public interface Message
+public interface Message extends EncodingSupport
{
public static final SimpleString HDR_ACTUAL_EXPIRY_TIME = new SimpleString("JBMActualExpiryTime");
@@ -65,8 +66,9 @@
void setPriority(byte priority);
-
- MessagingBuffer encode();
+ int encodeSize();
+
+ void encode(MessagingBuffer buffer);
void decode(MessagingBuffer buffer);
Modified: trunk/src/main/org/jboss/messaging/core/message/impl/MessageImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/message/impl/MessageImpl.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/message/impl/MessageImpl.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -21,6 +21,27 @@
*/
package org.jboss.messaging.core.message.impl;
+import static org.jboss.messaging.util.DataConstants.BOOLEAN;
+import static org.jboss.messaging.util.DataConstants.BYTE;
+import static org.jboss.messaging.util.DataConstants.BYTES;
+import static org.jboss.messaging.util.DataConstants.CHAR;
+import static org.jboss.messaging.util.DataConstants.DOUBLE;
+import static org.jboss.messaging.util.DataConstants.FLOAT;
+import static org.jboss.messaging.util.DataConstants.INT;
+import static org.jboss.messaging.util.DataConstants.LONG;
+import static org.jboss.messaging.util.DataConstants.NOT_NULL;
+import static org.jboss.messaging.util.DataConstants.NULL;
+import static org.jboss.messaging.util.DataConstants.SHORT;
+import static org.jboss.messaging.util.DataConstants.SIZE_BOOLEAN;
+import static org.jboss.messaging.util.DataConstants.SIZE_BYTE;
+import static org.jboss.messaging.util.DataConstants.SIZE_CHAR;
+import static org.jboss.messaging.util.DataConstants.SIZE_DOUBLE;
+import static org.jboss.messaging.util.DataConstants.SIZE_FLOAT;
+import static org.jboss.messaging.util.DataConstants.SIZE_INT;
+import static org.jboss.messaging.util.DataConstants.SIZE_LONG;
+import static org.jboss.messaging.util.DataConstants.SIZE_SHORT;
+import static org.jboss.messaging.util.DataConstants.STRING;
+
import java.util.Set;
import org.jboss.messaging.core.logging.Logger;
@@ -105,25 +126,50 @@
// Message implementation ----------------------------------------
- public MessagingBuffer encode()
+ public void encode(MessagingBuffer buff)
{
- MessagingBuffer buff = new BufferWrapper(1024);
-
+// buff.putSimpleString(destination);
+// buff.putInt(type);
+// buff.putBoolean(durable);
+// buff.putLong(expiration);
+// buff.putLong(timestamp);
+// buff.putByte(priority);
+// properties.encode(buff);
+// buff.putInt(body.limit());
+// buff.putBytes(body.array(), 0, body.limit());
+
+
buff.putSimpleString(destination);
buff.putInt(type);
buff.putBoolean(durable);
buff.putLong(expiration);
buff.putLong(timestamp);
buff.putByte(priority);
-
properties.encode(buff);
-
buff.putInt(body.limit());
-
- //TODO this can be optimisied
buff.putBytes(body.array(), 0, body.limit());
+
+ }
+
+ public int encodeSize()
+ {
+// return /* Destination */ SimpleString.sizeofString(destination) +
+// /* Type */ SIZE_INT +
+// /* Durable */ SIZE_BOOLEAN +
+// /* Expiration */ SIZE_LONG +
+// /* Timestamp */ SIZE_LONG +
+// /* Priority */ SIZE_BYTE +
+// /* PropertySize and Properties */ properties.encodeSize() +
+// /* BodySize and Body */ SIZE_INT + body.limit();
+ return /* Destination */ SimpleString.sizeofString(destination) +
+ /* Type */ SIZE_INT +
+ /* Durable */ SIZE_BOOLEAN +
+ /* Expiration */ SIZE_LONG +
+ /* Timestamp */ SIZE_LONG +
+ /* Priority */ SIZE_BYTE +
+ /* PropertySize and Properties */ properties.encodeSize() +
+ /* BodySize and Body */ SIZE_INT + body.limit();
- return buff;
}
public void decode(final MessagingBuffer buffer)
Modified: trunk/src/main/org/jboss/messaging/core/persistence/impl/journal/JournalStorageManager.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/persistence/impl/journal/JournalStorageManager.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/persistence/impl/journal/JournalStorageManager.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -5,17 +5,20 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import org.jboss.messaging.core.config.Configuration;
import org.jboss.messaging.core.filter.Filter;
import org.jboss.messaging.core.filter.impl.FilterImpl;
+import org.jboss.messaging.core.journal.IOCallback;
import org.jboss.messaging.core.journal.Journal;
import org.jboss.messaging.core.journal.PreparedTransactionInfo;
import org.jboss.messaging.core.journal.RecordInfo;
@@ -28,7 +31,6 @@
import org.jboss.messaging.core.postoffice.Binding;
import org.jboss.messaging.core.postoffice.PostOffice;
import org.jboss.messaging.core.postoffice.impl.BindingImpl;
-import org.jboss.messaging.core.remoting.impl.mina.BufferWrapper;
import org.jboss.messaging.core.server.JournalType;
import org.jboss.messaging.core.server.MessageReference;
import org.jboss.messaging.core.server.Queue;
@@ -38,6 +40,7 @@
import org.jboss.messaging.util.ByteBufferWrapper;
import org.jboss.messaging.util.MessagingBuffer;
import org.jboss.messaging.util.SimpleString;
+import org.jboss.messaging.util.VariableLatch;
/**
*
@@ -84,7 +87,7 @@
private final Journal bindingsJournal;
private final ConcurrentMap<SimpleString, Long> destinationIDMap = new ConcurrentHashMap<SimpleString, Long>();
-
+
private volatile boolean started;
public JournalStorageManager(Configuration config)
@@ -105,7 +108,7 @@
SequentialFileFactory bindingsFF = new NIOSequentialFileFactory(bindingsDir);
- bindingsJournal = new JournalImpl(1024 * 1024, 2, true, bindingsFF, 10000, "jbm-bindings", "bindings");
+ bindingsJournal = new JournalImpl(1024 * 1024, 2, true, bindingsFF, 10000, "jbm-bindings", "bindings", 1);
String journalDir = config.getJournalDirectory();
@@ -123,11 +126,11 @@
if (!AIOSequentialFileFactory.isSupported())
{
log.warn("AIO wasn't located on this platform, using just standard Java NIO. If you are on Linux, install LibAIO and the required wrapper and you will get a lot of performance benefit");
- journalFF = new NIOSequentialFileFactory(bindingsDir);
+ journalFF = new NIOSequentialFileFactory(journalDir);
}
else
{
- journalFF = new AIOSequentialFileFactory(bindingsDir);
+ journalFF = new AIOSequentialFileFactory(journalDir);
log.info("AIO loaded successfully");
}
}
@@ -144,7 +147,7 @@
messageJournal = new JournalImpl(config.getJournalFileSize(),
config.getJournalMinFiles(), config.isJournalSync(), journalFF,
- config.getJournalTaskPeriod(), "jbm-data", "jbm");
+ config.getJournalTaskPeriod(), "jbm-data", "jbm", 10000);
}
public long generateMessageID()
@@ -161,22 +164,14 @@
public void storeMessage(final ServerMessage message) throws Exception
{
- //TODO too much copying is occurring here
-
- MessagingBuffer buffer = new BufferWrapper(1024);
-
- buffer.putByte(ADD_MESSAGE);
-
- buffer.putBytes(message.encode().array());
-
- messageJournal.appendAddRecord(message.getMessageID(), buffer.array());
+ messageJournal.appendAddRecord(message.getMessageID(), ADD_MESSAGE, message);
}
public void storeAcknowledge(final long queueID, final long messageID) throws Exception
{
byte[] record = ackBytes(queueID, messageID);
- messageJournal.appendUpdateRecord(messageID, record);
+ messageJournal.appendUpdateRecord(messageID, ACKNOWLEDGE_REF, record);
}
public void storeDelete(final long messageID) throws Exception
@@ -188,22 +183,14 @@
public void storeMessageTransactional(long txID, ServerMessage message) throws Exception
{
- //TODO too much copying is occurring here
-
- MessagingBuffer buffer = new BufferWrapper(1024);
-
- buffer.putByte(ADD_MESSAGE);
-
- buffer.putBytes(message.encode().array());
-
- messageJournal.appendAddRecordTransactional(txID, message.getMessageID(), buffer.array());
+ messageJournal.appendAddRecordTransactional(txID, ADD_MESSAGE, message.getMessageID(), message);
}
public void storeAcknowledgeTransactional(long txID, long queueID, long messageID) throws Exception
{
byte[] record = ackBytes(queueID, messageID);
- messageJournal.appendUpdateRecordTransactional(txID, messageID, record);
+ messageJournal.appendUpdateRecordTransactional(txID, ACKNOWLEDGE_REF, messageID, record);
}
public void storeDeleteTransactional(long txID, long messageID) throws Exception
@@ -223,7 +210,7 @@
public void rollback(long txID) throws Exception
{
- messageJournal.appendRollbackRecord(txID);
+ messageJournal.appendRollbackRecord(txID);
}
// Other operations
@@ -234,15 +221,13 @@
ByteBuffer bb = ByteBuffer.wrap(bytes);
- bb.put(UPDATE_DELIVERY_COUNT);
-
bb.putLong(ref.getQueue().getPersistenceID());
bb.putLong(ref.getMessage().getMessageID());
bb.putInt(ref.getDeliveryCount());
- messageJournal.appendUpdateRecord(ref.getMessage().getMessageID(), bytes);
+ messageJournal.appendUpdateRecord(ref.getMessage().getMessageID(), UPDATE_DELIVERY_COUNT, bytes);
}
public void loadMessages(final PostOffice postOffice, final Map<Long, Queue> queues) throws Exception
@@ -261,7 +246,7 @@
ByteBuffer bb = ByteBuffer.wrap(data);
- byte recordType = bb.get();
+ byte recordType = record.getUserRecordType();
switch (recordType)
{
@@ -368,8 +353,6 @@
queue.setPersistenceID(queueID);
- daos.writeByte(BINDING_RECORD);
-
byte[] nameBytes = queue.getName().getData();
daos.writeInt(nameBytes.length);
@@ -399,7 +382,7 @@
byte[] data = baos.toByteArray();
- bindingsJournal.appendAddRecord(queueID, data);
+ bindingsJournal.appendAddRecord(queueID, BINDING_RECORD, data);
}
public void deleteBinding(Binding binding) throws Exception
@@ -429,8 +412,6 @@
DataOutputStream daos = new DataOutputStream(baos);
- daos.writeByte(DESTINATION_RECORD);
-
byte[] destBytes = destination.getData();
daos.writeInt(destBytes.length);
@@ -441,7 +422,7 @@
byte[] data = baos.toByteArray();
- bindingsJournal.appendAddRecord(destinationID, data);
+ bindingsJournal.appendAddRecord(destinationID, DESTINATION_RECORD, data);
return true;
}
@@ -484,7 +465,7 @@
DataInputStream dais = new DataInputStream(bais);
- byte rec = dais.readByte();
+ byte rec = record.getUserRecordType();
if (rec == BINDING_RECORD)
{
@@ -575,15 +556,13 @@
}
// Private ----------------------------------------------------------------------------------
-
+
private byte[] ackBytes(final long queueID, final long messageID)
{
- byte[] record = new byte[SIZE_BYTE + SIZE_LONG + SIZE_LONG];
+ byte[] record = new byte[SIZE_LONG + SIZE_LONG];
ByteBuffer bb = ByteBuffer.wrap(record);
- bb.put(ACKNOWLEDGE_REF);
-
bb.putLong(queueID);
bb.putLong(messageID);
Modified: trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ProducerSendMessage.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ProducerSendMessage.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ProducerSendMessage.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -64,15 +64,7 @@
public void encodeBody(final MessagingBuffer buffer)
{
- MessagingBuffer buf = clientMessage.encode();
-
- buf.flip();
-
- //TODO - can be optimised
-
- byte[] data = buf.array();
-
- buffer.putBytes(data, 0, buf.limit());
+ clientMessage.encode(buffer);
}
public void decodeBody(final MessagingBuffer buffer)
Modified: trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ReceiveMessage.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ReceiveMessage.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/core/remoting/impl/wireformat/ReceiveMessage.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -91,18 +91,9 @@
public void encodeBody(final MessagingBuffer buffer)
{
- MessagingBuffer buf = serverMessage.encode();
-
- buf.flip();
-
- //TODO - can be optimised
-
- byte[] data = buf.array();
-
buffer.putInt(deliveryCount);
buffer.putLong(deliveryID);
-
- buffer.putBytes(data, 0, buf.limit());
+ serverMessage.encode(buffer);
}
public void decodeBody(final MessagingBuffer buffer)
Modified: trunk/src/main/org/jboss/messaging/util/ByteBufferWrapper.java
===================================================================
--- trunk/src/main/org/jboss/messaging/util/ByteBufferWrapper.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/util/ByteBufferWrapper.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -33,6 +33,11 @@
this.buffer = buffer;
}
+ public ByteBuffer getBuffer()
+ {
+ return buffer;
+ }
+
public byte[] array()
{
return buffer.array();
Modified: trunk/src/main/org/jboss/messaging/util/TypedProperties.java
===================================================================
--- trunk/src/main/org/jboss/messaging/util/TypedProperties.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/src/main/org/jboss/messaging/util/TypedProperties.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -46,6 +46,7 @@
import java.util.Map;
import java.util.Set;
+import org.jboss.messaging.core.journal.EncodingSupport;
import org.jboss.messaging.core.logging.Logger;
/**
@@ -57,7 +58,7 @@
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
*
*/
-public class TypedProperties
+public class TypedProperties implements EncodingSupport
{
private static final Logger log = Logger.getLogger(TypedProperties.class);
@@ -269,7 +270,7 @@
for (Map.Entry<SimpleString, PropertyValue> entry: properties.entrySet())
{
- SimpleString s = entry.getKey();;
+ SimpleString s = entry.getKey();
byte[] data = s.getData();
buffer.putInt(data.length);
buffer.putBytes(data);
@@ -279,6 +280,23 @@
}
}
+ public int encodeSize()
+ {
+ if (properties == null)
+ {
+ return SIZE_BYTE;
+ }
+ else
+ {
+ int size = SIZE_BYTE + SIZE_INT;
+ for (Map.Entry<SimpleString, PropertyValue> entry: properties.entrySet())
+ {
+ size += SimpleString.sizeofString(entry.getKey()) + entry.getValue().encodeSize();
+ }
+ return size;
+ }
+ }
+
public void clear()
{
if (properties != null)
@@ -343,6 +361,8 @@
void write(MessagingBuffer buffer);
+ int encodeSize();
+
byte getType();
}
@@ -366,6 +386,12 @@
{
return NULL;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE;
+ }
+
}
private static final class BooleanValue implements PropertyValue
@@ -397,6 +423,12 @@
{
return BOOLEAN;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_BOOLEAN;
+ }
+
}
private static final class ByteValue implements PropertyValue
@@ -428,6 +460,11 @@
{
return BYTE;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_BYTE;
+ }
}
private static final class BytesValue implements PropertyValue
@@ -462,6 +499,12 @@
{
return BYTES;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_INT + val.length;
+ }
+
}
private static final class ShortValue implements PropertyValue
@@ -493,6 +536,11 @@
{
return SHORT;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_SHORT;
+ }
}
private static final class IntValue implements PropertyValue
@@ -524,6 +572,11 @@
{
return INT;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_INT;
+ }
}
private static final class LongValue implements PropertyValue
@@ -555,6 +608,11 @@
{
return LONG;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_LONG;
+ }
}
private static final class FloatValue implements PropertyValue
@@ -586,6 +644,12 @@
{
return FLOAT;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_FLOAT;
+ }
+
}
private static final class DoubleValue implements PropertyValue
@@ -617,6 +681,11 @@
{
return DOUBLE;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_DOUBLE;
+ }
}
private static final class CharValue implements PropertyValue
@@ -653,6 +722,11 @@
{
return SIZE_CHAR;
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SIZE_CHAR;
+ }
}
private static final class StringValue implements PropertyValue
@@ -689,5 +763,10 @@
{
return SimpleString.sizeofString(val);
}
+
+ public int encodeSize()
+ {
+ return SIZE_BYTE + SimpleString.sizeofString(val);
+ }
}
}
Added: trunk/src/main/org/jboss/messaging/util/VariableLatch.java
===================================================================
--- trunk/src/main/org/jboss/messaging/util/VariableLatch.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/util/VariableLatch.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,126 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * 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.util;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+
+/** This class will use the framework provided to by AbstractQueuedSynchronizer.
+ * AbstractQueuedSynchronizer is the framework for any sort of concurrent synchronization, such as Semaphores, events, etc, based on AtomicIntegers.
+ *
+ * The idea is, instead of providing each user specific Latch/Synchronization, java.util.concurrent provides the framework for reuses, based on an AtomicInteger (getState())
+ *
+ * On JBossMessaging we have the requirement of increment and decrement a counter until the user fires a ready event (commit). At that point we just act as a regular countDown
+ *
+ * @author Clebert Suconic
+ * */
+public class VariableLatch
+{
+ /**
+ * Look at the doc and examples provided by AbstractQueuedSynchronizer for more information
+ * @see AbstractQueuedSynchronizer*/
+ @SuppressWarnings("serial")
+ private static class CountSync extends AbstractQueuedSynchronizer
+ {
+
+ public CountSync ()
+ {
+ setState(0);
+ }
+
+
+ public int getCount()
+ {
+ return getState();
+ }
+
+ public int tryAcquireShared(int numberOfAqcquires)
+ {
+ return getState()==0 ? 1 : -1;
+ }
+
+ public void add()
+ {
+ for (;;)
+ {
+ int actualState = getState();
+ int newState = actualState + 1;
+ if (compareAndSetState(actualState, newState))
+ {
+ return;
+ }
+ }
+ }
+
+
+ public boolean tryReleaseShared(int numberOfReleases)
+ {
+ for (;;)
+ {
+ int actualState = getState();
+ if (actualState == 0)
+ {
+ return true;
+ }
+
+ int newState = getState() - numberOfReleases;
+
+ if (compareAndSetState(actualState, newState))
+ {
+ return newState == 0;
+ }
+ }
+ }
+ }
+
+ CountSync control = new CountSync();
+
+
+ public int getCount()
+ {
+ return control.getCount();
+ }
+
+ public void up()
+ {
+ control.add();
+ }
+
+ public void down()
+ {
+ control.releaseShared(1);
+ }
+
+ public void waitCompletion() throws InterruptedException
+ {
+ control.acquireSharedInterruptibly(1);
+ }
+
+ public void waitCompletion(int seconds) throws InterruptedException
+ {
+ if (!control.tryAcquireSharedNanos(1, TimeUnit.SECONDS.toNanos(seconds)))
+ {
+ throw new IllegalStateException("Timeout!");
+ }
+ }
+}
Property changes on: trunk/tests/jms-tests/src
___________________________________________________________________
Name: svn:ignore
+ local
Modified: trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/MultiThreadWriteNativeTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/MultiThreadWriteNativeTest.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/MultiThreadWriteNativeTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -119,6 +119,13 @@
position.set(0);
}
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ assertEquals(0, AsynchronousFileImpl.getTotalMaxIO());
+ }
+
public void testMultipleASynchronousWrites() throws Throwable
{
executeTest(false);
@@ -134,43 +141,48 @@
log.info(sync?"Sync test:":"Async test");
AsynchronousFileImpl jlibAIO = new AsynchronousFileImpl();
jlibAIO.open(FILE_NAME, 21000);
- log.debug("Preallocating file");
-
- jlibAIO.fill(0l, NUMBER_OF_THREADS, SIZE * NUMBER_OF_LINES, (byte)0);
- log.debug("Done Preallocating file");
-
- CountDownLatch latchStart = new CountDownLatch (NUMBER_OF_THREADS + 1);
-
- ArrayList<ThreadProducer> list = new ArrayList<ThreadProducer>(NUMBER_OF_THREADS);
- for(int i=0;i<NUMBER_OF_THREADS;i++)
+ try
{
- ThreadProducer producer = new ThreadProducer("Thread " + i, latchStart, jlibAIO, sync);
- list.add(producer);
- producer.start();
+ log.debug("Preallocating file");
+
+ jlibAIO.fill(0l, NUMBER_OF_THREADS, SIZE * NUMBER_OF_LINES, (byte)0);
+ log.debug("Done Preallocating file");
+
+ CountDownLatch latchStart = new CountDownLatch (NUMBER_OF_THREADS + 1);
+
+ ArrayList<ThreadProducer> list = new ArrayList<ThreadProducer>(NUMBER_OF_THREADS);
+ for(int i=0;i<NUMBER_OF_THREADS;i++)
+ {
+ ThreadProducer producer = new ThreadProducer("Thread " + i, latchStart, jlibAIO, sync);
+ list.add(producer);
+ producer.start();
+ }
+
+ latchStart.countDown();
+ latchStart.await();
+
+
+ long startTime = System.currentTimeMillis();
+
+
+
+ for (ThreadProducer producer: list)
+ {
+ producer.join();
+ if (producer.failed != null)
+ {
+ throw producer.failed;
+ }
+ }
+ long endTime = System.currentTimeMillis();
+
+ log.debug((sync?"Sync result:":"Async result:") + " Records/Second = " + (NUMBER_OF_THREADS * NUMBER_OF_LINES * 1000 / (endTime - startTime)) + " total time = " + (endTime - startTime) + " total number of records = " + (NUMBER_OF_THREADS * NUMBER_OF_LINES));
}
-
- latchStart.countDown();
- latchStart.await();
-
-
- long startTime = System.currentTimeMillis();
-
-
-
- for (ThreadProducer producer: list)
+ finally
{
- producer.join();
- if (producer.failed != null)
- {
- throw producer.failed;
- }
+ jlibAIO.close();
}
- long endTime = System.currentTimeMillis();
- log.debug((sync?"Sync result:":"Async result:") + " Records/Second = " + (NUMBER_OF_THREADS * NUMBER_OF_LINES * 1000 / (endTime - startTime)) + " total time = " + (endTime - startTime) + " total number of records = " + (NUMBER_OF_THREADS * NUMBER_OF_LINES));
-
- jlibAIO.close();
-
}
Modified: trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/SingleThreadWriteNativeTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/SingleThreadWriteNativeTest.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/SingleThreadWriteNativeTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -50,6 +50,12 @@
File file = new File(FILE_NAME);
file.delete();
}
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ assertEquals(0, AsynchronousFileImpl.getTotalMaxIO());
+ }
private void encodeBufer(ByteBuffer buffer)
{
@@ -147,7 +153,8 @@
}
finally
{
- try {controller.close();} catch (Exception ignored){}
+ try {controller.close();} catch (Exception ignored){}
+ try {controller2.close();} catch (Exception ignored){}
}
@@ -499,49 +506,53 @@
private void validateData(int numberOfLines, int size, int aioLimit) throws Exception
{
final AsynchronousFileImpl controller = new AsynchronousFileImpl();
- controller.open(FILE_NAME, aioLimit);
-
- ByteBuffer compareBlock = ByteBuffer.allocateDirect(size);
- encodeBufer(compareBlock);
-
- ByteBuffer readBuffer = controller.newBuffer(size);
-
-
- boolean firstInvalid = false;
- for (int i=0;i<numberOfLines;i++)
+ try
{
- if (i % 1000 == 0)
- {
- log.info("line = " + i);
- }
- CountDownLatch latch = new CountDownLatch(1);
- LocalAIO callback = new LocalAIO(latch);
- controller.read(i * size, size, readBuffer, callback);
-
- latch.await();
+ controller.open(FILE_NAME, aioLimit);
- if (!compareBuffers(compareBlock, readBuffer))
+ ByteBuffer compareBlock = ByteBuffer.allocateDirect(size);
+ encodeBufer(compareBlock);
+
+ ByteBuffer readBuffer = controller.newBuffer(size);
+
+
+ boolean firstInvalid = false;
+ for (int i=0;i<numberOfLines;i++)
{
- //log.info("Invalid line at " + i);
- firstInvalid=true;
- }
- else
- {
- if (firstInvalid)
+ if (i % 1000 == 0)
{
- for (int line=0;line<10;line++) log.info("*********************************************");
- log.warn("Valid line after an invalid line!!!");
+ log.info("line = " + i);
}
+ CountDownLatch latch = new CountDownLatch(1);
+ LocalAIO callback = new LocalAIO(latch);
+ controller.read(i * size, size, readBuffer, callback);
+
+ latch.await();
+
+ if (!compareBuffers(compareBlock, readBuffer))
+ {
+ //log.info("Invalid line at " + i);
+ firstInvalid=true;
+ }
+ else
+ {
+ if (firstInvalid)
+ {
+ for (int line=0;line<10;line++) log.info("*********************************************");
+ log.warn("Valid line after an invalid line!!!");
+ }
+ }
+
+ readBuffer.position(100);
+ ByteBuffer buf1 = readBuffer.slice();
+
+ //System.out.println("buf1=" + buf1);
}
-
- readBuffer.position(100);
- ByteBuffer buf1 = readBuffer.slice();
-
- //System.out.println("buf1=" + buf1);
-
-
-
}
+ finally
+ {
+ controller.close();
+ }
}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/AIOSequentialFileFactoryTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/AIOSequentialFileFactoryTest.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/AIOSequentialFileFactoryTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -24,10 +24,18 @@
import java.io.File;
import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.journal.SequentialFileFactory;
import org.jboss.messaging.core.journal.impl.AIOSequentialFileFactory;
+import org.jboss.messaging.core.journal.IOCallback;
public class AIOSequentialFileFactoryTest extends SequentialFileFactoryTestBase
{
@@ -52,12 +60,122 @@
public void testBuffer() throws Exception
{
- SequentialFile file = factory.createSequentialFile("filtetmp.log", true);
+ SequentialFile file = factory.createSequentialFile("filtetmp.log", true, 10);
file.open();
- ByteBuffer buff = file.newBuffer(10);
+ ByteBuffer buff = factory.newBuffer(10);
assertEquals(512, buff.limit());
- //ByteBuffer buffer =
+ file.close();
}
+ public void testBlockCallback() throws Exception
+ {
+ class BlockCallback implements IOCallback
+ {
+
+ int countDone = 0;
+ int countError = 0;
+ CountDownLatch blockLatch;
+ BlockCallback()
+ {
+ this.blockLatch = new CountDownLatch(1);
+ }
+
+ public void release()
+ {
+ blockLatch.countDown();
+ }
+
+ public void done()
+ {
+
+ try
+ {
+ blockLatch.await();
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+
+ countDone ++;
+
+
+
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ try
+ {
+ blockLatch.await();
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+
+ countError ++;
+ }
+ }
+
+ BlockCallback callback = new BlockCallback();
+
+ final int NUMBER_OF_RECORDS = 10000;
+
+ SequentialFile file = factory.createSequentialFile("callbackBlock.log", true, 1000);
+ file.open();
+ file.fill(0, 512 * NUMBER_OF_RECORDS, (byte)'a');
+
+
+ for (int i=0; i<NUMBER_OF_RECORDS; i++)
+ {
+ ByteBuffer buffer = factory.newBuffer(512);
+
+ buffer.putInt(i + 10);
+
+ for (int j=buffer.position(); j<buffer.limit(); j++)
+ {
+ buffer.put((byte)'b');
+ }
+
+ file.write(buffer, true, callback);
+ }
+
+
+ callback.release();
+ file.close();
+ assertEquals(NUMBER_OF_RECORDS, callback.countDone);
+ assertEquals(0, callback.countError);
+
+
+
+ file.open();
+
+ ByteBuffer buffer = factory.newBuffer(512);
+
+ for (int i=0; i<NUMBER_OF_RECORDS; i++)
+ {
+
+ file.read(buffer);
+ buffer.rewind();
+
+ int recordRead = buffer.getInt();
+
+ assertEquals(i + 10, recordRead);
+
+ for (int j=buffer.position(); j<buffer.limit(); j++)
+ {
+ assertEquals((byte)'b', buffer.get());
+ }
+
+ }
+
+
+ file.close();
+
+
+
+
+ }
+
+
}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestBase.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestBase.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -29,12 +29,14 @@
import java.util.ListIterator;
import java.util.Map;
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
import org.jboss.messaging.core.journal.PreparedTransactionInfo;
import org.jboss.messaging.core.journal.RecordInfo;
import org.jboss.messaging.core.journal.SequentialFileFactory;
import org.jboss.messaging.core.journal.TestableJournal;
import org.jboss.messaging.core.journal.impl.JournalImpl;
import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.tests.unit.core.journal.impl.fakes.FakeCallback;
import org.jboss.messaging.tests.util.RandomUtil;
import org.jboss.messaging.tests.util.UnitTestCase;
@@ -57,6 +59,8 @@
protected Map<Long, TransactionHolder> transactions = new LinkedHashMap<Long, TransactionHolder>();
+ protected int maxAIO;
+
protected int minFiles;
protected int fileSize;
@@ -97,7 +101,9 @@
fileFactory = null;
- journal = null;;
+ journal = null;
+
+ assertEquals(0, AsynchronousFileImpl.getTotalMaxIO());
}
protected void resetFileFactory() throws Exception
@@ -109,17 +115,26 @@
// Private ---------------------------------------------------------------------------------
- protected void setup(int minFreeFiles, int fileSize, boolean sync)
- {
- this.minFiles = minFreeFiles;
- this.fileSize = fileSize;
- this.sync = sync;
- }
-
+ protected void setup(int minFreeFiles, int fileSize, boolean sync, int maxAIO)
+ {
+ this.minFiles = minFreeFiles;
+ this.fileSize = fileSize;
+ this.sync = sync;
+ this.maxAIO = maxAIO;
+ }
+
+ protected void setup(int minFreeFiles, int fileSize, boolean sync)
+ {
+ this.minFiles = minFreeFiles;
+ this.fileSize = fileSize;
+ this.sync = sync;
+ this.maxAIO = 1000;
+ }
+
public void createJournal() throws Exception
{
journal =
- new JournalImpl(fileSize, minFiles, sync, fileFactory, 1000, filePrefix, fileExtension);
+ new JournalImpl(fileSize, minFiles, sync, fileFactory, 1000, filePrefix, fileExtension, maxAIO);
}
protected void startJournal() throws Exception
@@ -190,9 +205,9 @@
{
byte[] record = generateRecord(size);
- journal.appendAddRecord(arguments[i], record);
+ journal.appendAddRecord(arguments[i], (byte)0, record);
- records.add(new RecordInfo(arguments[i], record, false));
+ records.add(new RecordInfo(arguments[i], (byte)0, record, false));
}
}
@@ -202,9 +217,9 @@
{
byte[] updateRecord = generateRecord(recordLength);
- journal.appendUpdateRecord(arguments[i], updateRecord);
+ journal.appendUpdateRecord(arguments[i], (byte)0, updateRecord);
- records.add(new RecordInfo(arguments[i], updateRecord, true));
+ records.add(new RecordInfo(arguments[i], (byte)0, updateRecord, true));
}
}
@@ -227,9 +242,9 @@
// SIZE_BYTE + SIZE_LONG + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE
byte[] record = generateRecord(recordLength - JournalImpl.SIZE_ADD_RECORD_TX );
- journal.appendAddRecordTransactional(txID, arguments[i], record);
+ journal.appendAddRecordTransactional(txID, (byte)0, arguments[i], record);
- tx.records.add(new RecordInfo(arguments[i], record, false));
+ tx.records.add(new RecordInfo(arguments[i], (byte)0, record, false));
}
}
@@ -242,9 +257,9 @@
{
byte[] updateRecord = generateRecord(recordLength - JournalImpl.SIZE_UPDATE_RECORD_TX );
- journal.appendUpdateRecordTransactional(txID, arguments[i], updateRecord);
+ journal.appendUpdateRecordTransactional(txID, (byte)0, arguments[i], updateRecord);
- tx.records.add(new RecordInfo(arguments[i], updateRecord, true));
+ tx.records.add(new RecordInfo(arguments[i], (byte)0, updateRecord, true));
}
}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestUnit.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestUnit.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestUnit.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -102,7 +102,7 @@
{
try
{
- new JournalImpl(JournalImpl.MIN_FILE_SIZE - 1, 10, true, fileFactory, 5000, filePrefix, fileExtension);
+ new JournalImpl(JournalImpl.MIN_FILE_SIZE - 1, 10, true, fileFactory, 5000, filePrefix, fileExtension, 1);
fail("Should throw exception");
}
@@ -113,7 +113,7 @@
try
{
- new JournalImpl(10 * 1024, 1, true, fileFactory, 5000, filePrefix, fileExtension);
+ new JournalImpl(10 * 1024, 1, true, fileFactory, 5000, filePrefix, fileExtension, 1);
fail("Should throw exception");
}
@@ -124,7 +124,7 @@
try
{
- new JournalImpl(10 * 1024, 10, true, null, 5000, filePrefix, fileExtension);
+ new JournalImpl(10 * 1024, 10, true, null, 5000, filePrefix, fileExtension, 1);
fail("Should throw exception");
}
@@ -135,7 +135,7 @@
try
{
- new JournalImpl(10 * 1024, 10, true, fileFactory, JournalImpl.MIN_TASK_PERIOD - 1, filePrefix, fileExtension);
+ new JournalImpl(10 * 1024, 10, true, fileFactory, JournalImpl.MIN_TASK_PERIOD - 1, filePrefix, fileExtension, 1);
fail("Should throw exception");
}
@@ -146,7 +146,7 @@
try
{
- new JournalImpl(10 * 1024, 10, true, fileFactory, 5000, null, fileExtension);
+ new JournalImpl(10 * 1024, 10, true, fileFactory, 5000, null, fileExtension, 1);
fail("Should throw exception");
}
@@ -155,17 +155,28 @@
//Ok
}
- try
- {
- new JournalImpl(10 * 1024, 10, true, fileFactory, 5000, filePrefix, null);
-
- fail("Should throw exception");
- }
- catch (NullPointerException e)
- {
- //Ok
- }
-
+ try
+ {
+ new JournalImpl(10 * 1024, 10, true, fileFactory, 5000, filePrefix, null, 1);
+
+ fail("Should throw exception");
+ }
+ catch (NullPointerException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ new JournalImpl(10 * 1024, 10, true, fileFactory, 5000, filePrefix, null, 0);
+
+ fail("Should throw exception");
+ }
+ catch (NullPointerException e)
+ {
+ //Ok
+ }
+
}
public void testFilesImmediatelyAfterload() throws Exception
@@ -1999,18 +2010,18 @@
{
byte[] record = generateRecord(10 + (int)(1500 * Math.random()));
- journal.appendAddRecord(i, record);
+ journal.appendAddRecord(i, (byte)0, record);
- records.add(new RecordInfo(i, record, false));
+ records.add(new RecordInfo(i, (byte)0, record, false));
}
for (int i = 0; i < 1000; i++)
{
byte[] record = generateRecord(10 + (int)(1024 * Math.random()));
- journal.appendUpdateRecord(i, record);
+ journal.appendUpdateRecord(i, (byte)0, record);
- records.add(new RecordInfo(i, record, true));
+ records.add(new RecordInfo(i, (byte)0, record, true));
}
for (int i = 0; i < 1000; i++)
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -26,9 +26,11 @@
import java.util.List;
import java.util.UUID;
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.journal.SequentialFileFactory;
import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.tests.unit.core.journal.impl.fakes.FakeCallback;
import org.jboss.messaging.tests.util.UnitTestCase;
/**
@@ -40,7 +42,7 @@
*/
public abstract class SequentialFileFactoryTestBase extends UnitTestCase
{
- private static final Logger log = Logger.getLogger(SequentialFileFactoryTestBase.class);
+ protected final Logger log = Logger.getLogger(this.getClass());
protected void setUp() throws Exception
@@ -50,6 +52,12 @@
factory = createFactory();
}
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ assertEquals(0, AsynchronousFileImpl.getTotalMaxIO());
+ }
+
protected abstract SequentialFileFactory createFactory();
protected SequentialFileFactory factory;
@@ -66,19 +74,21 @@
expectedFiles.add(fileName);
- SequentialFile sf = factory.createSequentialFile(fileName, false);
+ SequentialFile sf = factory.createSequentialFile(fileName, false, 1);
sf.open();
assertEquals(fileName, sf.getFileName());
+
+ sf.close();
}
//Create a couple with a different extension - they shouldn't be picked up
- SequentialFile sf1 = factory.createSequentialFile("different.file", false);
+ SequentialFile sf1 = factory.createSequentialFile("different.file", false, 1);
sf1.open();
- SequentialFile sf2 = factory.createSequentialFile("different.cheese", false);
+ SequentialFile sf2 = factory.createSequentialFile("different.cheese", false, 1);
sf2.open();
List<String> fileNames = factory.listFiles("jbm");
@@ -101,33 +111,44 @@
assertEquals(1, fileNames.size());
assertTrue(fileNames.contains("different.cheese"));
+
+ sf1.close();
+ sf2.close();
}
public void testFill() throws Exception
{
- SequentialFile sf = factory.createSequentialFile("fill.jbm", true);
+ SequentialFile sf = factory.createSequentialFile("fill.jbm", true, 1);
sf.open();
- checkFill(sf, 0, 2048, (byte)'X');
+ try
+ {
- checkFill(sf, 512, 512, (byte)'Y');
-
- checkFill(sf, 0, 1, (byte)'Z');
-
- checkFill(sf, 512, 1, (byte)'A');
-
- checkFill(sf, 1024, 512*4, (byte)'B');
+ checkFill(sf, 0, 2048, (byte)'X');
+
+ checkFill(sf, 512, 512, (byte)'Y');
+
+ checkFill(sf, 0, 1, (byte)'Z');
+
+ checkFill(sf, 512, 1, (byte)'A');
+
+ checkFill(sf, 1024, 512*4, (byte)'B');
+ }
+ finally
+ {
+ sf.close();
+ }
}
public void testDelete() throws Exception
{
- SequentialFile sf = factory.createSequentialFile("delete-me.jbm", true);
+ SequentialFile sf = factory.createSequentialFile("delete-me.jbm", true, 1);
sf.open();
- SequentialFile sf2 = factory.createSequentialFile("delete-me2.jbm", true);
+ SequentialFile sf2 = factory.createSequentialFile("delete-me2.jbm", true, 1);
sf2.open();
@@ -147,45 +168,55 @@
assertTrue(fileNames.contains("delete-me2.jbm"));
+ sf2.close();
+
}
public void testWriteandRead() throws Exception
{
- SequentialFile sf = factory.createSequentialFile("write.jbm", true);
+ SequentialFile sf = factory.createSequentialFile("write.jbm", true, 1);
sf.open();
String s1 = "aardvark";
byte[] bytes1 = s1.getBytes("UTF-8");
- ByteBuffer bb1 = sf.wrapBuffer(bytes1);
+ ByteBuffer bb1 = factory.wrapBuffer(bytes1);
String s2 = "hippopotamus";
byte[] bytes2 = s2.getBytes("UTF-8");
- ByteBuffer bb2 = sf.wrapBuffer(bytes2);
+ ByteBuffer bb2 = factory.wrapBuffer(bytes2);
String s3 = "echidna";
byte[] bytes3 = s3.getBytes("UTF-8");
- ByteBuffer bb3 = sf.wrapBuffer(bytes3);
+ ByteBuffer bb3 = factory.wrapBuffer(bytes3);
- int bytesWritten = sf.write(bb1, true);
+ FakeCallback callback = new FakeCallback();
+ int bytesWritten = sf.write(bb1, true, callback);
+ callback.waitComplete();
assertEquals(calculateRecordSize(bytes1.length, sf.getAlignment()), bytesWritten);
- bytesWritten = sf.write(bb2, true);
+ callback = new FakeCallback();
+ bytesWritten = sf.write(bb2, true, callback);
+ callback.waitComplete();
assertEquals(calculateRecordSize(bytes2.length, sf.getAlignment()), bytesWritten);
- bytesWritten = sf.write(bb3, true);
+ callback = new FakeCallback();
+ bytesWritten = sf.write(bb3, true, callback);
+ callback.waitComplete();
assertEquals(calculateRecordSize(bytes3.length, sf.getAlignment()), bytesWritten);
sf.position(0);
- ByteBuffer rb1 = sf.newBuffer(bytes1.length);
- ByteBuffer rb2 = sf.newBuffer(bytes2.length);
- ByteBuffer rb3 = sf.newBuffer(bytes3.length);
+ ByteBuffer rb1 = factory.newBuffer(bytes1.length);
+ ByteBuffer rb2 = factory.newBuffer(bytes2.length);
+ ByteBuffer rb3 = factory.newBuffer(bytes3.length);
- int bytesRead = sf.read(rb1);
+ callback = new FakeCallback();
+ int bytesRead = sf.read(rb1, callback);
+ callback.waitComplete();
assertEquals(calculateRecordSize(bytes1.length, sf.getAlignment()), bytesRead);
for (int i=0; i<bytes1.length; i++)
@@ -193,7 +224,9 @@
assertEquals(bytes1[i], rb1.get(i));
}
- bytesRead = sf.read(rb2);
+ callback = new FakeCallback();
+ bytesRead = sf.read(rb2, callback);
+ callback.waitComplete();
assertEquals(calculateRecordSize(bytes2.length, sf.getAlignment()), bytesRead);
for (int i=0; i<bytes2.length; i++)
{
@@ -201,42 +234,52 @@
}
- bytesRead = sf.read(rb3);
+ callback = new FakeCallback();
+ bytesRead = sf.read(rb3, callback);
+ callback.waitComplete();
assertEquals(calculateRecordSize(bytes3.length, sf.getAlignment()), bytesRead);
for (int i=0; i<bytes3.length; i++)
{
assertEquals(bytes3[i], rb3.get(i));
}
+ sf.close();
+
}
public void testPosition() throws Exception
{
- SequentialFile sf = factory.createSequentialFile("position.jbm", true);
+ SequentialFile sf = factory.createSequentialFile("position.jbm", true, 1);
sf.open();
String s1 = "orange";
byte[] bytes1 = s1.getBytes("UTF-8");
- ByteBuffer bb1 = sf.wrapBuffer(bytes1);
+ ByteBuffer bb1 = factory.wrapBuffer(bytes1);
String s2 = "grapefruit";
- byte[] bytes2 = s2.getBytes("UTF-8");
- ByteBuffer bb2 = sf.wrapBuffer(bytes2);
+ byte[] bytes2 = s1.getBytes("UTF-8");
+ ByteBuffer bb2 = factory.wrapBuffer(bytes2);
String s3 = "lemon";
byte[] bytes3 = s3.getBytes("UTF-8");
- ByteBuffer bb3 = sf.wrapBuffer(bytes3);
+ ByteBuffer bb3 = factory.wrapBuffer(bytes3);
- int bytesWritten = sf.write(bb1, true);
+ FakeCallback callback = new FakeCallback();
+ int bytesWritten = sf.write(bb1, true, callback);
+ callback.waitComplete();
assertEquals(bb1.limit(), bytesWritten);
- bytesWritten = sf.write(bb2, true);
+ callback = new FakeCallback();
+ bytesWritten = sf.write(bb2, true, callback);
+ callback.waitComplete();
assertEquals(bb2.limit(), bytesWritten);
- bytesWritten = sf.write(bb3, true);
+ callback = new FakeCallback();
+ bytesWritten = sf.write(bb3, true, callback);
+ callback.waitComplete();
assertEquals(bb3.limit(), bytesWritten);
@@ -246,9 +289,9 @@
byte[] rbytes3 = new byte[bytes3.length];
- ByteBuffer rb1 = sf.newBuffer(rbytes1.length);
- ByteBuffer rb2 = sf.newBuffer(rbytes2.length);
- ByteBuffer rb3 = sf.newBuffer(rbytes3.length);
+ ByteBuffer rb1 = factory.newBuffer(rbytes1.length);
+ ByteBuffer rb2 = factory.newBuffer(rbytes2.length);
+ ByteBuffer rb3 = factory.newBuffer(rbytes3.length);
sf.position(bb1.limit() + bb2.limit());
@@ -271,20 +314,24 @@
assertEquals(rb1.limit(), bytesRead);
rb1.get(rbytes1);
- assertByteArraysEquivalent(bytes1, rbytes1);
+ assertByteArraysEquivalent(bytes1, rbytes1);
+
+ sf.close();
}
public void testOpenClose() throws Exception
{
- SequentialFile sf = factory.createSequentialFile("openclose.jbm", true);
+ SequentialFile sf = factory.createSequentialFile("openclose.jbm", true, 1);
sf.open();
String s1 = "cheesecake";
byte[] bytes1 = s1.getBytes("UTF-8");
- ByteBuffer bb1 = sf.wrapBuffer(bytes1);
+ ByteBuffer bb1 = factory.wrapBuffer(bytes1);
- int bytesWritten = sf.write(bb1, true);
+ FakeCallback callback = new FakeCallback();
+ int bytesWritten = sf.write(bb1, true, callback);
+ callback.waitComplete();
assertEquals(bb1.limit(), bytesWritten);
@@ -304,6 +351,8 @@
sf.open();
sf.write(bb1, true);
+
+ sf.close();
}
// Private ---------------------------------
@@ -318,7 +367,7 @@
file.position(pos);
- ByteBuffer bb = file.newBuffer(size);
+ ByteBuffer bb = factory.newBuffer(size);
int bytesRead = file.read(bb);
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeCallback.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeCallback.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeCallback.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,40 @@
+package org.jboss.messaging.tests.unit.core.journal.impl.fakes;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.jboss.messaging.core.journal.IOCallback;
+
+public class FakeCallback implements IOCallback
+{
+
+ String msg;
+ CountDownLatch latch;
+
+ public FakeCallback(CountDownLatch latch)
+ {
+ this.latch = latch;
+ }
+
+ public FakeCallback()
+ {
+ this.latch = new CountDownLatch(1);
+ }
+
+ public void done()
+ {
+ latch.countDown();
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ latch.countDown();
+ this.msg = errorMessage;
+ }
+
+ public void waitComplete() throws Exception
+ {
+ latch.await();
+ }
+
+}
+
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -45,7 +45,7 @@
private Map<String, FakeSequentialFile> fileMap = new ConcurrentHashMap<String, FakeSequentialFile>();
- public SequentialFile createSequentialFile(final String fileName, final boolean sync) throws Exception
+ public SequentialFile createSequentialFile(final String fileName, final boolean sync, final int maxAIO) throws Exception
{
FakeSequentialFile sf = fileMap.get(fileName);
@@ -90,6 +90,21 @@
fileMap.clear();
}
+ public boolean supportsCallbacks()
+ {
+ return false;
+ }
+
+ public ByteBuffer newBuffer(int size)
+ {
+ return ByteBuffer.allocate(size);
+ }
+
+ public ByteBuffer wrapBuffer(byte[] bytes)
+ {
+ return ByteBuffer.wrap(bytes);
+ }
+
public class FakeSequentialFile implements SequentialFile
{
private volatile boolean open;
@@ -259,16 +274,6 @@
}
}
- public ByteBuffer newBuffer(int size)
- {
- return ByteBuffer.allocate(size);
- }
-
- public ByteBuffer wrapBuffer(byte[] bytes)
- {
- return ByteBuffer.wrap(bytes);
- }
-
public int getAlignment() throws Exception
{
return 1;
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/JournalImplTestUnit.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/JournalImplTestUnit.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/JournalImplTestUnit.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -22,10 +22,17 @@
package org.jboss.messaging.tests.unit.core.journal.impl.timing;
import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.jboss.messaging.tests.unit.core.journal.impl.JournalImplTestBase;
+import org.jboss.messaging.tests.unit.core.journal.impl.fakes.FakeCallback;
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
+import org.jboss.messaging.core.journal.IOCallback;
+import org.jboss.messaging.core.journal.Journal;
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.core.logging.Logger;
/**
@@ -39,8 +46,13 @@
{
private static final Logger log = Logger.getLogger(JournalImplTestUnit.class);
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ assertEquals(0, AsynchronousFileImpl.getTotalMaxIO());
+ }
-
public void testAddUpdateDeleteManyLargeFileSize() throws Exception
{
final int numberAdds = 10000;
@@ -70,7 +82,8 @@
deletes[i] = i;
}
- setup(10, 10 * 1024 * 1024, true);
+ // This would take a long time with sync=true, and still validates the file.
+ setup(10, 10 * 1024 * 1024, false);
createJournal();
startJournal();
load();
@@ -113,14 +126,16 @@
deletes[i] = i;
}
- setup(10, 10 * 1024, true);
+ setup(10, 10 * 1024, false);
createJournal();
startJournal();
load();
add(adds);
update(updates);
delete(deletes);
- stopJournal();
+
+ log.info("Debug journal:" + debugJournal());
+ stopJournal(false);
createJournal();
startJournal();
loadAndCheck();
@@ -140,17 +155,19 @@
byte[] record = generateRecord(recordLength);
+
+ int NUMBER_OF_RECORDS = 1000;
- for (int count = 0; count < 100000; count++)
+ for (int count = 0; count < NUMBER_OF_RECORDS; count++)
{
- journal.appendAddRecord(count, record);
+ journal.appendAddRecord(count, (byte)0, record);
- if (count >= 5000)
+ if (count >= NUMBER_OF_RECORDS / 2)
{
- journal.appendDeleteRecord(count - 5000);
+ journal.appendDeleteRecord(count - NUMBER_OF_RECORDS / 2);
}
- if (count % 10000 == 0)
+ if (count % 100 == 0)
{
log.info("Done: " + count);
}
@@ -158,7 +175,7 @@
long end = System.currentTimeMillis();
- double rate = 1000 * ((double)100000) / (end - start);
+ double rate = 1000 * ((double)NUMBER_OF_RECORDS) / (end - start);
log.info("Rate of " + rate + " adds/removes per sec");
@@ -169,11 +186,173 @@
startJournal();
journal.load(new ArrayList<RecordInfo>(), new ArrayList<PreparedTransactionInfo>());
- assertEquals(5000, journal.getIDMapSize());
+ assertEquals(NUMBER_OF_RECORDS / 2, journal.getIDMapSize());
stopJournal();
}
+ public void testSpeedNonTransactional() throws Exception
+ {
+ for (int i=0;i<1;i++)
+ {
+ this.setUp();
+ System.gc(); Thread.sleep(500);
+ internaltestSpeedNonTransactional();
+ this.tearDown();
+ }
+ }
+
+ public void internaltestSpeedNonTransactional() throws Exception
+ {
+
+ final long numMessages = 10000;
+
+ int numFiles = (int)(((numMessages * 1024 + 512) / (10 * 1024 * 1024)) * 1.3);
+
+ if (numFiles<2) numFiles = 2;
+
+ log.info("num Files=" + numFiles);
+
+ Journal journal =
+ new JournalImpl(10 * 1024 * 1024, numFiles, true, getFileFactory(),
+ 5000, "jbm-data", "jbm", 5000);
+
+ journal.start();
+
+ journal.load(new ArrayList<RecordInfo>(), null);
+
+
+ final CountDownLatch latch = new CountDownLatch((int)numMessages);
+
+
+ class LocalCallback implements IOCallback
+ {
+
+ int i=0;
+ String message = null;
+ boolean done = false;
+ CountDownLatch latch;
+
+ public LocalCallback(int i, CountDownLatch latch)
+ {
+ this.i = i;
+ this.latch = latch;
+ }
+ public void done()
+ {
+ synchronized (this)
+ {
+ if (done)
+ {
+ message = "done received in duplicate";
+ }
+ done = true;
+ this.latch.countDown();
+ }
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ synchronized (this)
+ {
+ System.out.println("********************** Error = " + (i++));
+ message = errorMessage;
+ latch.countDown();
+ }
+ }
+
+ }
+
+
+ log.info("Adding data");
+ byte[] data = new byte[700];
+
+ long start = System.currentTimeMillis();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ journal.appendAddRecord(i, (byte)0, data);
+ }
+
+ long end = System.currentTimeMillis();
+
+ double rate = 1000 * (double)numMessages / (end - start);
+
+ boolean failed = false;
+
+ // If this fails it is probably because JournalImpl it is closing the files without waiting all the completes to arrive first
+ assertFalse(failed);
+
+
+ log.info("Rate " + rate + " records/sec");
+
+ journal.stop();
+
+ journal =
+ new JournalImpl(10 * 1024 * 1024, numFiles, true, getFileFactory(),
+ 5000, "jbm-data", "jbm", 5000);
+
+ journal.start();
+ journal.load(new ArrayList<RecordInfo>(), null);
+ journal.stop();
+
+ }
+
+ public void testSpeedTransactional() throws Exception
+ {
+ Journal journal =
+ new JournalImpl(10 * 1024 * 1024, 10, true, getFileFactory(),
+ 5000, "jbm-data", "jbm", 5000);
+
+ journal.start();
+
+ journal.load(new ArrayList<RecordInfo>(), null);
+
+ try
+ {
+ final int numMessages = 50050;
+
+ byte[] data = new byte[1024];
+
+ long start = System.currentTimeMillis();
+
+ int count = 0;
+ double rates[] = new double[50];
+ for (int i = 0; i < 50; i++)
+ {
+ long startTrans = System.currentTimeMillis();
+ for (int j=0; j<1000; j++)
+ {
+ journal.appendAddRecordTransactional(i, (byte)0, count++, data);
+ }
+
+ journal.appendCommitRecord(i);
+
+ long endTrans = System.currentTimeMillis();
+
+ rates[i] = 1000 * (double)1000 / (endTrans - startTrans);
+ }
+
+ long end = System.currentTimeMillis();
+
+ for (double rate: rates)
+ {
+ log.info("Transaction Rate = " + rate + " records/sec");
+
+ }
+
+ double rate = 1000 * (double)numMessages / (end - start);
+
+ log.info("Rate " + rate + " records/sec");
+ }
+ finally
+ {
+ journal.stop();
+ }
+
+ }
+
+
}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplAIOTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplAIOTest.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplAIOTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -35,6 +35,7 @@
import org.jboss.messaging.core.journal.impl.JournalImpl;
import org.jboss.messaging.core.journal.impl.NIOSequentialFileFactory;
import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.tests.unit.core.journal.impl.fakes.FakeCallback;
/**
*
@@ -59,152 +60,8 @@
file.mkdir();
- return new NIOSequentialFileFactory(journalDir);
+ return new AIOSequentialFileFactory(journalDir);
}
- public void testSpeedNonTransactional() throws Exception
- {
- for (int i=0;i<1;i++)
- {
- this.setUp();
- System.gc(); Thread.sleep(500);
- internaltestSpeedNonTransactional();
- this.tearDown();
- }
- }
-
- public void internaltestSpeedNonTransactional() throws Exception
- {
-
- final long numMessages = 100000;
-
- int numFiles = (int)(((numMessages * 1024 + 512) / (10 * 1024 * 1024)) * 1.3);
-
- if (numFiles<2) numFiles = 2;
-
- log.info("num Files=" + numFiles);
-
- Journal journal =
- new JournalImpl(10 * 1024 * 1024, numFiles, true, new AIOSequentialFileFactory(journalDir),
- 5000, "jbm-data", "jbm");
-
- journal.start();
-
- journal.load(new ArrayList<RecordInfo>(), null);
-
-
- final CountDownLatch latch = new CountDownLatch((int)numMessages);
-
-
- class LocalCallback implements IOCallback
- {
-
- int i=0;
- String message = null;
- boolean done = false;
- CountDownLatch latch;
-
- public LocalCallback(int i, CountDownLatch latch)
- {
- this.i = i;
- this.latch = latch;
- }
- public void done()
- {
- synchronized (this)
- {
- if (done)
- {
- message = "done received in duplicate";
- }
- done = true;
- this.latch.countDown();
- }
- }
-
- public void onError(int errorCode, String errorMessage)
- {
- synchronized (this)
- {
- System.out.println("********************** Error = " + (i++));
- message = errorMessage;
- latch.countDown();
- }
- }
-
- }
-
-
- log.info("Adding data");
- byte[] data = new byte[700];
-
- long start = System.currentTimeMillis();
-
- LocalCallback callback = new LocalCallback(1, latch);
- for (int i = 0; i < numMessages; i++)
- {
- journal.appendAddRecord(i, data, callback);
- }
-
- latch.await(10, TimeUnit.SECONDS);
-
- // Validates if the test has completed
- assertEquals(0, latch.getCount());
-
- long end = System.currentTimeMillis();
-
- double rate = 1000 * (double)numMessages / (end - start);
-
- boolean failed = false;
-
- // If this fails it is probably because JournalImpl it is closing the files without waiting all the completes to arrive first
- assertFalse(failed);
-
-
- log.info("Rate " + rate + " records/sec");
-
- journal.stop();
-
- journal =
- new JournalImpl(10 * 1024 * 1024, numFiles, true, new AIOSequentialFileFactory(journalDir),
- 5000, "jbm-data", "jbm");
-
- journal.start();
- journal.load(new ArrayList<RecordInfo>(), null);
- journal.stop();
-
- }
-
- public void testSpeedTransactional() throws Exception
- {
- Journal journal =
- new JournalImpl(10 * 1024 * 1024, 10, true, new AIOSequentialFileFactory(journalDir),
- 5000, "jbm-data", "jbm");
-
- journal.start();
-
- journal.load(new ArrayList<RecordInfo>(), null);
-
- final int numMessages = 10000;
-
- byte[] data = new byte[1024];
-
- long start = System.currentTimeMillis();
-
- int count = 0;
- for (int i = 0; i < numMessages; i++)
- {
- journal.appendAddRecordTransactional(i, count++, data);
-
- journal.appendCommitRecord(i);
- }
-
- long end = System.currentTimeMillis();
-
- double rate = 1000 * (double)numMessages / (end - start);
-
- log.info("Rate " + rate + " records/sec");
-
- }
}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplTest.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -59,75 +59,5 @@
}
- public void testSpeedNonTransactional() throws Exception
- {
- Journal journal =
- new JournalImpl(10 * 1024 * 1024, 10, true, new NIOSequentialFileFactory(journalDir),
- 5000, "jbm-data", "jbm");
-
- journal.start();
-
- journal.load(new ArrayList<RecordInfo>(), null);
-
- final int numMessages = 10000;
-
- byte[] data = new byte[1024];
-
- long start = System.currentTimeMillis();
-
- for (int i = 0; i < numMessages; i++)
- {
- journal.appendAddRecord(i, data);
- }
-
- long end = System.currentTimeMillis();
-
- double rate = 1000 * (double)numMessages / (end - start);
-
- log.info("Rate " + rate + " records/sec");
-
- journal.stop();
-
- journal =
- new JournalImpl(10 * 1024 * 1024, 10, true, new NIOSequentialFileFactory(journalDir),
- 5000, "jbm-data", "jbm");
-
- journal.start();
- journal.load(new ArrayList<RecordInfo>(), null);
-
-
- }
-
- public void testSpeedTransactional() throws Exception
- {
- Journal journal =
- new JournalImpl(10 * 1024 * 1024, 10, true, new NIOSequentialFileFactory(journalDir),
- 5000, "jbm-data", "jbm");
-
- journal.start();
-
- journal.load(new ArrayList<RecordInfo>(), null);
-
- final int numMessages = 10000;
-
- byte[] data = new byte[1024];
-
- long start = System.currentTimeMillis();
-
- int count = 0;
- for (int i = 0; i < numMessages; i++)
- {
- journal.appendAddRecordTransactional(i, count++, data);
-
- journal.appendCommitRecord(i);
- }
-
- long end = System.currentTimeMillis();
-
- double rate = 1000 * (double)numMessages / (end - start);
-
- log.info("Rate " + rate + " records/sec");
-
- }
}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/message/impl/MessageTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/message/impl/MessageTest.java 2008-05-12 14:57:22 UTC (rev 4173)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/message/impl/MessageTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -21,10 +21,13 @@
*/
package org.jboss.messaging.tests.unit.core.message.impl;
+import java.nio.ByteBuffer;
+
import org.jboss.messaging.core.client.ClientMessage;
import org.jboss.messaging.core.client.impl.ClientMessageImpl;
-import org.jboss.messaging.core.message.Message;
-import org.jboss.messaging.core.message.impl.MessageImpl;
+import org.jboss.messaging.core.journal.EncodingSupport;
+import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.core.remoting.impl.mina.BufferWrapper;
import org.jboss.messaging.core.server.MessageReference;
import org.jboss.messaging.core.server.Queue;
import org.jboss.messaging.core.server.QueueFactory;
@@ -32,7 +35,9 @@
import org.jboss.messaging.core.server.impl.ServerMessageImpl;
import org.jboss.messaging.tests.unit.core.server.impl.fakes.FakeQueueFactory;
import org.jboss.messaging.tests.util.UnitTestCase;
+import org.jboss.messaging.util.ByteBufferWrapper;
import org.jboss.messaging.util.SimpleString;
+import org.jboss.messaging.util.TypedProperties;
/**
*
@@ -45,7 +50,9 @@
*/
public class MessageTest extends UnitTestCase
{
- private QueueFactory queueFactory = new FakeQueueFactory();
+ private static final Logger log = Logger.getLogger(MessageTest.class);
+
+ private QueueFactory queueFactory = new FakeQueueFactory();
public void testCreateMessageBeforeSending()
{
@@ -245,7 +252,59 @@
assertEquals(1, messageDurable.getDurableRefCount());
}
+
+ public void testEncodingMessageProperties()
+ {
+
+ TypedProperties properties = new TypedProperties();
+ properties.putStringProperty(new SimpleString("str"), new SimpleString("Str2"));
+ properties.putStringProperty(new SimpleString("str2"), new SimpleString("Str2"));
+ properties.putBooleanProperty(new SimpleString("str3"), true );
+ properties.putByteProperty(new SimpleString("str4"), (byte)1);
+ properties.putBytesProperty(new SimpleString("str5"), new byte[]{1,2,3,4,5});
+ properties.putShortProperty(new SimpleString("str6"),(short)1);
+ properties.putIntProperty(new SimpleString("str7"), (int)1);
+ properties.putLongProperty(new SimpleString("str8"), (long)1);
+ properties.putFloatProperty(new SimpleString("str9"),(float) 1);
+ properties.putDoubleProperty(new SimpleString("str10"), (double) 1);
+ properties.putCharProperty(new SimpleString("str11"), 'a');
+
+ checkSizes(properties);
+
+ }
+
+ public void testEncodingMessage() throws Exception
+ {
+ byte[] bytes = new byte[]{(byte)1, (byte)2, (byte)3};
+ final BufferWrapper bufferBody = new BufferWrapper(bytes.length);
+ bufferBody.putBytes(bytes);
+
+
+ SimpleString address = new SimpleString("Simple Destination ");
+
+ ServerMessageImpl implMsg = new ServerMessageImpl(/* type */ 1, /* durable */ true, /* expiration */ 0,
+ /* timestamp */ 0, /* priority */(byte)0);
+
+ implMsg.setDestination(address);
+ implMsg.setBody(bufferBody);
+ implMsg.putStringProperty(new SimpleString("Key"), new SimpleString("This String is worthless!"));
+
+ checkSizes(implMsg);
+
+ implMsg.removeProperty(new SimpleString("Key"));
+
+ checkSizes(implMsg);
+
+ }
+ private void checkSizes(EncodingSupport obj)
+ {
+ ByteBuffer bf = ByteBuffer.allocateDirect(1024);
+ ByteBufferWrapper buffer = new ByteBufferWrapper(bf);
+ obj.encode(buffer);
+ assertEquals (buffer.position(), obj.encodeSize());
+ }
+
}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakeBinding.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakeBinding.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakeBinding.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,28 @@
+package org.jboss.messaging.tests.unit.core.persistence.fakes;
+
+import org.jboss.messaging.core.postoffice.Binding;
+import org.jboss.messaging.core.server.Queue;
+import org.jboss.messaging.util.SimpleString;
+
+public class FakeBinding implements Binding
+{
+ SimpleString address;
+ Queue queue;
+
+ public FakeBinding(SimpleString address, Queue queue)
+ {
+ this.address = address;
+ this.queue = queue;
+ }
+
+ public SimpleString getAddress()
+ {
+ return address;
+ }
+
+ public Queue getQueue()
+ {
+ return queue;
+ }
+
+}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakePostOffice.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakePostOffice.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/fakes/FakePostOffice.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,109 @@
+package org.jboss.messaging.tests.unit.core.persistence.fakes;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jboss.messaging.core.filter.Filter;
+import org.jboss.messaging.core.postoffice.Binding;
+import org.jboss.messaging.core.postoffice.FlowController;
+import org.jboss.messaging.core.postoffice.PostOffice;
+import org.jboss.messaging.core.server.Queue;
+import org.jboss.messaging.core.server.QueueFactory;
+import org.jboss.messaging.core.server.ServerMessage;
+import org.jboss.messaging.tests.unit.core.server.impl.fakes.FakeQueueFactory;
+import org.jboss.messaging.util.ConcurrentHashSet;
+import org.jboss.messaging.util.SimpleString;
+
+
+
+/** Maybe this Fake should be moved to postoffice.fakes, but since this
+ * Fake only has the basic needed for StorageManagerTest, I have left it here for now */
+public class FakePostOffice implements PostOffice
+{
+
+ ConcurrentHashMap<SimpleString, Binding> bindings = new ConcurrentHashMap<SimpleString, Binding>();
+
+ QueueFactory queueFactory = new FakeQueueFactory();
+
+ ConcurrentHashSet<SimpleString> addresses = new ConcurrentHashSet<SimpleString>();
+
+ public Binding addBinding(SimpleString address, SimpleString queueName,
+ Filter filter, boolean durable, boolean temporary) throws Exception
+ {
+ Queue queue = queueFactory.createQueue(-1, queueName, filter, durable, temporary);
+ Binding binding = new FakeBinding(address, queue);
+ bindings.put(address, binding);
+ return binding;
+ }
+
+ public boolean addDestination(SimpleString address, boolean temporary)
+ throws Exception
+ {
+ return addresses.addIfAbsent(address);
+ }
+
+ public boolean containsDestination(SimpleString address)
+ {
+ return addresses.contains(address);
+ }
+
+ public Binding getBinding(SimpleString queueName) throws Exception
+ {
+ return bindings.get(queueName);
+ }
+
+ public List<Binding> getBindingsForAddress(SimpleString address)
+ throws Exception
+ {
+ return null;
+ }
+
+ public FlowController getFlowController(SimpleString address)
+ {
+ return null;
+ }
+
+ public Map<SimpleString, List<Binding>> getMappings()
+ {
+ return null;
+ }
+
+ public Set<SimpleString> listAllDestinations()
+ {
+ return null;
+ }
+
+ public Binding removeBinding(SimpleString queueName) throws Exception
+ {
+ return null;
+ }
+
+ public boolean removeDestination(SimpleString address, boolean temporary)
+ throws Exception
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void start() throws Exception
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void stop() throws Exception
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public List<org.jboss.messaging.core.server.MessageReference> route(
+ ServerMessage message) throws Exception
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/impl/timing/StorageManagerTimingTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/impl/timing/StorageManagerTimingTest.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/persistence/impl/timing/StorageManagerTimingTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,285 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * 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.persistence.impl.timing;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
+import org.jboss.messaging.core.config.impl.FileConfiguration;
+import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.core.message.impl.MessageImpl;
+import org.jboss.messaging.core.persistence.impl.journal.JournalStorageManager;
+import org.jboss.messaging.core.remoting.impl.mina.BufferWrapper;
+import org.jboss.messaging.core.server.JournalType;
+import org.jboss.messaging.core.server.Queue;
+import org.jboss.messaging.core.server.impl.ServerMessageImpl;
+import org.jboss.messaging.tests.unit.core.persistence.fakes.FakePostOffice;
+import org.jboss.messaging.tests.util.UnitTestCase;
+import org.jboss.messaging.util.SimpleString;
+
+public class StorageManagerTimingTest extends UnitTestCase
+{
+
+ private static final Logger log = Logger.getLogger(StorageManagerTimingTest.class);
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ assertEquals(0, AsynchronousFileImpl.getTotalMaxIO());
+ }
+
+
+ public void testAIO() throws Exception
+ {
+ // just to do some initial loading.. ignore this rate
+ internalTestStorage(JournalType.ASYNCIO, 1000, 1, 1);
+
+ double rate = internalTestStorage(JournalType.ASYNCIO, 60000, 1, 1)[0];
+ printRates("Rate of AIO, 60000 inserts / commits on every insert", rate);
+
+ rate = internalTestStorage(JournalType.ASYNCIO, 30000, -1, 1)[0];
+ printRates("Rate of AIO, 30000 inserts / single commit at the end", rate);
+
+ rate = internalTestStorage(JournalType.ASYNCIO, 30000, 5, 1)[0];
+ printRates("Rate of AIO, 30000 inserts / commit every 5 recodds", rate);
+
+ rate = internalTestStorage(JournalType.ASYNCIO, 30000, -1, 1)[0];
+ printRates("Rate of AIO, 30000 inserts / single commit at the end (again)", rate);
+
+ }
+
+ public void testAIOMultiThread() throws Exception
+ {
+ double[] rates = internalTestStorage(JournalType.ASYNCIO, 10000, -1, 1);
+ rates = internalTestStorage(JournalType.ASYNCIO, 30000, -1, 5);
+
+ printRates("Rate of AIO, 30000 inserts / single commit at the end", rates);
+
+
+ rates = internalTestStorage(JournalType.ASYNCIO, 5000, 1, 5);
+
+ printRates("Rate of AIO, 30000 inserts / commit on every insert", rates);
+ }
+
+ public void testNIO() throws Exception
+ {
+ // just to do some initial loading.. ignore this rate
+ internalTestStorage(JournalType.NIO, 1000, 1, 1);
+ double rate = internalTestStorage(JournalType.NIO, 1000, 1, 1)[0];
+ printRates("Rate of NIO, 1000 inserts, 1000 commits", rate);
+
+ rate = internalTestStorage(JournalType.NIO, 30000, -1, 1)[0];
+ printRates("Rate of NIO, 30000 inserts / single commit at the end", rate);
+
+ rate = internalTestStorage(JournalType.NIO, 30000, 5, 1)[0];
+ printRates("Rate of NIO, 30000 inserts / commit every 5 records", rate);
+ }
+
+ public void testNIOMultiThread() throws Exception
+ {
+
+ double[] rates = internalTestStorage(JournalType.NIO, 5000, -1, 5);
+
+ printRates("Rate of NIO, 5000 inserts / single commit at the end", rates);
+
+ rates = internalTestStorage(JournalType.NIO, 5000, 1, 5);
+
+ printRates("Rate of NIO, 5000 inserts / commit on every insert", rates);
+
+
+ }
+
+ public double[] internalTestStorage(final JournalType journalType,
+ final long numberOfMessages,
+ final int transInterval,
+ final int numberOfThreads) throws Exception
+ {
+ FileConfiguration configuration = new FileConfiguration();
+
+ configuration.start();
+
+ deleteDirectory(new File(configuration.getBindingsDirectory()));
+ deleteDirectory(new File(configuration.getJournalDirectory()));
+
+ configuration.setJournalType(journalType);
+
+ final JournalStorageManager journal = new JournalStorageManager(configuration);
+ journal.start();
+
+ FakePostOffice office = new FakePostOffice();
+
+ HashMap<Long, Queue> queues = new HashMap<Long, Queue>();
+
+ journal.loadMessages(office, queues);
+
+ final byte[] bytes = new byte[900];
+
+ for (int i=0;i<bytes.length;i++)
+ {
+ bytes[i] = (byte)('a' + (i%20));
+ }
+
+
+ final BufferWrapper buffer = new BufferWrapper(1024);
+ buffer.putBytes(bytes);
+
+ final AtomicLong transactionGenerator = new AtomicLong(1);
+
+ class LocalThread extends Thread
+ {
+ int id;
+ int commits = 1;
+ Exception e;
+ long totalTime = 0;
+ public LocalThread(int id)
+ {
+ super("LocalThread:" + id);
+ this.id = id;
+ }
+
+ public void run()
+ {
+ try
+ {
+ long start = System.currentTimeMillis();
+
+ long trans = transactionGenerator.incrementAndGet();
+ boolean commitPending=false;
+ for (long i=1;i<=numberOfMessages;i++)
+ {
+
+ final SimpleString address = new SimpleString("Destination " + i);
+
+
+ ServerMessageImpl implMsg = new ServerMessageImpl(/* type */ 1, /* durable */ true, /* expiration */ 0,
+ /* timestamp */ 0, /* priority */(byte)0);
+
+ implMsg.putStringProperty(new SimpleString("Key"), new SimpleString("This String is worthless!"));
+
+ implMsg.setMessageID(i);
+ implMsg.setBody(buffer);
+
+ implMsg.setDestination(address);
+
+
+
+ journal.storeMessageTransactional(trans, implMsg);
+
+ commitPending = true;
+
+ if (transInterval>0 && i%transInterval == 0)
+ {
+ journal.commit(trans);
+ commits ++;
+ trans = transactionGenerator.incrementAndGet();
+ commitPending = false;
+ }
+ }
+
+ if (commitPending) journal.commit(trans);
+
+
+ long end = System.currentTimeMillis();
+
+ totalTime = end - start;
+ }
+ catch (Exception e)
+ {
+ log.error(e.getMessage(), e);
+ this.e = e;
+ }
+ }
+ }
+
+ try
+ {
+ LocalThread[] threads = new LocalThread[numberOfThreads];
+
+
+ for (int i = 0; i < numberOfThreads; i++)
+ {
+ threads[i] = new LocalThread(i);
+ }
+
+ for (int i = 0; i < numberOfThreads; i++)
+ {
+ threads[i].start();
+ }
+
+ for (int i = 0; i < numberOfThreads; i++)
+ {
+ threads[i].join();
+ }
+
+ for (int i = 0; i < numberOfThreads; i++)
+ {
+ assertNull(threads[i].e);
+ }
+
+ double rates[] = new double[numberOfThreads];
+
+ for (int i=0; i<numberOfThreads; i++)
+ {
+ rates[i] = (numberOfMessages + threads[i].commits) * 1000 / threads[i].totalTime;
+ }
+
+ return rates;
+ }
+ finally
+ {
+ journal.stop();
+ }
+
+ }
+
+
+ private void printRates(String msg, double rate)
+ {
+ printRates(msg, new double[] { rate });
+ }
+ private void printRates(String msg, double[] rates)
+ {
+ double rate = 0;
+
+ log.info("*************************************************************************");
+ log.info(" " + msg + " ");
+
+ double totalRate = 0;
+ for (int i=0; i<rates.length; i++)
+ {
+ rate = rates[i];
+ totalRate += rate;
+ if (rates.length>1)
+ {
+ log.info( " Thread " + i + ": = " + rate + " inserts/sec (including commits)");
+ }
+ }
+
+ log.info( " Total rate : = " + totalRate + " inserts/sec (including commits)");
+ log.info("*************************************************************************");
+ }
+
+
+}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/util/VariableLatchTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/util/VariableLatchTest.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/util/VariableLatchTest.java 2008-05-12 21:53:04 UTC (rev 4174)
@@ -0,0 +1,236 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * 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.util;
+
+import java.util.concurrent.CountDownLatch;
+
+import junit.framework.TestCase;
+
+import org.jboss.messaging.core.logging.Logger;
+import org.jboss.messaging.util.VariableLatch;
+
+
+/**
+ *
+ * @author clebert
+ *
+ */
+public class VariableLatchTest extends TestCase
+{
+ private static final Logger log = Logger.getLogger(VariableLatchTest.class);
+
+
+ public void testLatchOnSingleThread() throws Exception
+ {
+ VariableLatch latch = new VariableLatch();
+
+ for (int i=1;i<=10000;i++)
+ {
+ latch.up();
+ assertEquals(i, latch.getCount());
+ }
+
+ for (int i=10000; i>0; i--)
+ {
+ assertEquals(i, latch.getCount());
+ latch.down();
+ assertEquals(i-1, latch.getCount());
+ }
+
+ latch.waitCompletion();
+ }
+
+ /**
+ *
+ * This test will open numberOfThreads threads, and add numberOfAdds on the VariableLatch
+ * After those addthreads are finished, the latch count should be numberOfThreads * numberOfAdds
+ * Then it will open numberOfThreads threads again releasing numberOfAdds on the VariableLatch
+ * After those releaseThreads are finished, the latch count should be 0
+ * And all the waiting threads should be finished also
+ *
+ * @throws Exception
+ */
+ public void testLatchOnMultiThread() throws Exception
+ {
+ final VariableLatch latch = new VariableLatch();
+
+ latch.up(); // We hold at least one, so ThreadWaits won't go away
+
+ final int numberOfThreads = 100;
+ final int numberOfAdds = 1000;
+
+ class ThreadWait extends Thread
+ {
+ boolean waiting = true;
+ public void run()
+ {
+ try
+ {
+ latch.waitCompletion(5);
+ }
+ catch (Exception e)
+ {
+ log.error(e);
+ }
+ waiting = false;
+ }
+ }
+
+ class ThreadAdd extends Thread
+ {
+ CountDownLatch latchReady;
+ CountDownLatch latchStart;
+
+ ThreadAdd(CountDownLatch latchReady, CountDownLatch latchStart)
+ {
+ this.latchReady = latchReady;
+ this.latchStart = latchStart;
+ }
+
+ public void run()
+ {
+ try
+ {
+ latchReady.countDown();
+ // Everybody should start at the same time, to worse concurrency effects
+ latchStart.await();
+ for (int i=0; i< numberOfAdds; i++)
+ {
+ latch.up();
+ }
+ }
+ catch (Exception e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ CountDownLatch latchReady = new CountDownLatch(numberOfThreads);
+ CountDownLatch latchStart = new CountDownLatch(1);
+
+ ThreadAdd[] threadAdds = new ThreadAdd[numberOfThreads];
+ ThreadWait waits[] = new ThreadWait[numberOfThreads];
+
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ threadAdds[i] = new ThreadAdd(latchReady, latchStart);
+ threadAdds[i].start();
+ waits[i] = new ThreadWait();
+ waits[i].start();
+ }
+
+ latchReady.await();
+ latchStart.countDown();
+
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ threadAdds[i].join();
+ }
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ assertTrue(waits[i].waiting);
+ }
+
+ assertEquals(numberOfThreads * numberOfAdds + 1, latch.getCount());
+
+ class ThreadDown extends Thread
+ {
+ CountDownLatch latchReady;
+ CountDownLatch latchStart;
+
+ ThreadDown(CountDownLatch latchReady, CountDownLatch latchStart)
+ {
+ this.latchReady = latchReady;
+ this.latchStart = latchStart;
+ }
+
+ public void run()
+ {
+ try
+ {
+ latchReady.countDown();
+ // Everybody should start at the same time, to worse concurrency effects
+ latchStart.await();
+ for (int i=0; i< numberOfAdds; i++)
+ {
+ latch.down();
+ }
+ }
+ catch (Exception e)
+ {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ latchReady = new CountDownLatch(numberOfThreads);
+ latchStart = new CountDownLatch(1);
+
+ ThreadDown down[] = new ThreadDown[numberOfThreads];
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ down[i] = new ThreadDown(latchReady, latchStart);
+ down[i].start();
+ }
+
+ latchReady.await();
+ latchStart.countDown();
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ down[i].join();
+ }
+
+ assertEquals(1, latch.getCount());
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ assertTrue(waits[i].waiting);
+ }
+
+ latch.down();
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ waits[i].join();
+ }
+
+ assertEquals(0, latch.getCount());
+
+ for (int i=0; i< numberOfThreads; i++)
+ {
+ assertFalse (waits[i].waiting);
+ }
+
+
+
+
+ }
+
+
+}
More information about the jboss-cvs-commits
mailing list