[jboss-cvs] JBoss Messaging SVN: r4143 - in trunk: native and 13 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Mon May 5 17:55:56 EDT 2008
Author: clebert.suconic at jboss.com
Date: 2008-05-05 17:55:56 -0400 (Mon, 05 May 2008)
New Revision: 4143
Added:
trunk/native/.cdtproject
trunk/native/.project
trunk/native/.settings/
trunk/native/.settings/org.eclipse.cdt.core.prefs
trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h
trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java
trunk/src/main/org/jboss/messaging/core/journal/IOCallback.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/AbstractSequentialFactory.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/FileFactoryTestBase.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealAIOJournalImplTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealNIOJournalImplTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplAIOTest.java
Removed:
trunk/native/.settings/org.eclipse.cdt.core.prefs
trunk/native/src/org_jboss_messaging_core_asyncio_impl_JlibAIO.h
trunk/src/main/org/jboss/messaging/core/asyncio/impl/JlibAIO.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealJournalImplTest.java
trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFile.java
Modified:
trunk/.classpath
trunk/build-messaging.xml
trunk/native/src/AIOController.cpp
trunk/native/src/AIOController.h
trunk/native/src/AsyncFile.cpp
trunk/native/src/AsyncFile.h
trunk/native/src/JNICallbackAdapter.cpp
trunk/native/src/JNICallbackAdapter.h
trunk/native/src/LibAIOController.cpp
trunk/native/src/Makefile.am
trunk/src/etc/jbm-configuration.xml
trunk/src/main/org/jboss/messaging/core/asyncio/AsynchronousFile.java
trunk/src/main/org/jboss/messaging/core/journal/Journal.java
trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java
trunk/src/main/org/jboss/messaging/core/journal/impl/JournalFileImpl.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/persistence/impl/journal/JournalStorageManager.java
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/FakeJournalImplTest.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/RealJournalImplTest.java
trunk/tests/src/org/jboss/messaging/tests/util/UnitTestCase.java
Log:
JBMESSAGING-1283 - Initial commit of AIO into trunk
Modified: trunk/.classpath
===================================================================
--- trunk/.classpath 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/.classpath 2008-05-05 21:55:56 UTC (rev 4143)
@@ -52,7 +52,6 @@
<classpathentry kind="lib" path="thirdparty/jboss/integration/lib/jboss-transaction-spi.jar"/>
<classpathentry kind="lib" path="thirdparty/jboss/jboss-jaspi-api/lib/jboss-jaspi-api.jar"/>
<classpathentry kind="lib" path="thirdparty/slf4j/api/lib/slf4j-api-1.4.3.jar"/>
- <classpathentry kind="lib" path="tests/lib/jdbc-drivers/mysql-connector-java-5.1.5-bin.jar"/>
<classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
<classpathentry kind="var" path="ANT_HOME/lib/ant-junit.jar"/>
<classpathentry kind="lib" path="thirdparty/jboss/common/lib/jboss-common.jar"/>
Modified: trunk/build-messaging.xml
===================================================================
--- trunk/build-messaging.xml 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/build-messaging.xml 2008-05-05 21:55:56 UTC (rev 4143)
@@ -623,6 +623,7 @@
timeout="${junit.timeout}">
<jvmarg value="-Xmx1024M"/>
+ <jvmarg value="-Djava.library.path=native/src/.libs"/>
<!--<jvmarg line="-Xmx512M -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"/>-->
<!--<jvmarg value="-ea"/>-->
<sysproperty key="jbm.remoting.disable.invm" value="${disable.invm}"/>
@@ -726,4 +727,4 @@
<echo message="${test.execution.classpath.unix}" file="${test.execution.classpath.file}"/>
</target>
-</project>
\ No newline at end of file
+</project>
Copied: trunk/native/.cdtproject (from rev 4128, branches/trunk_tmp_aio/native/.cdtproject)
===================================================================
--- trunk/native/.cdtproject (rev 0)
+++ trunk/native/.cdtproject 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<?eclipse-cdt version="2.0"?>
+<cdtproject id="org.eclipse.cdt.make.core.make">
+ <extension point="org.eclipse.cdt.core.BinaryParser" id="org.eclipse.cdt.core.ELF"/>
+ <data>
+ <item id="scannerConfiguration">
+ <autodiscovery enabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile" problemReportingEnabled="true"/>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="true" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction useDefault="true" command="gcc" arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}"/>
+ <parser enabled="true"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+ <buildOutputProvider>
+ <openAction enabled="false" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="makefileGenerator">
+ <runAction useDefault="true" command="make" arguments="-f ${project_name}_scd.mk"/>
+ <parser enabled="false"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="false" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction useDefault="true" command="gcc" arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}"/>
+ <parser enabled="false"/>
+ </scannerInfoProvider>
+ </profile>
+ <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+ <buildOutputProvider>
+ <openAction enabled="false" filePath=""/>
+ <parser enabled="true"/>
+ </buildOutputProvider>
+ <scannerInfoProvider id="specsFile">
+ <runAction useDefault="true" command="gcc" arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}"/>
+ <parser enabled="false"/>
+ </scannerInfoProvider>
+ </profile>
+ </item>
+ <item id="org.eclipse.cdt.core.pathentry">
+ <pathentry kind="src" path=""/>
+ <pathentry kind="out" path=""/>
+ <pathentry kind="con" path="org.eclipse.cdt.make.core.DISCOVERED_SCANNER_INFO"/>
+ </item>
+ </data>
+</cdtproject>
\ No newline at end of file
Copied: trunk/native/.project (from rev 4128, branches/trunk_tmp_aio/native/.project)
===================================================================
--- trunk/native/.project (rev 0)
+++ trunk/native/.project 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>JBM-native</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.make.core.makeBuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.stopOnError</key>
+ <value>false</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.auto</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.command</key>
+ <value>make</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+ <value>false</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.append_environment</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.clean</key>
+ <value>clean</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.arguments</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.build.target.inc</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.core.errorOutputParser</key>
+ <value>org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser;</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableFullBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.environment</key>
+ <value></value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.make.core.ScannerConfigBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.make.core.makeNature</nature>
+ <nature>org.eclipse.cdt.make.core.ScannerConfigNature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ </natures>
+</projectDescription>
Copied: trunk/native/.settings (from rev 4128, branches/trunk_tmp_aio/native/.settings)
Deleted: trunk/native/.settings/org.eclipse.cdt.core.prefs
===================================================================
--- branches/trunk_tmp_aio/native/.settings/org.eclipse.cdt.core.prefs 2008-04-28 19:03:12 UTC (rev 4128)
+++ trunk/native/.settings/org.eclipse.cdt.core.prefs 2008-05-05 21:55:56 UTC (rev 4143)
@@ -1,3 +0,0 @@
-#Mon Apr 28 10:33:08 GMT-05:00 2008
-eclipse.preferences.version=1
-indexerId=org.eclipse.cdt.core.domsourceindexer
Copied: trunk/native/.settings/org.eclipse.cdt.core.prefs (from rev 4128, branches/trunk_tmp_aio/native/.settings/org.eclipse.cdt.core.prefs)
===================================================================
--- trunk/native/.settings/org.eclipse.cdt.core.prefs (rev 0)
+++ trunk/native/.settings/org.eclipse.cdt.core.prefs 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,3 @@
+#Mon Apr 28 10:33:08 GMT-05:00 2008
+eclipse.preferences.version=1
+indexerId=org.eclipse.cdt.core.domsourceindexer
Modified: trunk/native/src/AIOController.cpp
===================================================================
--- trunk/native/src/AIOController.cpp 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/AIOController.cpp 2008-05-05 21:55:56 UTC (rev 4143)
@@ -27,7 +27,7 @@
{
}
-void AIOController::log(THREAD_CONTEXT threadContext, short level, char * message)
+void AIOController::log(THREAD_CONTEXT threadContext, short level, const char * message)
{
jmethodID methodID = 0;
Modified: trunk/native/src/AIOController.h
===================================================================
--- trunk/native/src/AIOController.h 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/AIOController.h 2008-05-05 21:55:56 UTC (rev 4143)
@@ -41,7 +41,7 @@
/*
* level = 0-error, 1-warn, 2-info, 3-debug
*/
- void log(THREAD_CONTEXT threadContext, short level, char * message);
+ void log(THREAD_CONTEXT threadContext, short level, const char * message);
int fileHandle;
AsyncFile fileOutput;
Modified: trunk/native/src/AsyncFile.cpp
===================================================================
--- trunk/native/src/AsyncFile.cpp 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/AsyncFile.cpp 2008-05-05 21:55:56 UTC (rev 4143)
@@ -81,14 +81,16 @@
#endif
events = (struct io_event *)malloc (maxIO * sizeof (struct io_event));
+
+ if (events == 0)
+ {
+ throw AIOException (1, "Can't allocate ioEvents");
+ }
}
AsyncFile::~AsyncFile()
{
- ::pthread_mutex_destroy(&fileMutex);
- ::pthread_mutex_destroy(&pollerMutex);
- free(events);
if (io_queue_release(aioContext))
{
throw AIOException(2,"Can't release aio");
@@ -97,8 +99,16 @@
{
throw AIOException(2,"Can't close file");
}
+ free(events);
+ ::pthread_mutex_destroy(&fileMutex);
+ ::pthread_mutex_destroy(&pollerMutex);
}
+int isException (THREAD_CONTEXT threadContext)
+{
+ return JNI_ENV(threadContext)->ExceptionOccurred() != 0;
+}
+
void AsyncFile::pollEvents(THREAD_CONTEXT threadContext)
{
@@ -114,8 +124,13 @@
while (pollerRunning)
{
- int result = io_getevents(this->aioContext, 1, maxIO, events, &oneSecond);
+ if (isException(threadContext))
+ {
+ return;
+ }
+ int result = io_getevents(this->aioContext, 1, maxIO, events, 0);
+
#ifdef DEBUG
fprintf (stderr, "poll, pollerRunning=%d\n", pollerRunning); fflush(stderr);
#endif
@@ -134,39 +149,40 @@
struct iocb * iocbp = events[i].obj;
- CallbackAdapter * adapter = (CallbackAdapter *) iocbp->data;
-
- long result = events[i].res;
- if (result < 0)
+ if (iocbp->data == (void *) -1)
{
- std::string strerror = io_error(result);
- adapter->onError(threadContext, result, strerror);
+ pollerRunning = 0;
+// controller->log(threadContext, 2, "Received poller request to stop");
}
else
{
- adapter->completeBlock(threadContext);
- adapter->deleteRef(threadContext);
+ CallbackAdapter * adapter = (CallbackAdapter *) iocbp->data;
+
+ long result = events[i].res;
+ if (result < 0)
+ {
+ std::string strerror = io_error(result);
+ adapter->onError(threadContext, result, strerror);
+ }
+ else
+ {
+ adapter->completeBlock(threadContext);
+ adapter->deleteRef(threadContext);
+ }
}
delete iocbp;
}
}
- controller->log(threadContext, 2, "Poller finished execution");
+// controller->log(threadContext, 2, "Poller finished execution");
}
-void AsyncFile::preAllocate(THREAD_CONTEXT threadContext, int blocks, size_t size)
+void AsyncFile::preAllocate(THREAD_CONTEXT , off_t position, int blocks, size_t size, int fillChar)
{
- size_t currentSize = lseek (fileHandle, 0, SEEK_END);
-
- if (currentSize >= blocks * size)
- {
- controller->log(threadContext,2,"File being reused");
- return;
- }
-
+
if (size % ALIGNMENT != 0)
{
throw AIOException (101, "You can only pre allocate files in multiples of 512");
@@ -178,10 +194,10 @@
throw AIOException(10, "Error on posix_memalign");
}
- memset(preAllocBuffer, 0, size);
+ memset(preAllocBuffer, fillChar, size);
- if (::lseek (fileHandle, 0, SEEK_SET) < 0) throw AIOException (11, "Error positioning the file");
+ if (::lseek (fileHandle, position, SEEK_SET) < 0) throw AIOException (11, "Error positioning the file");
for (int i=0; i<blocks; i++)
{
@@ -191,7 +207,7 @@
}
}
- if (::lseek (fileHandle, 0, SEEK_SET) < 0) throw AIOException (11, "Error positioning the file");
+ if (::lseek (fileHandle, position, SEEK_SET) < 0) throw AIOException (11, "Error positioning the file");
free (preAllocBuffer);
}
@@ -285,7 +301,22 @@
void AsyncFile::stopPoller(THREAD_CONTEXT threadContext)
{
pollerRunning = 0;
- controller->log(threadContext, 2,"Setting poller to stop");
+
+
+ struct iocb * iocb = new struct iocb();
+ ::io_prep_pwrite(iocb, fileHandle, 0, 0, 0);
+ iocb->data = (void *) -1;
+
+ int result = 0;
+
+ while ((result = ::io_submit(aioContext, 1, &iocb)) == (-EAGAIN))
+ {
+ fprintf(stderr, "Couldn't send request to stop poller, trying again");
+ controller->log(threadContext, 1, "Couldn't send request to stop poller, trying again");
+ ::usleep(WAIT_FOR_SPOT);
+ }
+
+// controller->log(threadContext, 2,"Sent data to stop");
// It will wait the Poller to gives up its lock
LockClass lock(&pollerMutex);
}
Modified: trunk/native/src/AsyncFile.h
===================================================================
--- trunk/native/src/AsyncFile.h 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/AsyncFile.h 2008-05-05 21:55:56 UTC (rev 4143)
@@ -79,9 +79,8 @@
// Finishes the polling thread (if any) and return
void stopPoller(THREAD_CONTEXT threadContext);
+ void preAllocate(THREAD_CONTEXT threadContext, off_t position, int blocks, size_t size, int fillChar);
- void preAllocate(THREAD_CONTEXT threadContext, int numberOfBlocks, size_t size);
-
void pollEvents(THREAD_CONTEXT threadContext);
};
Modified: trunk/native/src/JNICallbackAdapter.cpp
===================================================================
--- trunk/native/src/JNICallbackAdapter.cpp 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/JNICallbackAdapter.cpp 2008-05-05 21:55:56 UTC (rev 4143)
@@ -22,10 +22,11 @@
#include <iostream>
#include "JavaUtilities.h"
-JNICallbackAdapter::JNICallbackAdapter(AIOController * _controller, jobject _obj) : CallbackAdapter(), refs(1)
+JNICallbackAdapter::JNICallbackAdapter(AIOController * _controller, jobject _callback, jobject _fileController) : CallbackAdapter(), refs(1)
{
controller = _controller;
- obj = _obj;
+ callback = _callback;
+ fileController = _fileController;
}
JNICallbackAdapter::~JNICallbackAdapter()
@@ -34,7 +35,7 @@
void JNICallbackAdapter::done(THREAD_CONTEXT threadContext)
{
- JNI_ENV(threadContext)->CallVoidMethod(obj,controller->done);
+ JNI_ENV(threadContext)->CallVoidMethod(fileController, controller->done, callback);
return;
}
@@ -42,10 +43,11 @@
{
controller->log(threadContext, 0, "Libaio event generated errors, callback object was informed about it");
jstring strError = JNI_ENV(threadContext)->NewStringUTF(error.data());
- JNI_ENV(threadContext)->CallVoidMethod(obj, controller->error, (jint)errorCode, strError);
+ JNI_ENV(threadContext)->CallVoidMethod(fileController, controller->error, callback, (jint)errorCode, strError);
}
void JNICallbackAdapter::destroy(THREAD_CONTEXT threadContext)
{
- JNI_ENV(threadContext)->DeleteGlobalRef(obj);
+ JNI_ENV(threadContext)->DeleteGlobalRef(callback);
+ JNI_ENV(threadContext)->DeleteGlobalRef(fileController);
}
Modified: trunk/native/src/JNICallbackAdapter.h
===================================================================
--- trunk/native/src/JNICallbackAdapter.h 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/JNICallbackAdapter.h 2008-05-05 21:55:56 UTC (rev 4143)
@@ -31,13 +31,14 @@
{
private:
AIOController * controller;
- jobject obj;
+ jobject callback;
+ jobject fileController;
int refs;
void destroy(THREAD_CONTEXT threadContext);
public:
// _ob must be a global Reference (use createGloblReferente before calling the constructor)
- JNICallbackAdapter(AIOController * _controller, jobject _ob);
+ JNICallbackAdapter(AIOController * _controller, jobject _callback, jobject _fileController);
virtual ~JNICallbackAdapter();
void done(THREAD_CONTEXT threadContext);
void onError(THREAD_CONTEXT threadContext, long error, std::string error);
Modified: trunk/native/src/LibAIOController.cpp
===================================================================
--- trunk/native/src/LibAIOController.cpp 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/LibAIOController.cpp 2008-05-05 21:55:56 UTC (rev 4143)
@@ -25,7 +25,7 @@
#include <string>
-#include "org_jboss_messaging_core_asyncio_impl_JlibAIO.h"
+#include "org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h"
#include "JavaUtilities.h"
@@ -41,18 +41,18 @@
* Method: init
* Signature: (Ljava/lang/String;Ljava/lang/Class;)J
*/
-JNIEXPORT jlong JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_init
- (JNIEnv * env, jclass, jstring jstrFileName, jclass callbackClass, jint maxIO, jobject logger)
+JNIEXPORT jlong JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_init
+ (JNIEnv * env, jclass clazz, jstring jstrFileName, jint maxIO, jobject logger)
{
try
{
std::string fileName = convertJavaString(env, jstrFileName);
AIOController * controller = new AIOController(fileName, (int) maxIO);
- controller->done = env->GetMethodID(callbackClass,"done","()V");
+ controller->done = env->GetMethodID(clazz,"callbackDone","(Lorg/jboss/messaging/core/asyncio/AIOCallback;)V");
if (!controller->done) return 0;
- controller->error = env->GetMethodID(callbackClass, "onError", "(ILjava/lang/String;)V");
+ controller->error = env->GetMethodID(clazz, "callbackError", "(Lorg/jboss/messaging/core/asyncio/AIOCallback;ILjava/lang/String;)V");
if (!controller->error) return 0;
jclass loggerClass = env->GetObjectClass(logger);
@@ -64,7 +64,7 @@
controller->logger = env->NewGlobalRef(logger);
- controller->log(env,4, "Controller initialized");
+// controller->log(env,4, "Controller initialized");
return (jlong)controller;
}
@@ -74,15 +74,28 @@
}
}
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_read
- (JNIEnv *env, jclass, jlong controllerAddress, jlong position, jlong size, jobject jbuffer, jobject callback)
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_read
+ (JNIEnv *env, jobject objThis, jlong controllerAddress, jlong position, jlong size, jobject jbuffer, jobject callback)
{
try
{
AIOController * controller = (AIOController *) controllerAddress;
void * buffer = env->GetDirectBufferAddress(jbuffer);
- CallbackAdapter * adapter = new JNICallbackAdapter(controller, env->NewGlobalRef(callback));
+ if (buffer == 0)
+ {
+ throwException(env, "java/lang/IllegalStateException", "Invalid Direct Buffer used");
+ return;
+ }
+
+ if (((long)buffer) % 512)
+ {
+ throwException(env, "java/lang/IllegalStateException", "Buffer not aligned for use with DMA");
+ return;
+ }
+
+ CallbackAdapter * adapter = new JNICallbackAdapter(controller, env->NewGlobalRef(callback), env->NewGlobalRef(objThis));
+
controller->fileOutput.read(env, position, (size_t)size, buffer, adapter);
}
catch (AIOException& e)
@@ -91,15 +104,21 @@
}
}
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_write
- (JNIEnv *env, jclass, jlong controllerAddress, jlong position, jlong size, jobject jbuffer, jobject callback)
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_write
+ (JNIEnv *env, jobject objThis, jlong controllerAddress, jlong position, jlong size, jobject jbuffer, jobject callback)
{
try
{
AIOController * controller = (AIOController *) controllerAddress;
void * buffer = env->GetDirectBufferAddress(jbuffer);
- CallbackAdapter * adapter = new JNICallbackAdapter(controller, env->NewGlobalRef(callback));
+ if (buffer == 0)
+ {
+ throwException(env, "java/lang/IllegalStateException", "Invalid Direct Buffer used");
+ return;
+ }
+ CallbackAdapter * adapter = new JNICallbackAdapter(controller, env->NewGlobalRef(callback), env->NewGlobalRef(objThis));
+
controller->fileOutput.write(env, position, (size_t)size, buffer, adapter);
}
catch (AIOException& e)
@@ -110,7 +129,7 @@
-JNIEXPORT void Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_internalPollEvents
+JNIEXPORT void Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_internalPollEvents
(JNIEnv *env, jclass, jlong controllerAddress)
{
try
@@ -124,7 +143,7 @@
}
}
-JNIEXPORT jobject JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_newBuffer
+JNIEXPORT jobject JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_newBuffer
(JNIEnv * env, jobject, jlong size)
{
try
@@ -150,7 +169,7 @@
}
}
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_destroyBuffer
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_destroyBuffer
(JNIEnv * env, jobject, jobject jbuffer)
{
void * buffer = env->GetDirectBufferAddress(jbuffer);
@@ -158,14 +177,26 @@
}
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_stopPoller
+ (JNIEnv *env, jclass, jlong controllerAddress)
+{
+ try
+ {
+ AIOController * controller = (AIOController *) controllerAddress;
+ controller->fileOutput.stopPoller(env);
+ }
+ catch (AIOException& e)
+ {
+ throwException(env, "java/lang/RuntimeException", e.what());
+ }
+}
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_closeInternal
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_closeInternal
(JNIEnv *env, jclass, jlong controllerAddress)
{
try
{
AIOController * controller = (AIOController *) controllerAddress;
- controller->fileOutput.stopPoller(env);
controller->destroy(env);
delete controller;
}
@@ -175,13 +206,17 @@
}
}
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_preAllocate
- (JNIEnv * env, jclass, jlong controllerAddress, jint blocks, jlong size)
+
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_fill
+ (JNIEnv * env, jclass, jlong controllerAddress, jlong position, jint blocks, jlong size, jbyte fillChar)
{
try
{
AIOController * controller = (AIOController *) controllerAddress;
- controller->fileOutput.preAllocate(env, blocks, size);
+
+ controller->fileOutput.preAllocate(env, position, blocks, size, fillChar);
+
+ //controller->fileOutput.preAllocate(env, blocks, size);
}
catch (AIOException& e)
{
Modified: trunk/native/src/Makefile.am
===================================================================
--- trunk/native/src/Makefile.am 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/Makefile.am 2008-05-05 21:55:56 UTC (rev 4143)
@@ -4,4 +4,4 @@
libJBMLibAIO_la_SOURCES = AIOController.cpp AIOController.h AIOException.h AsyncFile.cpp \
AsyncFile.h CallbackAdapter.h JAIODatatypes.h JavaUtilities.cpp \
JavaUtilities.h JNICallbackAdapter.cpp JNICallbackAdapter.h LibAIOController.cpp \
- LockClass.h org_jboss_messaging_core_persistence_impl_libaio_jni_impl_JlibAIO
+ LockClass.h org_jboss_messaging_core_persistence_impl_libaio_jni_impl_AsynchronousFileImpl.h
Copied: trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h (from rev 4128, branches/trunk_tmp_aio/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h)
===================================================================
--- trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h (rev 0)
+++ trunk/native/src/org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl.h 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,87 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl */
+
+#ifndef _Included_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+#define _Included_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Inaccessible static: log */
+/* Inaccessible static: loaded */
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: init
+ * Signature: (Ljava/lang/String;ILorg/jboss/messaging/core/logging/Logger;)J
+ */
+JNIEXPORT jlong JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_init
+ (JNIEnv *, jclass, jstring, jint, jobject);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: write
+ * Signature: (JJJLjava/nio/ByteBuffer;Lorg/jboss/messaging/core/asyncio/AIOCallback;)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_write
+ (JNIEnv *, jobject, jlong, jlong, jlong, jobject, jobject);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: read
+ * Signature: (JJJLjava/nio/ByteBuffer;Lorg/jboss/messaging/core/asyncio/AIOCallback;)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_read
+ (JNIEnv *, jobject, jlong, jlong, jlong, jobject, jobject);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: fill
+ * Signature: (JJIJB)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_fill
+ (JNIEnv *, jclass, jlong, jlong, jint, jlong, jbyte);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: closeInternal
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_closeInternal
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: stopPoller
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_stopPoller
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: internalPollEvents
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_internalPollEvents
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: destroyBuffer
+ * Signature: (Ljava/nio/ByteBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_destroyBuffer
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl
+ * Method: newBuffer
+ * Signature: (J)Ljava/nio/ByteBuffer;
+ */
+JNIEXPORT jobject JNICALL Java_org_jboss_messaging_core_asyncio_impl_AsynchronousFileImpl_newBuffer
+ (JNIEnv *, jobject, jlong);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Deleted: trunk/native/src/org_jboss_messaging_core_asyncio_impl_JlibAIO.h
===================================================================
--- trunk/native/src/org_jboss_messaging_core_asyncio_impl_JlibAIO.h 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/native/src/org_jboss_messaging_core_asyncio_impl_JlibAIO.h 2008-05-05 21:55:56 UTC (rev 4143)
@@ -1,79 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class org_jboss_messaging_core_asyncio_impl_JlibAIO */
-
-#ifndef _Included_org_jboss_messaging_core_asyncio_impl_JlibAIO
-#define _Included_org_jboss_messaging_core_asyncio_impl_JlibAIO
-#ifdef __cplusplus
-extern "C" {
-#endif
-/* Inaccessible static: log */
-/* Inaccessible static: loaded */
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: init
- * Signature: (Ljava/lang/String;Ljava/lang/Class;ILorg/jboss/messaging/core/logging/Logger;)J
- */
-JNIEXPORT jlong JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_init
- (JNIEnv *, jclass, jstring, jclass, jint, jobject);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: write
- * Signature: (JJJLjava/nio/ByteBuffer;Lorg/jboss/messaging/core/asyncio/AIOCallback;)V
- */
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_write
- (JNIEnv *, jclass, jlong, jlong, jlong, jobject, jobject);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: read
- * Signature: (JJJLjava/nio/ByteBuffer;Lorg/jboss/messaging/core/asyncio/AIOCallback;)V
- */
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_read
- (JNIEnv *, jclass, jlong, jlong, jlong, jobject, jobject);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: preAllocate
- * Signature: (JIJ)V
- */
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_preAllocate
- (JNIEnv *, jclass, jlong, jint, jlong);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: closeInternal
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_closeInternal
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: internalPollEvents
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_internalPollEvents
- (JNIEnv *, jclass, jlong);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: destroyBuffer
- * Signature: (Ljava/nio/ByteBuffer;)V
- */
-JNIEXPORT void JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_destroyBuffer
- (JNIEnv *, jobject, jobject);
-
-/*
- * Class: org_jboss_messaging_core_asyncio_impl_JlibAIO
- * Method: newBuffer
- * Signature: (J)Ljava/nio/ByteBuffer;
- */
-JNIEXPORT jobject JNICALL Java_org_jboss_messaging_core_asyncio_impl_JlibAIO_newBuffer
- (JNIEnv *, jobject, jlong);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
Modified: trunk/src/etc/jbm-configuration.xml
===================================================================
--- trunk/src/etc/jbm-configuration.xml 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/etc/jbm-configuration.xml 2008-05-05 21:55:56 UTC (rev 4143)
@@ -63,7 +63,7 @@
<create-journal-dir>true</create-journal-dir>
- <journal-type>nio</journal-type>
+ <journal-type>asyncio</journal-type>
<journal-sync>true</journal-sync>
Modified: trunk/src/main/org/jboss/messaging/core/asyncio/AsynchronousFile.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/asyncio/AsynchronousFile.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/asyncio/AsynchronousFile.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -17,30 +17,32 @@
*/
public interface AsynchronousFile
{
-
- void close();
-
- /**
- *
- * Note: If you are using a native Linux implementation, maxIO can't be higher than what's defined on /proc/sys/fs/aio-max-nr, or you would get an error
- * @param fileName
- * @param maxIO The number of max concurrent asynchrnous IO operations. It has to be balanced between the size of your writes and the capacity of your disk.
- */
- void open(String fileName, int maxIO);
-
- /**
- * Warning: This function will perform a synchronous IO, probably translating to a fstat call
- * */
- long size();
-
- void write(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage);
-
- void read(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage);
-
- void preAllocate(int blocks, long size);
-
- ByteBuffer newBuffer(long size);
-
- void destroyBuffer(ByteBuffer buffer);
-
+
+ void close() throws Exception;
+
+ /**
+ *
+ * Note: If you are using a native Linux implementation, maxIO can't be higher than what's defined on /proc/sys/fs/aio-max-nr, or you would get an error
+ * @param fileName
+ * @param maxIO The number of max concurrent asynchrnous IO operations. It has to be balanced between the size of your writes and the capacity of your disk.
+ */
+ void open(String fileName, int maxIO);
+
+ /**
+ * Warning: This function will perform a synchronous IO, probably translating to a fstat call
+ * */
+ long size();
+
+ void write(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage);
+
+ void read(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage);
+
+ void fill(long position, int blocks, long size, byte fillChar);
+
+ ByteBuffer newBuffer(long size);
+
+ void destroyBuffer(ByteBuffer buffer);
+
+ int getBlockSize();
+
}
Copied: trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java (from rev 4128, branches/trunk_tmp_aio/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java)
===================================================================
--- trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/core/asyncio/impl/AsynchronousFileImpl.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,288 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.messaging.core.asyncio.impl;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.jboss.messaging.core.asyncio.AIOCallback;
+import org.jboss.messaging.core.asyncio.AsynchronousFile;
+import org.jboss.messaging.core.logging.Logger;
+
+/**
+ *
+ * @author clebert.suconic at jboss.com
+ * Warning: Case you refactor the name or the package of this class
+ * You need to make sure you also rename the C++ native calls
+ */
+public class AsynchronousFileImpl implements AsynchronousFile
+{
+ private static Logger log = Logger.getLogger(AsynchronousFileImpl.class);
+ private boolean opened = false;
+ private String fileName;
+ private Thread poller;
+ private static boolean loaded = false;
+ private int maxIO;
+
+ Semaphore writeSemaphore;
+
+ ReadWriteLock lock = new ReentrantReadWriteLock();
+ Lock writeLock = lock.writeLock();
+
+ Semaphore pollerSemaphore = new Semaphore(1);
+
+ /**
+ * Warning: Beware of the C++ pointer! It will bite you! :-)
+ */
+ private long handler;
+
+ private static boolean loadLibrary(String name)
+ {
+ try
+ {
+ log.trace(name + " being loaded");
+ System.loadLibrary(name);
+ return true;
+ }
+ catch (Throwable e)
+ {
+ log.trace(name + " -> error loading it", e);
+ return false;
+ }
+
+ }
+
+ static
+ {
+ String libraries[] = new String[] {"JBMLibAIO", "JBMLibAIO32", "JBMLibAIO64"};
+
+
+ for (String library: libraries)
+ {
+ if (loadLibrary(library))
+ {
+ loaded = true;
+ break;
+ }
+ }
+
+ if (!loaded)
+ {
+ log.debug("Couldn't locate LibAIO Wrapper");
+ }
+ }
+
+ public static boolean isLoaded()
+ {
+ return loaded;
+ }
+
+
+
+
+ public void open(String fileName, int maxIO)
+ {
+ try
+ {
+ writeLock.lock();
+ this.maxIO = maxIO;
+
+ this.writeSemaphore = new Semaphore(maxIO);
+
+ if (opened)
+ {
+ throw new IllegalStateException("AsynchronousFile is already opened");
+ }
+ opened = true;
+ this.fileName=fileName;
+ handler = init (fileName, maxIO, log);
+ startPoller();
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
+ }
+
+ class PollerThread extends Thread
+ {
+ PollerThread ()
+ {
+ super("NativePoller for " + fileName);
+ }
+ public void run()
+ {
+ // informing caller that this thread already has the lock
+ try
+ {
+ pollEvents();
+ }
+ finally
+ {
+ pollerSemaphore.release();
+ }
+ }
+ }
+
+ public void close() throws Exception
+ {
+ checkOpened();
+
+ writeLock.lock();
+ writeSemaphore.acquire(maxIO);
+ stopPoller(handler);
+ // We need to make sure we won't call close until Poller is completely done, or we might get beautiful GPFs
+ try
+ {
+ pollerSemaphore.acquire();
+ closeInternal(handler);
+ opened = false;
+ handler = 0;
+ }
+ finally
+ {
+ writeLock.unlock();
+ pollerSemaphore.release();
+ }
+ }
+
+
+ public void write(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage)
+ {
+ checkOpened();
+ this.writeSemaphore.acquireUninterruptibly();
+ try
+ {
+ write (handler, position, size, directByteBuffer, aioPackage);
+ }
+ catch (RuntimeException e)
+ {
+ writeSemaphore.release();
+ throw e;
+ }
+
+ }
+
+ public void read(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage)
+ {
+ checkOpened();
+ this.writeSemaphore.acquireUninterruptibly();
+ try
+ {
+ read (handler, position, size, directByteBuffer, aioPackage);
+ }
+ catch (RuntimeException e)
+ {
+ writeSemaphore.release();
+ throw e;
+ }
+
+ }
+
+ public long size()
+ {
+ checkOpened();
+ // TODO: wire this method to ftell
+ return 0;
+ }
+
+ public void fill(long position, int blocks, long size, byte fillChar)
+ {
+ checkOpened();
+ fill(handler, position, blocks, size, fillChar);
+ }
+
+ public int getBlockSize()
+ {
+ return 512;
+ }
+
+
+ /** The JNI layer will call this method, so we could use it to unlock readWriteLocks held in the java layer */
+ @SuppressWarnings("unused") // Called by the JNI layer.. just ignore the warning
+ private void callbackDone(AIOCallback callback)
+ {
+ writeSemaphore.release();
+ callback.done();
+ }
+
+ @SuppressWarnings("unused") // Called by the JNI layer.. just ignore the warning
+ private void callbackError(AIOCallback callback, int errorCode, String errorMessage)
+ {
+ writeSemaphore.release();
+ callback.onError(errorCode, errorMessage);
+ }
+
+ private void pollEvents()
+ {
+ if (!opened)
+ {
+ return;
+ }
+ internalPollEvents(handler);
+ }
+
+ private synchronized void startPoller()
+ {
+ checkOpened();
+
+ poller = new PollerThread();
+ try
+ {
+ this.pollerSemaphore.acquire();
+ poller.start();
+ }
+ catch (Exception ex)
+ {
+ log.error(ex.getMessage(), ex);
+ }
+ }
+
+
+
+ private void checkOpened()
+ {
+ if (!opened)
+ {
+ throw new RuntimeException("File is not opened");
+ }
+ }
+
+ /**
+ * I'm sending aioPackageClazz here, as you could have multiple classLoaders with the same class, and I don't want the hassle of doing classLoading in the Native layer
+ */
+ @SuppressWarnings("unchecked")
+ private static native long init(String fileName, int maxIO, Logger logger);
+
+ private native void write(long handle, long position, long size, ByteBuffer buffer, AIOCallback aioPackage);
+
+ private native void read(long handle, long position, long size, ByteBuffer buffer, AIOCallback aioPackage);
+
+ private static native void fill(long handle, long position, int blocks, long size, byte fillChar);
+
+ private static native void closeInternal(long handler);
+
+ private static native void stopPoller(long handler);
+
+ /** Poll asynchrounous events from internal queues */
+ private static native void internalPollEvents(long handler);
+
+ // Should we make this method static?
+ public native void destroyBuffer(ByteBuffer buffer);
+
+ // Should we make this method static?
+ public native ByteBuffer newBuffer(long size);
+
+
+
+
+
+}
Deleted: trunk/src/main/org/jboss/messaging/core/asyncio/impl/JlibAIO.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/asyncio/impl/JlibAIO.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/asyncio/impl/JlibAIO.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -1,158 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.messaging.core.asyncio.impl;
-
-import java.nio.ByteBuffer;
-
-import org.jboss.messaging.core.asyncio.AIOCallback;
-import org.jboss.messaging.core.asyncio.AsynchronousFile;
-import org.jboss.messaging.core.logging.Logger;
-
-/**
- *
- * @author clebert.suconic at jboss.com
- * Warning: Case you refactor the name or the package of this class
- * You need to make sure you also rename the C++ native calls
- */
-public class JlibAIO implements AsynchronousFile
-{
- private static Logger log = Logger.getLogger(JlibAIO.class);
- private boolean opened = false;
- private String fileName;
- private Thread poller;
- private static boolean loaded = true;
-
- /**
- * Warning: Beware of the C++ pointer! It will bite you! :-)
- */
- private long handler;
-
- static
- {
- try
- {
- log.info("JLibAIO being loaded");
- System.loadLibrary("JBMLibAIO");
- }
- catch (Throwable e)
- {
- log.error(e.getLocalizedMessage(), e);
- loaded = false;
- }
- }
-
- public static boolean isLoaded()
- {
- return loaded;
- }
-
-
-
-
- public void open(String fileName, int maxIO)
- {
- opened = true;
- this.fileName=fileName;
- handler = init (fileName, AIOCallback.class, maxIO, log);
- startPoller();
- }
-
- class PollerThread extends Thread
- {
- PollerThread ()
- {
- super("NativePoller for " + fileName);
- }
- public void run()
- {
- pollEvents();
- }
- }
-
- private void startPoller()
- {
- checkOpened();
- poller = new PollerThread();
- poller.start();
- }
-
- public void close()
- {
- checkOpened();
- opened = false;
- closeInternal(handler);
- handler = 0;
- }
-
-
- public void write(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage)
- {
- checkOpened();
- write (handler, position, size, directByteBuffer, aioPackage);
-
- }
-
- public void read(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioPackage)
- {
- checkOpened();
- read (handler, position, size, directByteBuffer, aioPackage);
-
- }
-
- public long size()
- {
- checkOpened();
- // TODO: wire this method to ftell
- return 0;
- }
-
- public void preAllocate(int blocks, long size)
- {
- checkOpened();
- preAllocate(handler, blocks, size);
- }
-
- private void pollEvents()
- {
- checkOpened();
- internalPollEvents(handler);
- }
-
- private void checkOpened()
- {
- if (!opened)
- {
- throw new RuntimeException("File is not opened");
- }
- }
-
- /**
- * I'm sending aioPackageClazz here, as you could have multiple classLoaders with the same class, and I don't want the hassle of doing classLoading in the Native layer
- */
- @SuppressWarnings("unchecked")
- private static native long init(String fileName, Class aioPackageClazz, int maxIO, Logger logger);
-
- private static native void write(long handle, long position, long size, ByteBuffer buffer, AIOCallback aioPackage);
-
- private static native void read(long handle, long position, long size, ByteBuffer buffer, AIOCallback aioPackage);
-
- private static native void preAllocate(long handle, int blocks, long size);
-
- private static native void closeInternal(long handler);
-
- /** Poll asynchrounous events from internal queues */
- private static native void internalPollEvents(long handler);
-
- // Should we make this method static?
- public native void destroyBuffer(ByteBuffer buffer);
-
- // Should we make this method static?
- public native ByteBuffer newBuffer(long size);
-
-
-}
Copied: trunk/src/main/org/jboss/messaging/core/journal/IOCallback.java (from rev 4128, branches/trunk_tmp_aio/src/main/org/jboss/messaging/core/journal/IOCallback.java)
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/IOCallback.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/core/journal/IOCallback.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,15 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.messaging.core.journal;
+
+import org.jboss.messaging.core.asyncio.AIOCallback;
+
+public interface IOCallback extends AIOCallback
+{
+
+}
Modified: trunk/src/main/org/jboss/messaging/core/journal/Journal.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/Journal.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/journal/Journal.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -36,6 +36,9 @@
{
// Non transactional operations
+ // TODO: Implement callbacks
+ void appendAddRecord(long id, byte[] record, IOCallback callback) throws Exception;
+
void appendAddRecord(long id, byte[] record) throws Exception;
void appendUpdateRecord(long id, byte[] record) throws Exception;
@@ -57,7 +60,7 @@
void appendPrepareRecord(long txID) throws Exception;
void appendRollbackRecord(long txID) throws Exception;
-
+
// Load
void load(List<RecordInfo> committedRecords,
@@ -69,4 +72,6 @@
void stopReclaimer();
+ int getAlignment() throws Exception;
+
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/journal/SequentialFile.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -37,17 +37,29 @@
*/
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[]);
}
Copied: trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java (from rev 4128, branches/trunk_tmp_aio/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java)
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFile.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,239 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.messaging.core.journal.impl;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicLong;
+
+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;
+
+public class AIOSequentialFile implements SequentialFile
+{
+
+ String journalDir;
+ String fileName;
+
+ AsynchronousFile aioFile;
+
+ AtomicLong position = new AtomicLong(0);
+
+ public AIOSequentialFile(String journalDir, String fileName) throws Exception
+ {
+ this.journalDir = journalDir;
+ this.fileName = fileName;
+ }
+
+ public int getAlignment() throws Exception
+ {
+ checkOpened();
+ return aioFile.getBlockSize();
+ }
+
+ public int calculateBlockStart(int position) throws Exception
+ {
+ int alignment = getAlignment();
+
+ int pos = ((position / alignment) + (position % alignment != 0 ? 1 : 0)) * alignment;
+
+ return pos;
+ }
+
+
+
+ public void close() throws Exception
+ {
+ checkOpened();
+ aioFile.close();
+ aioFile = null;
+
+ }
+
+ public void delete() throws Exception
+ {
+ if (aioFile != null)
+ {
+ aioFile.close();
+ aioFile = null;
+ }
+
+ File file = new File(journalDir + "/" + fileName);
+ file.delete();
+ }
+
+ public void fill(int position, int size, byte fillCharacter)
+ throws Exception
+ {
+ checkOpened();
+
+ int blockSize = aioFile.getBlockSize();
+
+ if (size % (10*1024*1024) == 0)
+ {
+ blockSize = 10*1024*1024;
+ }
+ else
+ if (size % (1024*1024) == 0)
+ {
+ blockSize = 1024*1024;
+ }
+ else
+ if (size % (10*1024) == 0)
+ {
+ blockSize = 10*1024;
+ }
+ else
+ {
+ blockSize = aioFile.getBlockSize();
+ }
+
+ int blocks = size / blockSize;
+ if (size % blockSize != 0)
+ {
+ blocks++;
+ }
+
+ if (position % aioFile.getBlockSize() != 0)
+ {
+ 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);
+
+ }
+
+ public String getFileName()
+ {
+ return fileName;
+ }
+
+ public void open() throws Exception
+ {
+ aioFile = new AsynchronousFileImpl();
+ aioFile.open(journalDir + "/" + fileName, 1000);
+ position.set(0);
+
+ }
+
+ public void position(int pos) throws Exception
+ {
+ position.set(pos);
+
+ }
+
+ public int read(ByteBuffer bytes, IOCallback callback) throws Exception
+ {
+ int bytesToRead = bytes.limit();
+ long positionToRead = position.getAndAdd(bytesToRead);
+
+ bytes.rewind();
+ aioFile.read(positionToRead, bytesToRead, bytes, callback);
+
+ return bytesToRead;
+ }
+
+ public int read(ByteBuffer bytes) throws Exception
+ {
+ WaitCompletion waitCompletion = new WaitCompletion();
+ int bytesRead = read (bytes, waitCompletion);
+
+ waitCompletion.waitLatch();
+
+ if (waitCompletion.errorMessage != null)
+ {
+ throw new MessagingException(waitCompletion.errorCode, waitCompletion.errorMessage);
+ }
+
+ return bytesRead;
+ }
+
+ public int write(ByteBuffer bytes, boolean sync, IOCallback callback)
+ throws Exception
+ {
+ int bytesToWrite = bytes.limit();
+ long positionToWrite = position.getAndAdd(bytesToWrite);
+
+ aioFile.write(positionToWrite, bytesToWrite, bytes, callback);
+ return bytesToWrite;
+ }
+
+ 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;
+ }
+
+ private void checkOpened() throws Exception
+ {
+ if (aioFile == null)
+ {
+ throw new IllegalStateException ("File not opened");
+ }
+ }
+
+ class WaitCompletion implements IOCallback
+ {
+
+ CountDownLatch latch = new CountDownLatch(1);
+
+ String errorMessage;
+ int errorCode = 0;
+
+ public void done()
+ {
+ latch.countDown();
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ System.out.println("OK Error!");
+ this.errorCode = errorCode;
+ this.errorMessage = errorMessage;
+
+ latch.countDown();
+
+ }
+
+ public void waitLatch() throws Exception
+ {
+ latch.await();
+ }
+
+ }
+
+ 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;
+ };
+
+}
Copied: trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java (from rev 4128, branches/trunk_tmp_aio/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java)
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/AIOSequentialFileFactory.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,31 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.messaging.core.journal.impl;
+
+import org.jboss.messaging.core.journal.SequentialFile;
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
+
+public class AIOSequentialFileFactory extends AbstractSequentialFactory
+{
+
+ public AIOSequentialFileFactory(String journalDir)
+ {
+ super(journalDir);
+ }
+
+ public SequentialFile createSequentialFile(String fileName, boolean sync) throws Exception
+ {
+ return new AIOSequentialFile(journalDir, fileName);
+ }
+
+ public static boolean isSupported()
+ {
+ return AsynchronousFileImpl.isLoaded();
+ }
+
+}
Copied: trunk/src/main/org/jboss/messaging/core/journal/impl/AbstractSequentialFactory.java (from rev 4128, branches/trunk_tmp_aio/src/main/org/jboss/messaging/core/journal/impl/AbstractSequentialFactory.java)
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/AbstractSequentialFactory.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/AbstractSequentialFactory.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.messaging.core.journal.impl;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.messaging.core.journal.SequentialFileFactory;
+
+public abstract class AbstractSequentialFactory implements SequentialFileFactory
+{
+ protected final String journalDir;
+
+ public AbstractSequentialFactory(final String journalDir)
+ {
+ this.journalDir = journalDir;
+ }
+
+ public List<String> listFiles(final String extension) throws Exception
+ {
+ File dir = new File(journalDir);
+
+ FilenameFilter fnf = new FilenameFilter()
+ {
+ public boolean accept(File file, String name)
+ {
+ return name.endsWith("." + extension);
+ }
+ };
+
+ String[] fileNames = dir.list(fnf);
+
+ if (fileNames == null)
+ {
+ throw new IOException("Failed to list: " + journalDir);
+ }
+
+ return Arrays.asList(fileNames);
+ }
+
+}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/JournalFileImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/JournalFileImpl.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/JournalFileImpl.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -23,6 +23,7 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.logging.Logger;
@@ -129,6 +130,32 @@
{
return file;
}
+
+ public String toString()
+ {
+ try
+ {
+ return "JournalFileImpl: " + file.getFileName();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return "Error:" + e.toString();
+ }
+ }
-
+ /** Receive debug information about the journal */
+ public String debug()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ for (Entry<JournalFile, Integer> entry: negCounts.entrySet())
+ {
+ builder.append(" file = " + entry.getKey() + " negcount value = " + entry.getValue() + "\n");
+ }
+
+ return builder.toString();
+ }
+
+
}
Modified: trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/JournalImpl.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -39,6 +39,7 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
+import org.jboss.messaging.core.journal.IOCallback;
import org.jboss.messaging.core.journal.PreparedTransactionInfo;
import org.jboss.messaging.core.journal.RecordInfo;
import org.jboss.messaging.core.journal.SequentialFile;
@@ -52,11 +53,14 @@
* A JournalImpl
*
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @author <a href="mailto:clebert.suconic at jboss.com">Clebert Suconic</a>
*
*/
public class JournalImpl implements TestableJournal
{
private static final Logger log = Logger.getLogger(JournalImpl.class);
+ //private static final boolean trace = log.isTraceEnabled();
+ private static final boolean trace = true;
private static final int STATE_STOPPED = 0;
@@ -67,40 +71,62 @@
// The sizes of primitive types
private static final int SIZE_LONG = 8;
-
- private static final int SIZE_INT = 4;
-
- private static final int SIZE_BYTE = 1;
-
- public static final int MIN_FILE_SIZE = 1024;
-
- public static final int MIN_TASK_PERIOD = 1000;
-
- //Record markers - they must be all unique
-
+
+ private static final int SIZE_INT = 4;
+
+ private static final int SIZE_BYTE = 1;
+
+ public static final int MIN_FILE_SIZE = 1024;
+
+ public static final int MIN_TASK_PERIOD = 1000;
+
+ //Record markers - they must be all unique
+
+ 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 byte ADD_RECORD = 11;
+ public static final byte SIZE_UPDATE_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_INT + SIZE_BYTE;
+
public static final byte UPDATE_RECORD = 12;
+ public static final int SIZE_DELETE_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
+
public static final byte DELETE_RECORD = 13;
-
+
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_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;
+
public static final byte DELETE_RECORD_TX = 16;
+ public static final int SIZE_PREPARE_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
+
public static final byte PREPARE_RECORD = 17;
-
+
+
+ public static final byte SIZE_COMMIT_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
+
public static final byte COMMIT_RECORD = 18;
+ public static final byte SIZE_ROLLBACK_RECORD = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
+
public static final byte ROLLBACK_RECORD = 19;
public static final byte DONE = 20;
public static final byte FILL_CHARACTER = 74; // Letter 'J'
-
-
+
+
private final int fileSize;
private final int minFiles;
@@ -114,8 +140,8 @@
public final String filePrefix;
public final String fileExtension;
-
+
private final Queue<JournalFile> dataFiles = new ConcurrentLinkedQueue<JournalFile>();
private final Queue<JournalFile> freeFiles = new ConcurrentLinkedQueue<JournalFile>();
@@ -123,17 +149,17 @@
private Map<Long, PosFiles> posFilesMap = new ConcurrentHashMap<Long, PosFiles>();
private Map<Long, TransactionNegPos> transactionInfos = new ConcurrentHashMap<Long, TransactionNegPos>();
-
-
+
+
/*
* We use a semaphore rather than synchronized since it performs better when contended
*/
//TODO - improve concurrency by allowing concurrent accesses if doesn't change current file
private final Semaphore lock = new Semaphore(1, true);
-
+
private volatile JournalFile currentFile ;
-
+
private volatile int state;
private volatile long lastOrderingID;
@@ -147,8 +173,8 @@
private Reclaimer reclaimer = new Reclaimer();
public JournalImpl(final int fileSize, final int minFiles,
- final boolean sync, final SequentialFileFactory fileFactory, final long taskPeriod,
- final String filePrefix, final String fileExtension)
+ final boolean sync, final SequentialFileFactory fileFactory, final long taskPeriod,
+ final String filePrefix, final String fileExtension)
{
if (fileSize < MIN_FILE_SIZE)
{
@@ -192,12 +218,12 @@
// Journal implementation ----------------------------------------------------------------
- public ByteBuffer allocateBuffer(final int size) throws Exception
- {
- return ByteBuffer.allocateDirect(size);
- }
+ /*public ByteBuffer allocateBuffer(final int size) throws Exception
+ {
+ return ByteBuffer.allocateDirect(size);
+ }*/
- public void appendAddRecord(final long id, final byte[] record) throws Exception
+ public void appendAddRecord(long id, byte[] record, IOCallback callback) throws Exception
{
if (state != STATE_LOADED)
{
@@ -206,20 +232,43 @@
int size = SIZE_BYTE + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
bb.put(ADD_RECORD);
bb.putLong(id);
bb.putInt(record.length);
bb.put(record);
bb.put(DONE);
- bb.flip();
+ bb.rewind();
+ appendRecord(bb, true, callback);
+
+ posFilesMap.put(id, new PosFiles(currentFile));
+ }
+
+ public void appendAddRecord(final long id, 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)
@@ -233,23 +282,23 @@
{
throw new IllegalStateException("Cannot find add info " + id);
}
-
- int size = SIZE_BYTE + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ int size = SIZE_UPDATE_RECORD + record.length;
- bb.put(UPDATE_RECORD);
- bb.putLong(id);
- bb.putInt(record.length);
- bb.put(record);
- bb.put(DONE);
- bb.flip();
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
- appendRecord(bb, true);
+ bb.put(UPDATE_RECORD);
+ bb.putLong(id);
+ bb.putInt(record.length);
+ bb.put(record);
+ bb.put(DONE);
+ bb.rewind();
+ appendRecord(bb, true);
+
posFiles.addUpdateFile(currentFile);
}
-
+
public void appendDeleteRecord(long id) throws Exception
{
if (state != STATE_LOADED)
@@ -266,76 +315,76 @@
posFiles.addDelete(currentFile);
- int size = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
+ int size = SIZE_DELETE_RECORD;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
- bb.put(DELETE_RECORD);
- bb.putLong(id);
- bb.put(DONE);
- bb.flip();
-
- appendRecord(bb, true);
- }
+ bb.put(DELETE_RECORD);
+ bb.putLong(id);
+ bb.put(DONE);
+ bb.rewind();
+
+ appendRecord(bb, true);
+ }
public long getTransactionID()
{
return transactionIDSequence.getAndIncrement();
}
-
+
public void appendAddRecordTransactional(final long txID, final long id,
- final byte[] record) throws Exception
- {
+ final byte[] record) throws Exception
+ {
if (state != STATE_LOADED)
{
throw new IllegalStateException("Journal must be loaded first");
}
- int size = SIZE_BYTE + SIZE_LONG + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE;
-
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
-
+ 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.flip();
+ bb.put(DONE);
+ bb.rewind();
appendRecord(bb, false);
TransactionNegPos tx = getTransactionInfo(txID);
tx.addPos(currentFile, id);
- }
+ }
public void appendUpdateRecordTransactional(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_BYTE + SIZE_LONG + SIZE_LONG + SIZE_INT + record.length + SIZE_BYTE;
+ int size = SIZE_UPDATE_RECORD_TX + record.length;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
- bb.put(UPDATE_RECORD_TX);
- bb.putLong(txID);
- bb.putLong(id);
- bb.putInt(record.length);
- bb.put(record);
- bb.put(DONE);
- bb.flip();
+ bb.put(UPDATE_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 appendDeleteRecordTransactional(final long txID, final long id) throws Exception
{
@@ -344,23 +393,23 @@
throw new IllegalStateException("Journal must be loaded first");
}
- int size = SIZE_BYTE + SIZE_LONG + SIZE_LONG + SIZE_BYTE;
+ int size = SIZE_DELETE_RECORD_TX;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
- bb.put(DELETE_RECORD_TX);
- bb.putLong(txID);
- bb.putLong(id);
- bb.put(DONE);
- bb.flip();
-
- appendRecord(bb, false);
+ bb.put(DELETE_RECORD_TX);
+ bb.putLong(txID);
+ bb.putLong(id);
+ bb.put(DONE);
+ bb.rewind();
+ appendRecord(bb, false);
+
TransactionNegPos tx = getTransactionInfo(txID);
- tx.addNeg(currentFile, id);
- }
-
+ tx.addNeg(currentFile, id);
+ }
+
public void appendPrepareRecord(final long txID) throws Exception
{
if (state != STATE_LOADED)
@@ -375,16 +424,16 @@
throw new IllegalStateException("Cannot find tx with id " + txID);
}
- int size = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
+ int size = SIZE_PREPARE_RECORD;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
- bb.put(PREPARE_RECORD);
- bb.putLong(txID);
- bb.put(DONE);
- bb.flip();
+ bb.put(PREPARE_RECORD);
+ bb.putLong(txID);
+ bb.put(DONE);
+ bb.rewind();
- appendRecord(bb, true);
+ appendRecord(bb, true);
tx.prepare(currentFile);
}
@@ -402,19 +451,19 @@
{
throw new IllegalStateException("Cannot find tx with id " + txID);
}
-
- int size = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ int size = SIZE_COMMIT_RECORD;
- bb.put(COMMIT_RECORD);
- bb.putLong(txID);
- bb.put(DONE);
- bb.flip();
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
- appendRecord(bb, true);
+ bb.put(COMMIT_RECORD);
+ bb.putLong(txID);
+ bb.put(DONE);
+ bb.rewind();
- tx.commit(currentFile);
+ appendRecord(bb, true);
+
+ tx.commit(currentFile);
}
public void appendRollbackRecord(final long txID) throws Exception
@@ -430,24 +479,24 @@
{
throw new IllegalStateException("Cannot find tx with id " + txID);
}
-
- int size = SIZE_BYTE + SIZE_LONG + SIZE_BYTE;
- ByteBuffer bb = ByteBuffer.wrap(new byte[size]);
+ int size = SIZE_ROLLBACK_RECORD;
- bb.put(ROLLBACK_RECORD);
- bb.putLong(txID);
- bb.put(DONE);
- bb.flip();
-
- appendRecord(bb, true);
+ ByteBuffer bb = currentFile.getFile().newBuffer(size);
+ bb.put(ROLLBACK_RECORD);
+ bb.putLong(txID);
+ bb.put(DONE);
+ bb.rewind();
+
+ appendRecord(bb, true);
+
tx.rollback(currentFile);
}
-
+
public synchronized void load(final List<RecordInfo> committedRecords,
- final List<PreparedTransactionInfo> preparedTransactions) throws Exception
- {
+ final List<PreparedTransactionInfo> preparedTransactions) throws Exception
+ {
if (state != STATE_STARTED)
{
throw new IllegalStateException("Journal must be in started state");
@@ -462,21 +511,22 @@
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 = ByteBuffer.wrap(new byte[SIZE_LONG]);
+ ByteBuffer bb = file.newBuffer(SIZE_LONG);
file.read(bb);
- bb.flip();
+ //bb.flip();
+ //bb.rewind();
long orderingID = bb.getLong();
-
+
orderedFiles.add(new JournalFileImpl(file, orderingID));
file.close();
@@ -487,14 +537,14 @@
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));
- }
+ {
+ long id1 = f1.getOrderingID();
+ long id2 = f2.getOrderingID();
+
+ return (id1 < id2 ? -1 : (id1 == id2 ? 0 : 1));
+ }
}
-
+
Collections.sort(orderedFiles, new JournalFileComparator());
int lastDataPos = -1;
@@ -502,11 +552,16 @@
long maxTransactionID = -1;
for (JournalFile file: orderedFiles)
- {
- ByteBuffer bb = ByteBuffer.wrap(new byte[fileSize]);
-
+ {
file.getFile().open();
+ if (trace)
+ {
+ trace("Loading file " + file.getFile().getFileName());
+ }
+
+ ByteBuffer bb = file.getFile().newBuffer(fileSize);
+
int bytesRead = file.getFile().read(bb);
if (bytesRead != fileSize)
@@ -514,13 +569,14 @@
//deal with this better
throw new IllegalStateException("File is wrong size " + bytesRead +
- " expected " + fileSize + " : " + file.getFile().getFileName());
+ " expected " + fileSize + " : " + file.getFile().getFileName());
}
- bb.flip();
+// bb.flip();
+// bb.rewind();
- //First long is the ordering timestamp
- bb.getLong();
+ //First long is the ordering timestamp, we just jump its position
+ bb.position(file.getFile().calculateBlockStart(SIZE_LONG));
boolean hasData = false;
@@ -530,15 +586,18 @@
byte recordType = bb.get();
+
switch(recordType)
{
case ADD_RECORD:
- {
- long id = bb.getLong();
+ {
+ long id = bb.getLong();
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
+ if (trace) log.trace("ADD Record ID = " + id);
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
byte end = bb.get();
if (end != DONE)
@@ -546,22 +605,23 @@
repairFrom(pos, file);
}
else
- {
+ {
records.add(new RecordInfo(id, record, false));
- hasData = true;
-
+ hasData = true;
+
posFilesMap.put(id, new PosFiles(file));
}
-
+
break;
- }
- case UPDATE_RECORD:
+ }
+ case UPDATE_RECORD:
{
- long id = bb.getLong();
+ long id = bb.getLong();
+ if (trace) log.trace("Update Record ID = " + id);
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
byte end = bb.get();
if (end != DONE)
@@ -569,12 +629,12 @@
repairFrom(pos, file);
}
else
- {
- records.add(new RecordInfo(id, record, true));
- hasData = true;
+ {
+ records.add(new RecordInfo(id, record, true));
+ hasData = true;
file.incPosCount();
- PosFiles posFiles = posFilesMap.get(id);
+ PosFiles posFiles = posFilesMap.get(id);
if (posFiles != null)
{
@@ -584,21 +644,23 @@
posFiles.addUpdateFile(file);
}
}
-
+
break;
- }
- case DELETE_RECORD:
+ }
+ case DELETE_RECORD:
{
- long id = bb.getLong();
+ long id = bb.getLong();
byte end = bb.get();
+ if (trace) log.trace("DeleteRecord id=" + id);
+
if (end != DONE)
{
repairFrom(pos, file);
}
else
- {
- recordsToDelete.add(id);
+ {
+ recordsToDelete.add(id);
hasData = true;
PosFiles posFiles = posFilesMap.remove(id);
@@ -606,19 +668,23 @@
if (posFiles != null)
{
posFiles.addDelete(file);
- }
+ }
}
break;
- }
+ }
case ADD_RECORD_TX:
- {
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- long id = bb.getLong();
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
+ {
+ long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ long id = bb.getLong();
+
+ if (trace) log.trace("AddRecordTX txID = " + txID + " , id=" + id);
+
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
byte end = bb.get();
if (end != DONE)
@@ -626,16 +692,16 @@
repairFrom(pos, file);
}
else
- {
+ {
TransactionHolder tx = transactions.get(txID);
if (tx == null)
{
- tx = new TransactionHolder(txID);
+ tx = new TransactionHolder(txID);
transactions.put(txID, tx);
}
- tx.recordInfos.add(new RecordInfo(id, record, false));
+ tx.recordInfos.add(new RecordInfo(id, record, false));
TransactionNegPos tnp = transactionInfos.get(txID);
@@ -648,19 +714,22 @@
tnp.addPos(file, id);
- hasData = true;
+ hasData = true;
}
-
+
break;
- }
+ }
case UPDATE_RECORD_TX:
- {
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- long id = bb.getLong();
- int size = bb.getInt();
- byte[] record = new byte[size];
- bb.get(record);
+ {
+ long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ long id = bb.getLong();
+
+ if (trace) log.trace("UpdateRecordTX txID = " + txID + " , id=" + id);
+
+ int size = bb.getInt();
+ byte[] record = new byte[size];
+ bb.get(record);
byte end = bb.get();
if (end != DONE)
@@ -668,12 +737,12 @@
repairFrom(pos, file);
}
else
- {
+ {
TransactionHolder tx = transactions.get(txID);
if (tx == null)
{
- tx = new TransactionHolder(txID);
+ tx = new TransactionHolder(txID);
transactions.put(txID, tx);
}
@@ -689,17 +758,20 @@
}
tnp.addPos(file, id);
-
- hasData = true;
+
+ hasData = true;
}
-
+
break;
- }
+ }
case DELETE_RECORD_TX:
- {
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
- long id = bb.getLong();
+ {
+ long txID = bb.getLong();
+ maxTransactionID = Math.max(maxTransactionID, txID);
+ long id = bb.getLong();
+
+ if (trace) log.trace("DeleteRecordTX txID = " + txID + " , id=" + id);
+
byte end = bb.get();
if (end != DONE)
@@ -707,16 +779,16 @@
repairFrom(pos, file);
}
else
- {
+ {
TransactionHolder tx = transactions.get(txID);
if (tx == null)
{
- tx = new TransactionHolder(txID);
+ tx = new TransactionHolder(txID);
transactions.put(txID, tx);
}
- tx.recordsToDelete.add(id);
+ tx.recordsToDelete.add(id);
TransactionNegPos tnp = transactionInfos.get(txID);
@@ -729,15 +801,18 @@
tnp.addNeg(file, id);
- hasData = true;
+ hasData = true;
}
-
+
break;
- }
+ }
case PREPARE_RECORD:
{
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
+ long txID = bb.getLong();
+
+ if (trace) log.trace("Prepare txID=" + txID);
+
+ maxTransactionID = Math.max(maxTransactionID, txID);
byte end = bb.get();
if (end != DONE)
@@ -752,7 +827,7 @@
{
throw new IllegalStateException("Cannot find tx with id " + txID);
}
-
+
tx.prepared = true;
TransactionNegPos tnp = transactionInfos.get(txID);
@@ -762,16 +837,19 @@
throw new IllegalStateException("Cannot find tx " + txID);
}
- tnp.prepare(file);
+ tnp.prepare(file);
- hasData = true;
+ hasData = true;
}
break;
}
case COMMIT_RECORD:
{
- long txID = bb.getLong();
+ long txID = bb.getLong();
+
+ if (trace) log.trace("Commit txID=" + txID);
+
maxTransactionID = Math.max(maxTransactionID, txID);
byte end = bb.get();
@@ -785,19 +863,19 @@
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;
+ 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;
}
}
@@ -805,8 +883,11 @@
}
case ROLLBACK_RECORD:
{
- long txID = bb.getLong();
- maxTransactionID = Math.max(maxTransactionID, txID);
+ long txID = bb.getLong();
+
+ if (trace) log.trace("RollbacktxID=" + txID);
+
+ maxTransactionID = Math.max(maxTransactionID, txID);
byte end = bb.get();
if (end != DONE)
@@ -818,24 +899,24 @@
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;
+ {
+ TransactionNegPos tnp = transactionInfos.remove(txID);
+
+ if (tnp == null)
+ {
+ throw new IllegalStateException("Cannot find tx " + txID);
+ }
+
+ tnp.rollback(file);
+
+ hasData = true;
}
}
break;
}
- case FILL_CHARACTER:
- {
+ case FILL_CHARACTER:
+ {
//End of records in file - we check the file only contains fill characters from this point
while (bb.hasRemaining())
{
@@ -848,49 +929,52 @@
}
}
- break;
- }
- default:
+ break;
+ }
+ default:
{
throw new IllegalStateException("Journal " + file.getFile().getFileName() +
- " is corrupt, invalid record type " + recordType);
+ " 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();
+ file.getFile().close();
}
else
- {
+ {
//Empty dataFiles with no data
freeFiles.add(file);
- //Position it ready for writing
- file.getFile().position(SIZE_LONG);
- }
- }
+// //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();
@@ -906,9 +990,9 @@
}
if (currentFile != null)
- {
+ {
currentFile.getFile().open();
-
+
currentFile.getFile().position(lastDataPos);
currentFile.setOffset(lastDataPos);
@@ -916,8 +1000,8 @@
else
{
currentFile = freeFiles.remove();
- }
-
+ }
+
for (RecordInfo record: records)
{
if (!recordsToDelete.contains(record.id))
@@ -953,64 +1037,77 @@
preparedTransactions.add(info);
}
}
-
+
state = STATE_LOADED;
+ }
+
+ public int getAlignment() throws Exception
+ {
+ return this.currentFile.getFile().getAlignment();
}
+ public synchronized void checkReclaimStatus() throws Exception
+ {
+ JournalFile[] files = new JournalFile[dataFiles.size()];
+
+ reclaimer.scan(dataFiles.toArray(files));
+
+ }
+
// TestableJournal implementation --------------------------------------------------------------
-
+
public synchronized void checkAndReclaimFiles() throws Exception
- {
- JournalFile[] files = new JournalFile[dataFiles.size()];
+ {
+ checkReclaimStatus();
- reclaimer.scan(dataFiles.toArray(files));
+ for (JournalFile file: dataFiles)
+ {
+ if (file.isCanReclaim())
+ {
+ //File can be reclaimed or deleted
- for (JournalFile file: dataFiles)
- {
- if (file.isCanReclaim())
- {
- //File can be reclaimed or deleted
-
- dataFiles.remove(file);
-
- //FIXME - size() involves a scan!!!
- if (freeFiles.size() + dataFiles.size() + 1 < minFiles)
- {
- //Re-initialise it
-
- long newOrderingID = generateOrderingID();
-
- ByteBuffer bb = ByteBuffer.wrap(new byte[SIZE_LONG]);
-
- bb.putLong(newOrderingID);
-
- SequentialFile sf = file.getFile();
-
- sf.open();
-
- //Note we MUST re-fill it - otherwise we won't be able to detect corrupt records
-
- //TODO - if we can avoid this somehow would be good, since filling the file is a heavyweight
- //operation and can impact other IO operations on the disk
- sf.fill(0, fileSize, FILL_CHARACTER);
-
- sf.write(bb, true);
-
- JournalFile jf = new JournalFileImpl(sf, newOrderingID);
-
- sf.position(SIZE_LONG);
-
- jf.setOffset(SIZE_LONG);
-
- freeFiles.add(jf);
- }
- else
- {
- file.getFile().open();
-
- file.getFile().delete();
- }
- }
+ if (trace) log.trace("Reclaiming file " + file);
+
+ dataFiles.remove(file);
+
+ //FIXME - size() involves a scan!!!
+ if (freeFiles.size() + dataFiles.size() + 1 < minFiles)
+ {
+ //Re-initialise it
+
+ long newOrderingID = generateOrderingID();
+
+ SequentialFile sf = file.getFile();
+
+ sf.open();
+
+ ByteBuffer bb = sf.newBuffer(SIZE_LONG);
+
+ bb.putLong(newOrderingID);
+
+ //Note we MUST re-fill it - otherwise we won't be able to detect corrupt records
+
+ //TODO - if we can avoid this somehow would be good, since filling the file is a heavyweight
+ //operation and can impact other IO operations on the disk
+ sf.fill(0, fileSize, FILL_CHARACTER);
+
+ int bytesWritten = sf.write(bb, true);
+
+ JournalFile jf = new JournalFileImpl(sf, newOrderingID);
+
+ sf.position(bytesWritten);
+
+ jf.setOffset(bytesWritten);
+
+ freeFiles.add(jf);
+ }
+ else
+ {
+ file.getFile().open();
+
+ file.getFile().delete();
+ }
+ }
}
}
@@ -1059,12 +1156,12 @@
{
file.getFile().close();
}
-
+
currentFile = null;
dataFiles.clear();
- freeFiles.clear();
+ freeFiles.clear();
state = STATE_STOPPED;
}
@@ -1095,19 +1192,19 @@
}
// Public -----------------------------------------------------------------------------
-
+
// Private -----------------------------------------------------------------------------
-
+
private void appendRecord(ByteBuffer bb, boolean sync) throws Exception
{
lock.acquire();
int size = bb.capacity();
-
+
try
- {
+ {
checkFile(size);
- currentFile.getFile().write(bb, sync);
+ currentFile.getFile().write(bb, sync);
currentFile.extendOffset(size);
}
finally
@@ -1116,43 +1213,62 @@
}
}
+ private void appendRecord(ByteBuffer bb, boolean sync, IOCallback callback) throws Exception
+ {
+ lock.acquire();
+
+ int size = bb.capacity();
+
+ try
+ {
+ checkFile(size);
+ currentFile.getFile().write(bb, sync, callback);
+ currentFile.extendOffset(size);
+ }
+ finally
+ {
+ lock.release();
+ }
+ }
+
private void repairFrom(int pos, JournalFile file) throws Exception
{
log.warn("Corruption has been detected in file: " + file.getFile().getFileName() +
- " in the record that starts at position " + pos + ". " +
- "The most likely cause is that a crash occurred in the previous run. The corrupt record will be discarded.");
+ " in the record that starts at position " + pos + ". " +
+ "The most likely cause is that a crash occurred in the previous run. The corrupt record will be discarded.");
file.getFile().fill(pos, fileSize - pos, FILL_CHARACTER);
file.getFile().position(pos);
}
-
+
private JournalFile createFile() throws Exception
{
long orderingID = generateOrderingID();
String fileName = filePrefix + "-" + orderingID + "." + fileExtension;
-
+
+ if (trace) log.trace("Creating file " + fileName);
+
SequentialFile sequentialFile = fileFactory.createSequentialFile(fileName, sync);
sequentialFile.open();
-
+
sequentialFile.fill(0, fileSize, FILL_CHARACTER);
- ByteBuffer bb = ByteBuffer.wrap(new byte[SIZE_LONG]);
+ ByteBuffer bb = sequentialFile.newBuffer(SIZE_LONG);
bb.putLong(orderingID);
- bb.flip();
+ bb.rewind();
- sequentialFile.write(bb, true);
+ int bytesWritten = sequentialFile.write(bb, true);
- sequentialFile.position(SIZE_LONG);
-
JournalFile info = new JournalFileImpl(sequentialFile, orderingID);
- info.extendOffset(SIZE_LONG);
+ info.extendOffset(bytesWritten);
+
return info;
}
@@ -1164,29 +1280,34 @@
{
//Ensure it's unique
try
- {
+ {
Thread.sleep(1);
}
catch (InterruptedException ignore)
- {
+ {
}
orderingID = System.currentTimeMillis();
}
- lastOrderingID = orderingID;
+ lastOrderingID = orderingID;
return orderingID;
}
private void checkFile(final int size) throws Exception
{
+
+ if (size % currentFile.getFile().getAlignment() != 0)
+ {
+ throw new IllegalStateException("You can't write blocks in a size different than " + currentFile.getFile().getAlignment());
+ }
//We take into account the first timestamp long
- if (size > fileSize - SIZE_LONG)
+ if (size > fileSize - currentFile.getFile().calculateBlockStart(SIZE_HEADER))
{
throw new IllegalArgumentException("Record is too large to store " + size);
}
-
+
if (currentFile == null || fileSize - currentFile.getOffset() < size)
- {
+ {
currentFile.getFile().close();
dataFiles.add(currentFile);
@@ -1200,7 +1321,7 @@
{
currentFile = createFile();
}
- }
+ }
}
private TransactionNegPos getTransactionInfo(final long txID)
@@ -1216,8 +1337,13 @@
return tx;
}
-
+ private void trace(String message)
+ {
+ log.info(message);
+ }
+
+
// Inner classes ---------------------------------------------------------------------------
private class ReclaimerTask extends TimerTask
@@ -1228,12 +1354,12 @@
return super.cancel();
}
-
+
public synchronized void run()
{
try
{
- checkAndReclaimFiles();
+ checkAndReclaimFiles();
}
catch (Exception e)
{
@@ -1241,8 +1367,8 @@
cancel();
}
- }
- }
+ }
+ }
private static class PosFiles
{
@@ -1282,7 +1408,7 @@
}
}
}
-
+
private class TransactionNegPos
{
private List<Pair<JournalFile, Long>> pos;
@@ -1297,7 +1423,7 @@
{
transactionPos = new HashSet<JournalFile>();
}
-
+
if (!transactionPos.contains(file))
{
transactionPos.add(file);
@@ -1305,39 +1431,39 @@
//We add a pos for the transaction itself in the file - this prevents any transactional operations
//being deleted before a commit or rollback is written
file.incPosCount();
- }
+ }
}
void addPos(final JournalFile file, final long id)
- {
- addTXPosCount(file);
+ {
+ addTXPosCount(file);
if (pos == null)
{
pos = new ArrayList<Pair<JournalFile, Long>>();
}
-
+
pos.add(new Pair<JournalFile, Long>(file, id));
}
void addNeg(final JournalFile file, final long id)
- {
- addTXPosCount(file);
+ {
+ addTXPosCount(file);
if (neg == null)
{
neg = new ArrayList<Pair<JournalFile, Long>>();
}
- neg.add(new Pair<JournalFile, Long>(file, id));
+ neg.add(new Pair<JournalFile, Long>(file, id));
}
void commit(final JournalFile file)
- {
+ {
if (pos != null)
{
for (Pair<JournalFile, Long> p: pos)
- {
+ {
PosFiles posFiles = posFilesMap.get(p.b);
if (posFiles == null)
@@ -1347,25 +1473,25 @@
posFilesMap.put(p.b, posFiles);
}
else
- {
- posFiles.addUpdateFile(p.a);
+ {
+ posFiles.addUpdateFile(p.a);
}
- }
+ }
}
if (neg != null)
{
- for (Pair<JournalFile, Long> n: neg)
- {
- PosFiles posFiles = posFilesMap.remove(n.b);
-
- if (posFiles == null)
- {
- throw new IllegalStateException("Cannot find add info " + n.b);
- }
-
- posFiles.addDelete(n.a);
- }
+ for (Pair<JournalFile, Long> n: neg)
+ {
+ PosFiles posFiles = posFilesMap.remove(n.b);
+
+ if (posFiles != null)
+ {
+ //throw new IllegalStateException("Cannot find add info " + n.b);
+ posFiles.addDelete(n.a);
+ }
+
+ }
}
//Now add negs for the pos we added in each file in which there were transactional operations
@@ -1373,11 +1499,11 @@
for (JournalFile jf: transactionPos)
{
file.incNegCount(jf);
- }
+ }
}
void rollback(JournalFile file)
- {
+ {
//Now add negs for the pos we added in each file in which there were transactional operations
//Note that we do this on rollback as we do on commit, since we need to ensure the file containing
//the rollback record doesn't get deleted before the files with the transactional operations are deleted
@@ -1407,4 +1533,28 @@
}
}
}
+
+ 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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFile.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -26,6 +26,7 @@
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
+import org.jboss.messaging.core.journal.IOCallback;
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.logging.Logger;
@@ -39,7 +40,7 @@
public class NIOSequentialFile implements SequentialFile
{
private static final Logger log = Logger.getLogger(NIOSequentialFile.class);
-
+
private String journalDir;
private String fileName;
@@ -51,28 +52,39 @@
private FileChannel channel;
private RandomAccessFile rfile;
-
+
public NIOSequentialFile(final String journalDir, final String fileName, final boolean sync)
{
this.journalDir = journalDir;
this.fileName = fileName;
- this.sync = sync;
+ this.sync = sync;
}
+ public int getAlignment()
+ {
+ return 1;
+ }
+
+ public int calculateBlockStart(int position) throws Exception
+ {
+ return position;
+ }
+
+
public String getFileName()
{
return fileName;
}
-
+
public void open() throws Exception
- {
+ {
file = new File(journalDir + "/" + fileName);
-
+
rfile = new RandomAccessFile(file, "rw");
-
- channel = rfile.getChannel();
+
+ channel = rfile.getChannel();
}
public void fill(final int position, final int size, final byte fillCharacter) throws Exception
@@ -81,17 +93,17 @@
for (int i = 0; i < size; i++)
{
- bb.put(fillCharacter);
+ bb.put(fillCharacter);
}
bb.flip();
-
+
channel.position(position);
-
+
channel.write(bb);
-
- channel.force(false);
+ channel.force(false);
+
channel.position(0);
}
@@ -100,42 +112,84 @@
channel.close();
rfile.close();
-
+
channel = null;
rfile = null;
file = null;
}
-
+
public void delete() throws Exception
- {
+ {
file.delete();
- close();
+ close();
}
-
+
public int read(ByteBuffer bytes) throws Exception
{
- int bytesRead = channel.read(bytes);
+ return read(bytes, null);
+ }
+
+ public int read(ByteBuffer bytes, IOCallback callback) throws Exception
+ {
+ try
+ {
+ int bytesRead = channel.read(bytes);
+ if (callback != null)
+ {
+ callback.done();
+ }
+ bytes.flip();
+ return bytesRead;
+ }
+ catch (Exception e)
+ {
+ if (callback != null)
+ {
+ callback.onError(-1, e.getLocalizedMessage());
+ }
+
+ throw e;
+ }
- return bytesRead;
}
-
+
public int write(ByteBuffer bytes, boolean sync) throws Exception
{
+ return write(bytes, sync, null);
+ }
+
+ public int write(ByteBuffer bytes, boolean sync, IOCallback callback) throws Exception
+ {
int bytesRead = channel.write(bytes);
if (sync && this.sync)
{
channel.force(false);
}
-
+
+ if (callback != null)
+ {
+ callback.done();
+ }
+
return bytesRead;
}
-
+
public void position(final int pos) throws Exception
{
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/journal/impl/NIOSequentialFileFactory.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -21,12 +21,6 @@
*/
package org.jboss.messaging.core.journal.impl;
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.journal.SequentialFileFactory;
@@ -37,13 +31,11 @@
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
*
*/
-public class NIOSequentialFileFactory implements SequentialFileFactory
+public class NIOSequentialFileFactory extends AbstractSequentialFactory implements SequentialFileFactory
{
- private final String journalDir;
-
public NIOSequentialFileFactory(final String journalDir)
{
- this.journalDir = journalDir;
+ super(journalDir);
}
public SequentialFile createSequentialFile(final String fileName, final boolean sync)
@@ -51,25 +43,4 @@
return new NIOSequentialFile(journalDir, fileName, sync);
}
- public List<String> listFiles(final String extension) throws Exception
- {
- File dir = new File(journalDir);
-
- FilenameFilter fnf = new FilenameFilter()
- {
- public boolean accept(File file, String name)
- {
- return name.endsWith("." + extension);
- }
- };
-
- String[] fileNames = dir.list(fnf);
-
- if (fileNames == null)
- {
- throw new IOException("Failed to list: " + journalDir);
- }
-
- return Arrays.asList(fileNames);
- }
}
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/src/main/org/jboss/messaging/core/persistence/impl/journal/JournalStorageManager.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -21,6 +21,7 @@
import org.jboss.messaging.core.journal.RecordInfo;
import org.jboss.messaging.core.journal.SequentialFileFactory;
import org.jboss.messaging.core.journal.impl.JournalImpl;
+import org.jboss.messaging.core.journal.impl.AIOSequentialFileFactory;
import org.jboss.messaging.core.journal.impl.NIOSequentialFileFactory;
import org.jboss.messaging.core.logging.Logger;
import org.jboss.messaging.core.message.Message;
@@ -84,9 +85,9 @@
public JournalStorageManager(Configuration config)
{
- if (config.getJournalType() != JournalType.NIO)
+ if (config.getJournalType() != JournalType.NIO && config.getJournalType() != JournalType.ASYNCIO)
{
- throw new IllegalArgumentException("Only support NIO journal");
+ throw new IllegalArgumentException("Only NIO and AsyncIO are supported journals");
}
String bindingsDir = config.getBindingsDirectory();
@@ -99,7 +100,7 @@
checkAndCreateDir(bindingsDir, config.isCreateBindingsDir());
SequentialFileFactory bindingsFF = new NIOSequentialFileFactory(bindingsDir);
-
+
bindingsJournal = new JournalImpl(1024 * 1024, 2, true, bindingsFF, 10000, "jbm-bindings", "bindings");
String journalDir = config.getJournalDirectory();
@@ -111,7 +112,31 @@
checkAndCreateDir(journalDir, config.isCreateBindingsDir());
- SequentialFileFactory journalFF = new NIOSequentialFileFactory(journalDir);
+ SequentialFileFactory journalFF = null;
+
+ if (config.getJournalType() == JournalType.ASYNCIO)
+ {
+ 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);
+ }
+ else
+ {
+ journalFF = new AIOSequentialFileFactory(bindingsDir);
+ log.info("AIO loaded successfully");
+ }
+ }
+ else
+ if (config.getJournalType() == JournalType.NIO)
+ {
+ journalFF = new NIOSequentialFileFactory(bindingsDir);
+ }
+ else
+ if (config.getJournalType() == JournalType.JDBC)
+ { // Sanity check only... this is previously tested
+ throw new IllegalArgumentException("JDBC Journal is not supported yet");
+ }
messageJournal = new JournalImpl(config.getJournalFileSize(),
config.getJournalMinFiles(), config.isJournalSync(), journalFF,
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/MultiThreadWriteNativeTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -20,10 +20,17 @@
import junit.framework.TestCase;
import org.jboss.messaging.core.asyncio.AIOCallback;
-import org.jboss.messaging.core.asyncio.impl.JlibAIO;
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
import org.jboss.messaging.core.logging.Logger;
-// you need to define java.library.path=${project-root}/native/src/.libs
+/**
+ *
+ * you need to define -Djava.library.path=${project-root}/native/src/.libs when calling the JVM
+ * If you are running this test in eclipse you should do:
+ * I - Run->Open Run Dialog
+ * II - Find the class on the list (you will find it if you already tried running this testcase before)
+ * III - Add -Djava.library.path=<your project place>/native/src/.libs
+ * */
public class MultiThreadWriteNativeTest extends TestCase
{
@@ -47,12 +54,12 @@
static class ExecClass implements Runnable
{
- JlibAIO aio;
+ AsynchronousFileImpl aio;
ByteBuffer buffer;
AIOCallback callback;
- public ExecClass(JlibAIO aio, ByteBuffer buffer, AIOCallback callback)
+ public ExecClass(AsynchronousFileImpl aio, ByteBuffer buffer, AIOCallback callback)
{
this.aio = aio;
this.buffer = buffer;
@@ -81,7 +88,7 @@
- private static void addData(JlibAIO aio, ByteBuffer buffer, AIOCallback callback) throws Exception
+ private static void addData(AsynchronousFileImpl aio, ByteBuffer buffer, AIOCallback callback) throws Exception
{
//aio.write(getNewPosition()*SIZE, SIZE, buffer, callback);
executor.execute(new ExecClass(aio, buffer, callback));
@@ -125,10 +132,11 @@
private void executeTest(boolean sync) throws Throwable
{
log.info(sync?"Sync test:":"Async test");
- JlibAIO jlibAIO = new JlibAIO();
+ AsynchronousFileImpl jlibAIO = new AsynchronousFileImpl();
jlibAIO.open(FILE_NAME, 21000);
log.debug("Preallocating file");
- jlibAIO.preAllocate(NUMBER_OF_THREADS, SIZE * NUMBER_OF_LINES);
+
+ 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);
@@ -179,9 +187,9 @@
Throwable failed = null;
CountDownLatch latchStart;
boolean sync;
- JlibAIO libaio;
+ AsynchronousFileImpl libaio;
- public ThreadProducer(String name, CountDownLatch latchStart, JlibAIO libaio, boolean sync)
+ public ThreadProducer(String name, CountDownLatch latchStart, AsynchronousFileImpl libaio, boolean sync)
{
super(name);
this.latchStart = latchStart;
@@ -281,9 +289,9 @@
boolean errorCalled = false;
CountDownLatch latchDone;
ByteBuffer releaseMe;
- JlibAIO libaio;
+ AsynchronousFileImpl libaio;
- public LocalCallback(CountDownLatch latchDone, ByteBuffer releaseMe, JlibAIO libaio)
+ public LocalCallback(CountDownLatch latchDone, ByteBuffer releaseMe, AsynchronousFileImpl libaio)
{
this.latchDone = latchDone;
this.releaseMe = releaseMe;
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/integration/core/asyncio/impl/SingleThreadWriteNativeTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -13,16 +13,27 @@
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import org.jboss.messaging.core.asyncio.AIOCallback;
-import org.jboss.messaging.core.asyncio.impl.JlibAIO;
+import org.jboss.messaging.core.asyncio.impl.AsynchronousFileImpl;
+import org.jboss.messaging.core.logging.Logger;
import junit.framework.TestCase;
-//you need to define java.library.path=${project-root}/native/src/.libs
+/**
+ *
+ * you need to define -Djava.library.path=${project-root}/native/src/.libs when calling the JVM
+ * If you are running this test in eclipse you should do:
+ * I - Run->Open Run Dialog
+ * II - Find the class on the list (you will find it if you already tried running this testcase before)
+ * III - Add -Djava.library.path=<your project place>/native/src/.libs
+ * */
public class SingleThreadWriteNativeTest extends TestCase
{
+ private static final Logger log = Logger.getLogger(SingleThreadWriteNativeTest.class);
+
private static CharsetEncoder UTF_8_ENCODER = Charset.forName("UTF-8").newEncoder();
@@ -52,7 +63,108 @@
buffer.put((byte)'\n');
}
+
+ public void testTwoFiles() throws Exception
+ {
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
+ final AsynchronousFileImpl controller2 = new AsynchronousFileImpl();
+ controller.open(FILE_NAME + ".1", 10000);
+ controller2.open(FILE_NAME + ".2", 10000);
+
+ int numberOfLines = 100000;
+ int size = 1024;
+
+ try
+ {
+ System.out.println("++testDirectDataNoPage"); System.out.flush();
+ CountDownLatch latchDone = new CountDownLatch(numberOfLines);
+ CountDownLatch latchDone2 = new CountDownLatch(numberOfLines);
+
+ ByteBuffer block = controller.newBuffer(size);
+ encodeBufer(block);
+
+ preAlloc(controller, numberOfLines * size);
+ preAlloc(controller2, numberOfLines * size);
+
+ ArrayList<LocalAIO> list = new ArrayList<LocalAIO>();
+ ArrayList<LocalAIO> list2 = new ArrayList<LocalAIO>();
+ for (int i=0; i<numberOfLines; i++)
+ {
+ list.add(new LocalAIO(latchDone));
+ list2.add(new LocalAIO(latchDone2));
+ }
+
+
+ long valueInitial = System.currentTimeMillis();
+
+ System.out.println("Adding data");
+
+ long lastTime = System.currentTimeMillis();
+ int counter = 0;
+ Iterator<LocalAIO> iter2 = list2.iterator();
+
+ for (LocalAIO tmp: list)
+ {
+ LocalAIO tmp2 = iter2.next();
+
+ controller.write(counter * size, size, block, tmp);
+ controller.write(counter * size, size, block, tmp2);
+ if (++counter % 5000 == 0)
+ {
+ System.out.println(5000*1000/(System.currentTimeMillis()-lastTime) + " rec/sec (Async)");
+ lastTime = System.currentTimeMillis();
+ }
+
+ }
+
+ System.out.println("Data added " + (System.currentTimeMillis() - valueInitial));
+
+
+ System.out.println("Finished append " + (System.currentTimeMillis() - valueInitial) + " received = " + LocalAIO.staticDone);
+ System.out.println("Flush now");
+ System.out.println("Received " + LocalAIO.staticDone);
+ long timeTotal = System.currentTimeMillis() - valueInitial;
+
+ System.out.println("Asynchronous time = " + timeTotal + " for " + numberOfLines + " registers " + " size each line = " + size + " Records/Sec=" + (numberOfLines*1000/timeTotal) + " (Assynchronous)");
+
+ latchDone.await();
+ latchDone2.await();
+
+ timeTotal = System.currentTimeMillis() - valueInitial;
+ System.out.println("After completions time = " + timeTotal + " for " + numberOfLines + " registers " + " size each line = " + size + " Records/Sec=" + (numberOfLines*1000/timeTotal) + " (Assynchronous)");
+
+ for (LocalAIO tmp: list)
+ {
+ assertEquals(1, tmp.timesDoneCalled);
+ assertTrue(tmp.doneCalled);
+ assertFalse(tmp.errorCalled);
+ }
+
+ controller.destroyBuffer(block);
+
+ controller.close();
+ }
+ finally
+ {
+ try {controller.close();} catch (Exception ignored){}
+ }
+
+
+ }
+
+ public void testAnnoyingPoller() throws Exception
+ {
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
+ for (int i=0; i< 1000; i++)
+ {
+ controller.open(FILE_NAME, 10000);
+ controller.close();
+
+ }
+ }
+
+
public void testAddBeyongSimultaneousLimit() throws Exception
{
asyncData(150000,1024,100);
@@ -60,27 +172,141 @@
public void testAddAsyncData() throws Exception
{
- asyncData(150000,1024,20000);
+ asyncData(500000,1024,30000);
}
+ public void testValidateData() throws Exception
+ {
+ validateData(150000,1024,20000);
+ }
+
+ public void testInvalidReads() throws Exception
+ {
+ class LocalCallback implements AIOCallback
+ {
+
+ CountDownLatch latch = new CountDownLatch(1);
+ boolean error;
+ public void done()
+ {
+ latch.countDown();
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ {
+ this.error = true;
+ latch.countDown();
+ }
+ }
+
+ AsynchronousFileImpl controller = new AsynchronousFileImpl();
+ try
+ {
+
+ final int NUMBER_LINES = 1;
+ final int SIZE = 512;
+
+ controller.open(FILE_NAME, 10);
+ controller.close();
+
+ controller = new AsynchronousFileImpl();
+
+ controller.open(FILE_NAME, 10);
+
+ controller.fill(0,1, 512, (byte)'j');
+
+
+ ByteBuffer buffer = controller.newBuffer(SIZE);
+
+
+ buffer.clear();
+
+ for (int i=0; i<SIZE; i++)
+ {
+ buffer.put((byte)(i%100));
+ }
+
+ LocalCallback callbackLocal = new LocalCallback();
+
+ controller.write(0, 512, buffer, callbackLocal);
+
+ callbackLocal.latch.await();
+
+ ByteBuffer newBuffer = ByteBuffer.allocateDirect(50);
+
+ callbackLocal = new LocalCallback();
+
+ controller.read(0, 50, newBuffer, callbackLocal);
+
+ callbackLocal.latch.await();
+
+ //assertTrue(callbackLocal.error);
+
+ callbackLocal = new LocalCallback();
+
+ byte bytes[] = new byte[512];
+
+ try
+ {
+ newBuffer = ByteBuffer.wrap(bytes);
+
+ controller.read(0, 512, newBuffer, callbackLocal);
+
+ fail("An exception was supposed to be thrown");
+ }
+ catch (Exception ignored)
+ {
+ }
+
+ //newBuffer = ByteBuffer.allocateDirect(512);
+ newBuffer = controller.newBuffer(512);
+ callbackLocal = new LocalCallback();
+ controller.read(0, 512, newBuffer,callbackLocal);
+ callbackLocal.latch.await();
+ assertFalse(callbackLocal.error);
+
+ newBuffer.rewind();
+
+ byte[] bytesRead = new byte[SIZE];
+
+ newBuffer.get(bytesRead);
+
+ for (int i=0; i<SIZE;i++)
+ {
+ assertEquals((byte)(i%100), bytesRead[i]);
+ }
+
+
+ controller.destroyBuffer(buffer);
+ }
+ finally
+ {
+ try { controller.close(); } catch (Throwable ignored){}
+
+ }
+
+ }
+
+
public void testRead() throws Exception
{
-
-
-
-
- final JlibAIO controller = new JlibAIO();
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
try
{
- final int NUMBER_LINES = 300;
+ final int NUMBER_LINES = 1000;
final int SIZE = 1024;
controller.open(FILE_NAME, 10);
+
+ log.info("Filling file");
+ controller.fill(0,1, NUMBER_LINES * SIZE, (byte)'j');
+
ByteBuffer buffer = controller.newBuffer(SIZE);
-
+ log.info("Writing file");
+
for (int i=0; i<NUMBER_LINES; i++)
{
buffer.clear();
@@ -100,6 +326,13 @@
assertTrue(aio.doneCalled);
}
+
+ // If you call close you're supposed to wait events to finish before closing it
+ log.info("Closing file");
+ controller.close();
+ log.info("Reading file");
+ controller.open(FILE_NAME, 10);
+
ByteBuffer newBuffer = ByteBuffer.allocateDirect(SIZE);
for (int i=0; i<NUMBER_LINES; i++)
@@ -150,9 +383,199 @@
}
+
+
+ public void testConcurrentClose() throws Exception
+ {
+ // The test might eventually pass if broken
+ for (int i=0; i<10; i++)
+ internalConcurrentClose();
+ }
+
+ public void internalConcurrentClose() throws Exception
+ {
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
+ try
+ {
+
+ final int NUMBER_LINES = 1000;
+ CountDownLatch readLatch = new CountDownLatch (NUMBER_LINES);
+ final int SIZE = 1024;
+
+ controller.open(FILE_NAME, 10000);
+
+ log.info("Filling file");
+
+ controller.fill(0,1, NUMBER_LINES * SIZE, (byte)'j');
+
+ log.info("Writing file");
+
+ for (int i=0; i<NUMBER_LINES; i++)
+ {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(SIZE);
+
+ buffer.clear();
+ addString ("Str value " + i + "\n", buffer);
+ for (int j=buffer.position(); j<buffer.capacity()-1;j++)
+ {
+ buffer.put((byte)' ');
+ }
+ buffer.put((byte)'\n');
+
+
+ LocalAIO aio = new LocalAIO(readLatch);
+ controller.write(i * SIZE, SIZE, buffer, aio);
+ }
+
+
+ long counter = readLatch.getCount();
+ // If you call close you're supposed to wait events to finish before closing it
+ controller.close();
+ log.info("Closed file with counter = " + counter);
+ assertEquals(0, readLatch.getCount());
+ readLatch.await();
+ log.info("Reading file");
+ controller.open(FILE_NAME, 10);
+
+ ByteBuffer newBuffer = ByteBuffer.allocateDirect(SIZE);
+
+ ByteBuffer buffer = ByteBuffer.allocateDirect(SIZE);
+
+ for (int i=0; i<NUMBER_LINES; i++)
+ {
+ newBuffer.clear();
+ addString ("Str value " + i + "\n", newBuffer);
+ for (int j=newBuffer.position(); j<newBuffer.capacity()-1;j++)
+ {
+ newBuffer.put((byte)' ');
+ }
+ newBuffer.put((byte)'\n');
+
+
+ CountDownLatch latch = new CountDownLatch(1);
+ LocalAIO aio = new LocalAIO(latch);
+ controller.read(i * SIZE, SIZE, buffer, aio);
+ latch.await();
+ assertFalse(aio.errorCalled);
+ assertTrue(aio.doneCalled);
+
+ byte bytesRead[] = new byte[SIZE];
+ byte bytesCompare[] = new byte[SIZE];
+
+ newBuffer.rewind();
+ newBuffer.get(bytesCompare);
+ buffer.rewind();
+ buffer.get(bytesRead);
+
+ for (int count=0;count<SIZE;count++)
+ {
+ assertEquals("byte position " + count + " differs on line " + i, bytesCompare[count], bytesRead[count]);
+ }
+
+
+ //byte[] byteCompare = new byte[SIZE];
+ //byte[] byteRead = new byte[SIZE];
+
+ assertTrue(buffer.equals(newBuffer));
+ }
+
+ }
+ finally
+ {
+ try { controller.close(); } catch (Throwable ignored){}
+
+ }
+
+ }
+
+ /**
+ * This method is not used unless you uncomment testValidateData
+ * The purpose of this method is to verify if the information generated by one of the write methods is correct
+ * @param numberOfLines
+ * @param size
+ * @param aioLimit
+ * @throws Exception
+ */
+ 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++)
+ {
+ 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();
+
+ 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);
+
+
+
+ }
+ }
+
+
+ private boolean compareBuffers(ByteBuffer buffer1, ByteBuffer buffer2)
+ {
+
+ buffer1.rewind();
+ buffer2.rewind();
+
+ if (buffer1.limit() != buffer2.limit())
+ {
+ return false;
+ }
+
+ byte bytes1[] = new byte[buffer1.limit()];
+ byte bytes2[] = new byte[buffer2.limit()];
+
+ buffer1.get(bytes1);
+ buffer2.get(bytes2);
+
+ for (int i=0; i< bytes1.length; i++)
+ {
+ if (bytes1[i] != bytes2[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private void asyncData(int numberOfLines, int size, int aioLimit) throws Exception
{
- final JlibAIO controller = new JlibAIO();
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
controller.open(FILE_NAME, aioLimit);
try
@@ -182,7 +605,7 @@
for (LocalAIO tmp: list)
{
controller.write(counter * size, size, block, tmp);
- if (++counter % 5000 == 0)
+ if (++counter % 20000 == 0)
{
System.out.println(5000*1000/(System.currentTimeMillis()-lastTime) + " rec/sec (Async)");
lastTime = System.currentTimeMillis();
@@ -233,7 +656,7 @@
final int SIZE = 1024;
//final int SIZE = 512;
- final JlibAIO controller = new JlibAIO();
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
controller.open(FILE_NAME, 2000);
ByteBuffer block = controller.newBuffer(SIZE);
@@ -285,11 +708,11 @@
}
- private void preAlloc(JlibAIO controller, long size)
+ private void preAlloc(AsynchronousFileImpl controller, long size)
{
System.out.println("Pre allocating"); System.out.flush();
long startPreAllocate = System.currentTimeMillis();
- controller.preAllocate(1, size);
+ controller.fill(0l, 1, size, (byte)0);
long endPreAllocate = System.currentTimeMillis() - startPreAllocate;
if (endPreAllocate != 0) System.out.println("PreAllocated the file in " + endPreAllocate + " seconds, What means " + (size/endPreAllocate) + " bytes per millisecond");
}
@@ -297,7 +720,7 @@
public void testInvalidWrite() throws Exception
{
- final JlibAIO controller = new JlibAIO();
+ final AsynchronousFileImpl controller = new AsynchronousFileImpl();
controller.open(FILE_NAME, 2000);
try
@@ -337,7 +760,7 @@
public void testInvalidAlloc() throws Exception
{
- JlibAIO controller = new JlibAIO();
+ AsynchronousFileImpl controller = new AsynchronousFileImpl();
try
{
// You don't need to open the file to alloc it
Added: 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 (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/AIOSequentialFileFactoryTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,63 @@
+/*
+ * 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.journal.impl;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+
+import org.jboss.messaging.core.journal.SequentialFile;
+import org.jboss.messaging.core.journal.SequentialFileFactory;
+import org.jboss.messaging.core.journal.impl.AIOSequentialFileFactory;
+
+public class AIOSequentialFileFactoryTest extends SequentialFileFactoryTestBase
+{
+
+ protected String journalDir = System.getProperty("user.home") + "/journal-test";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ File file = new File(journalDir);
+
+ deleteDirectory(file);
+
+ file.mkdir();
+ }
+
+ protected SequentialFileFactory createFactory()
+ {
+ return new AIOSequentialFileFactory(journalDir);
+ }
+
+ public void testBuffer() throws Exception
+ {
+ SequentialFile file = factory.createSequentialFile("filtetmp.log", true);
+ file.open();
+ ByteBuffer buff = file.newBuffer(10);
+ assertEquals(512, buff.limit());
+ //ByteBuffer buffer =
+ }
+
+
+}
Modified: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/FakeJournalImplTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/FakeJournalImplTest.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/FakeJournalImplTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -37,4 +37,9 @@
{
return new FakeSequentialFileFactory();
}
+
+ protected int getAlignment()
+ {
+ return 1;
+ }
}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/FileFactoryTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/FileFactoryTestBase.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/FileFactoryTestBase.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,82 @@
+/*
+ * 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.journal.impl;
+
+import java.nio.ByteBuffer;
+
+import org.jboss.messaging.core.journal.SequentialFile;
+import org.jboss.messaging.core.journal.SequentialFileFactory;
+import org.jboss.messaging.tests.util.UnitTestCase;
+
+public abstract class FileFactoryTestBase extends UnitTestCase
+{
+ protected abstract SequentialFileFactory createFactory();
+
+ protected SequentialFileFactory factory;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ factory = createFactory();
+ }
+
+
+
+ // Protected ---------------------------------
+
+ protected void checkFill(SequentialFile file, int pos, int size, byte fillChar) throws Exception
+ {
+ file.fill(pos, size, fillChar);
+
+ file.close();
+
+ file.open();
+
+ file.position(pos);
+
+
+
+ ByteBuffer bb = ByteBuffer.allocateDirect(size);
+
+ int bytesRead = file.read(bb);
+
+ assertEquals(size, bytesRead);
+
+ bb.rewind();
+
+ byte bytes[] = new byte[size];
+
+ bb.get(bytes);
+
+ for (int i = 0; i < size; i++)
+ {
+ //log.info(" i is " + i);
+ assertEquals(fillChar, bytes[i]);
+ }
+
+ }
+
+
+
+}
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestBase.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -68,13 +68,13 @@
protected String fileExtension = "jbm";
protected SequentialFileFactory fileFactory;
-
+
protected void setUp() throws Exception
{
super.setUp();
resetFileFactory();
-
+
transactions.clear();
records.clear();
@@ -91,7 +91,7 @@
journal.stop();
}
catch (Exception ignore)
- {
+ {
}
}
@@ -106,22 +106,22 @@
}
protected abstract SequentialFileFactory getFileFactory() throws Exception;
-
+
// Private ---------------------------------------------------------------------------------
protected void setup(int minFreeFiles, int fileSize, boolean sync)
- {
+ {
this.minFiles = minFreeFiles;
this.fileSize = fileSize;
this.sync = sync;
}
public void createJournal() throws Exception
- {
+ {
journal =
new JournalImpl(fileSize, minFiles, sync, fileFactory, 1000, filePrefix, fileExtension);
}
-
+
protected void startJournal() throws Exception
{
journal.start();
@@ -129,10 +129,18 @@
protected void stopJournal() throws Exception
{
+ stopJournal(true);
+ }
+
+ protected void stopJournal(boolean reclaim) throws Exception
+ {
//We do a reclaim in here
- journal.checkAndReclaimFiles();
+ if (reclaim)
+ {
+ journal.checkAndReclaimFiles();
+ }
- journal.stop();
+ journal.stop();
}
protected void loadAndCheck() throws Exception
@@ -164,7 +172,7 @@
}
checkTransactionsEquivalent(prepared, preparedTransactions);
- }
+ }
protected void load() throws Exception
{
@@ -173,51 +181,57 @@
protected void add(long... arguments) throws Exception
{
+ addWithSize(recordLength, arguments);
+ }
+
+ protected void addWithSize(int size, long... arguments) throws Exception
+ {
for (int i = 0; i < arguments.length; i++)
- {
- byte[] record = generateRecord(recordLength);
+ {
+ byte[] record = generateRecord(size);
journal.appendAddRecord(arguments[i], record);
- records.add(new RecordInfo(arguments[i], record, false));
+ records.add(new RecordInfo(arguments[i], record, false));
}
}
protected void update(long... arguments) throws Exception
{
for (int i = 0; i < arguments.length; i++)
- {
+ {
byte[] updateRecord = generateRecord(recordLength);
journal.appendUpdateRecord(arguments[i], updateRecord);
- records.add(new RecordInfo(arguments[i], updateRecord, true));
+ records.add(new RecordInfo(arguments[i], updateRecord, true));
}
}
protected void delete(long... arguments) throws Exception
{
for (int i = 0; i < arguments.length; i++)
- {
+ {
journal.appendDeleteRecord(arguments[i]);
removeRecordsForID(arguments[i]);
}
}
-
+
protected void addTx(long txID, long... arguments) throws Exception
{
TransactionHolder tx = getTransaction(txID);
for (int i = 0; i < arguments.length; i++)
- {
- byte[] record = generateRecord(recordLength);
+ {
+ // 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);
tx.records.add(new RecordInfo(arguments[i], record, false));
- }
+ }
}
protected void updateTx(long txID, long... arguments) throws Exception
@@ -225,24 +239,24 @@
TransactionHolder tx = getTransaction(txID);
for (int i = 0; i < arguments.length; i++)
- {
- byte[] updateRecord = generateRecord(recordLength);
-
+ {
+ byte[] updateRecord = generateRecord(recordLength - JournalImpl.SIZE_UPDATE_RECORD_TX );
+
journal.appendUpdateRecordTransactional(txID, arguments[i], updateRecord);
tx.records.add(new RecordInfo(arguments[i], updateRecord, true));
- }
+ }
}
-
+
protected void deleteTx(long txID, long... arguments) throws Exception
{
TransactionHolder tx = getTransaction(txID);
for (int i = 0; i < arguments.length; i++)
- {
+ {
journal.appendDeleteRecordTransactional(txID, arguments[i]);
- tx.deletes.add(arguments[i]);
+ tx.deletes.add(arguments[i]);
}
}
@@ -262,7 +276,7 @@
}
journal.appendPrepareRecord(txID);
-
+
tx.prepared = true;
}
@@ -335,7 +349,7 @@
return tx;
}
-
+
protected void checkTransactionsEquivalent(List<PreparedTransactionInfo> expected, List<PreparedTransactionInfo> actual)
{
assertEquals("Lists not same length", expected.size(), actual.size());
@@ -390,7 +404,7 @@
assertEquals("type not same", rexpected.isUpdate, ractual.isUpdate);
assertByteArraysEquivalent(rexpected.data, ractual.data);
- }
+ }
}
protected byte[] generateRecord(int length)
@@ -403,6 +417,11 @@
return record;
}
+ protected String debugJournal() throws Exception
+ {
+ return "***************************************************\n" + ((JournalImpl)journal).debug() + "***************************************************\n" ;
+ }
+
class TransactionHolder
{
List<RecordInfo> records = new ArrayList<RecordInfo>();
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/JournalImplTestUnit.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -32,6 +32,7 @@
* A JournalImplTestBase
*
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @author <a href="mailto:clebert.suconic at jboss.com">Clebert Suconic</a>
*
*/
public abstract class JournalImplTestUnit extends JournalImplTestBase
@@ -94,7 +95,7 @@
{
//OK
}
- stopJournal();
+ stopJournal();
}
public void testParams() throws Exception
@@ -120,7 +121,7 @@
{
//Ok
}
-
+
try
{
new JournalImpl(10 * 1024, 10, true, null, 5000, filePrefix, fileExtension);
@@ -171,79 +172,79 @@
{
try
{
- setup(10, 10 * 1024, true);
- createJournal();
- startJournal();
- load();
-
- List<String> files = fileFactory.listFiles(fileExtension);
-
- assertEquals(10, files.size());
-
- for (String file: files)
- {
- assertTrue(file.startsWith(filePrefix));
- }
-
- stopJournal();
-
- resetFileFactory();
-
- setup(20, 10 * 1024, true);
- createJournal();
- startJournal();
- load();
-
- files = fileFactory.listFiles(fileExtension);
-
- assertEquals(20, files.size());
-
- for (String file: files)
- {
- assertTrue(file.startsWith(filePrefix));
- }
-
- stopJournal();
-
- fileExtension = "tim";
-
- resetFileFactory();
-
- setup(17, 10 * 1024, true);
- createJournal();
- startJournal();
- load();
-
- files = fileFactory.listFiles(fileExtension);
-
- assertEquals(17, files.size());
-
- for (String file: files)
- {
- assertTrue(file.startsWith(filePrefix));
- }
-
- stopJournal();
-
- filePrefix = "echidna";
-
- resetFileFactory();
-
- setup(11, 10 * 1024, true);
- createJournal();
- startJournal();
- load();
-
- files = fileFactory.listFiles(fileExtension);
-
- assertEquals(11, files.size());
-
- for (String file: files)
- {
- assertTrue(file.startsWith(filePrefix));
- }
-
- stopJournal();
+ setup(10, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+
+ List<String> files = fileFactory.listFiles(fileExtension);
+
+ assertEquals(10, files.size());
+
+ for (String file: files)
+ {
+ assertTrue(file.startsWith(filePrefix));
+ }
+
+ stopJournal();
+
+ resetFileFactory();
+
+ setup(20, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+
+ files = fileFactory.listFiles(fileExtension);
+
+ assertEquals(20, files.size());
+
+ for (String file: files)
+ {
+ assertTrue(file.startsWith(filePrefix));
+ }
+
+ stopJournal();
+
+ fileExtension = "tim";
+
+ resetFileFactory();
+
+ setup(17, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+
+ files = fileFactory.listFiles(fileExtension);
+
+ assertEquals(17, files.size());
+
+ for (String file: files)
+ {
+ assertTrue(file.startsWith(filePrefix));
+ }
+
+ stopJournal();
+
+ filePrefix = "echidna";
+
+ resetFileFactory();
+
+ setup(11, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+
+ files = fileFactory.listFiles(fileExtension);
+
+ assertEquals(11, files.size());
+
+ for (String file: files)
+ {
+ assertTrue(file.startsWith(filePrefix));
+ }
+
+ stopJournal();
}
finally
{
@@ -253,6 +254,36 @@
}
}
+ public void testEmptyReopen() throws Exception
+ {
+ setup(2, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+
+ List<String> files1 = fileFactory.listFiles(fileExtension);
+
+ assertEquals(2, files1.size());
+
+ stopJournal();
+
+ setup(2, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+
+ List<String> files2 = fileFactory.listFiles(fileExtension);
+
+ assertEquals(2, files2.size());
+
+ for (String file: files1)
+ {
+ assertTrue(files2.contains(file));
+ }
+
+ stopJournal();
+ }
+
public void testCreateFilesOnLoad() throws Exception
{
setup(10, 10 * 1024, true);
@@ -281,8 +312,8 @@
{
assertTrue(files2.contains(file));
}
-
- stopJournal();
+
+ stopJournal();
}
public void testReduceFreeFiles() throws Exception
@@ -311,40 +342,104 @@
{
assertTrue(files2.contains(file));
}
-
- stopJournal();
+
+ stopJournal();
}
+
+ private int calculateRecordsPerFile(int fileSize, int alignment, int recordSize)
+ {
+ recordSize = calculateRecordSize(recordSize, alignment);
+ return fileSize / recordSize;
+ }
+
+ /**
+ *
+ * Use: calculateNumberOfFiles (fileSize, numberOfRecords, recordSize, numberOfRecords2, recordSize2, , ...., numberOfRecordsN, recordSizeN);
+ * */
+ private int calculateNumberOfFiles(int fileSize, int alignment, int ... record) throws Exception
+ {
+
+
+// log.info("Processing calculateNumberOfFiles(" + fileSize + ", " + alignment);
+// for (int recordN: record)
+// {
+// System.out.print(", " + recordN);
+// }
+// System.out.println(");");
+
+ int headerSize = calculateRecordSize(JournalImpl.SIZE_HEADER, alignment);
+ int currentPosition = headerSize;
+ int totalFiles = 0;
+
+ for (int i=0; i<record.length; i+=2)
+ {
+ int numberOfRecords = record[i];
+ int recordSize = calculateRecordSize(record[i+1], alignment);
+// log.info(" numberOfRecords = " + numberOfRecords + " recordSize=" + recordSize);
+
+ while (numberOfRecords>0)
+ {
+ int recordsFit = (fileSize - currentPosition) / recordSize;
+ if (numberOfRecords < recordsFit)
+ {
+ currentPosition = currentPosition + numberOfRecords*recordSize;
+ numberOfRecords = 0;
+// log.info(" Adding " + numberOfRecords + " records of size " + recordSize + " numberOfFiles = " + totalFiles + " Position=" + currentPosition);
+ }
+ else if (recordsFit > 0)
+ {
+ currentPosition = currentPosition + recordsFit*recordSize;
+ numberOfRecords -= recordsFit;
+// log.info(" Adding " + recordsFit + " (fitting) of size " + recordSize + " numberOfFiles = " + totalFiles + " Position = " + currentPosition);
+ }
+ else
+ {
+ totalFiles++;
+ currentPosition = headerSize;
+// log.info(" Exploded... totalFiles=" + totalFiles);
+ }
+ }
+ }
+
+ // System.out.println(" Returning " + totalFiles);
+
+ return totalFiles;
+
+ }
+
public void testCheckCreateMoreFiles() throws Exception
{
- setup(10, 10 * 1024, true);
+ setup(2, 10 * 1024, true);
createJournal();
startJournal();
load();
List<String> files1 = fileFactory.listFiles(fileExtension);
- assertEquals(10, files1.size());
+ assertEquals(2, files1.size());
assertEquals(0, journal.getDataFilesCount());
- assertEquals(9, journal.getFreeFilesCount());
+ assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
//Fill all the files
- for (int i = 0; i < 90; i++)
+ for (int i = 0; i < 91; i++)
{
add(i);
}
- assertEquals(9, journal.getDataFilesCount());
+ int numberOfFiles = calculateNumberOfFiles(10*1024, journal.getAlignment(), 91, JournalImpl.SIZE_ADD_RECORD + this.recordLength);
+
+ assertEquals(numberOfFiles, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(90, journal.getIDMapSize());
-
+ assertEquals(91, journal.getIDMapSize());
+
List<String> files2 = fileFactory.listFiles(fileExtension);
- assertEquals(10, files2.size());
-
+ assertEquals(numberOfFiles + 1, files2.size());
+
for (String file: files1)
{
assertTrue(files2.contains(file));
@@ -357,14 +452,16 @@
add(i);
}
- assertEquals(10, journal.getDataFilesCount());
+ numberOfFiles = calculateNumberOfFiles(10*1024,journal.getAlignment(), 95, JournalImpl.SIZE_ADD_RECORD + this.recordLength);
+
+ assertEquals(numberOfFiles, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(95, journal.getIDMapSize());
List<String> files3 = fileFactory.listFiles(fileExtension);
- assertEquals(11, files3.size());
-
+ assertEquals(numberOfFiles + 1, files3.size());
+
for (String file: files1)
{
assertTrue(files3.contains(file));
@@ -377,22 +474,38 @@
add(i);
}
- assertEquals(22, journal.getDataFilesCount());
+ numberOfFiles = calculateNumberOfFiles(10*1024,journal.getAlignment(), 200, JournalImpl.SIZE_ADD_RECORD + this.recordLength);
+
+ assertEquals(numberOfFiles, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(200, journal.getIDMapSize());
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(23, files4.size());
-
+ assertEquals(numberOfFiles + 1, files4.size());
+
for (String file: files1)
{
assertTrue(files4.contains(file));
}
-
- stopJournal();
+
+ stopJournal();
}
+ // Validate the methods that are used on assertions
+ public void testCalculations() throws Exception
+ {
+
+ assertEquals(0,calculateNumberOfFiles(10*1024, 1, 1, 10, 2, 20));
+ assertEquals(0,calculateNumberOfFiles(10*1024, 512, 1, 1));
+ assertEquals(0,calculateNumberOfFiles(10*1024, 512, 19, 10));
+ assertEquals(1,calculateNumberOfFiles(10*1024, 512, 20, 10));
+ assertEquals(0,calculateNumberOfFiles(3000, 500, 2, 1000, 1, 500));
+ assertEquals(1,calculateNumberOfFiles(3000, 500, 2, 1000, 1, 1000));
+ assertEquals(9,calculateNumberOfFiles(10240, 1, 90, 1038, 45, 10));
+ assertEquals(11,calculateNumberOfFiles(10*1024, 512, 60, 14 + 1024, 30, 14));
+ }
+
public void testReclaim() throws Exception
{
setup(10, 10 * 1024, true);
@@ -407,20 +520,27 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
- for (int i = 0; i < 100; i++)
+
+
+ int addRecordsPerFile = calculateRecordsPerFile(10*1024, journal.getAlignment(), JournalImpl.SIZE_ADD_RECORD + this.recordLength);
+
+
+ // Fills exactly 10 files
+ int initialNumberOfAddRecords = addRecordsPerFile * 10;
+ for (int i = 0; i < initialNumberOfAddRecords; i++)
{
add(i);
}
- assertEquals(11, journal.getDataFilesCount());
+ // We have already 10 files, but since we have the last file on exact size, the counter will be numberOfUsedFiles -1
+ assertEquals(9, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(100, journal.getIDMapSize());
+ assertEquals(initialNumberOfAddRecords, journal.getIDMapSize());
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(12, files4.size());
-
+ assertEquals(10, files4.size());
+
for (String file: files1)
{
assertTrue(files4.contains(file));
@@ -428,34 +548,54 @@
//Now delete half of them
- for (int i = 0; i < 50; i++)
+ int deleteRecordsPerFile = calculateRecordsPerFile(10*1024, journal.getAlignment(), JournalImpl.SIZE_DELETE_RECORD);
+
+ for (int i = 0; i < initialNumberOfAddRecords / 2; i++)
{
delete(i);
}
- assertEquals(11, journal.getDataFilesCount());
+
+
+ int numberOfFiles = calculateNumberOfFiles(10*1024, journal.getAlignment(), initialNumberOfAddRecords, JournalImpl.SIZE_ADD_RECORD + this.recordLength,
+ initialNumberOfAddRecords/2, JournalImpl.SIZE_DELETE_RECORD);
+
+
+ if ((initialNumberOfAddRecords / 2) % deleteRecordsPerFile == 0)
+ {
+ // The file is already full, next add would fix it
+ numberOfFiles --;
+ }
+
+ assertEquals(numberOfFiles, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(50, journal.getIDMapSize());
+ assertEquals(initialNumberOfAddRecords/2, journal.getIDMapSize());
//Make sure the deletes aren't in the current file
- for (int i = 100; i < 110; i++)
+ for (int i = 0; i < 10; i++)
{
- add(i);
+ add(initialNumberOfAddRecords + i);
}
- assertEquals(12, journal.getDataFilesCount());
+ numberOfFiles = calculateNumberOfFiles(10*1024, journal.getAlignment(),
+ initialNumberOfAddRecords, JournalImpl.SIZE_ADD_RECORD + this.recordLength,
+ initialNumberOfAddRecords / 2, JournalImpl.SIZE_DELETE_RECORD,
+ 10, JournalImpl.SIZE_ADD_RECORD + this.recordLength);
+
+
+ assertEquals(numberOfFiles, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(60, journal.getIDMapSize());
+ assertEquals(initialNumberOfAddRecords/2 + 10, journal.getIDMapSize());
journal.checkAndReclaimFiles();
//Several of them should be reclaimed - and others deleted - the total number of files should not drop below
//10
- assertEquals(7, journal.getDataFilesCount());
- assertEquals(2, journal.getFreeFilesCount());
- assertEquals(60, journal.getIDMapSize());
+ assertEquals(journal.getAlignment()==1?6:7, journal.getDataFilesCount());
+ assertEquals(journal.getAlignment()==1?3:2, journal.getFreeFilesCount());
+ assertEquals(initialNumberOfAddRecords /2 + 10, journal.getIDMapSize());
List<String> files5 = fileFactory.listFiles(fileExtension);
@@ -463,7 +603,7 @@
//Now delete the rest
- for (int i = 50; i < 110; i++)
+ for (int i = initialNumberOfAddRecords /2; i < initialNumberOfAddRecords + 10; i++)
{
delete(i);
}
@@ -485,13 +625,13 @@
List<String> files6 = fileFactory.listFiles(fileExtension);
assertEquals(10, files6.size());
-
- stopJournal();
+
+ stopJournal();
}
-
+
public void testReclaimAddUpdateDeleteDifferentFiles1() throws Exception
{
- setup(2, 1046, true); //Make sure there is one record per file
+ setup(2, calculateRecordSize(8, getAlignment()) + calculateRecordSize(JournalImpl.SIZE_ADD_RECORD + recordLength, getAlignment()), true); //Make sure there is one record per file
createJournal();
startJournal();
load();
@@ -525,7 +665,7 @@
public void testReclaimAddUpdateDeleteDifferentFiles2() throws Exception
{
- setup(2, 1046, true); //Make sure there is one record per file
+ setup(2, calculateRecordSize(8, getAlignment()) + calculateRecordSize(JournalImpl.SIZE_ADD_RECORD + recordLength, getAlignment()), true); //Make sure there is one record per file
createJournal();
startJournal();
load();
@@ -582,20 +722,20 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
for (int i = 0; i < 100; i++)
{
addTx(1, i);
}
- assertEquals(11, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 100, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
List<String> files2 = fileFactory.listFiles(fileExtension);
- assertEquals(12, files2.size());
-
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 100, recordLength) + 1, files2.size());
+
for (String file: files1)
{
assertTrue(files2.contains(file));
@@ -605,14 +745,14 @@
//Make sure nothing reclaimed
- assertEquals(11, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 100, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
List<String> files3 = fileFactory.listFiles(fileExtension);
- assertEquals(12, files3.size());
-
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 100, recordLength) + 1, files3.size());
+
for (String file: files1)
{
assertTrue(files3.contains(file));
@@ -625,14 +765,14 @@
updateTx(1, i);
}
- assertEquals(22, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(23, files4.size());
-
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength) + 1, files4.size());
+
for (String file: files1)
{
assertTrue(files4.contains(file));
@@ -642,34 +782,36 @@
//Make sure nothing reclaimed
- assertEquals(22, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength) , journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
List<String> files5 = fileFactory.listFiles(fileExtension);
assertEquals(23, files5.size());
-
+
for (String file: files1)
{
assertTrue(files5.contains(file));
}
-
+
//Now delete them
-
+
for (int i = 0; i < 200; i++)
{
deleteTx(1, i);
}
- assertEquals(22, journal.getDataFilesCount());
+
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength, 200, JournalImpl.SIZE_DELETE_RECORD_TX), journal.getDataFilesCount());
+
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
List<String> files7 = fileFactory.listFiles(fileExtension);
- assertEquals(23, files7.size());
-
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength, 200, JournalImpl.SIZE_DELETE_RECORD_TX) + 1, files7.size());
+
for (String file: files1)
{
assertTrue(files7.contains(file));
@@ -677,14 +819,14 @@
journal.checkAndReclaimFiles();
- assertEquals(22, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength, 200, JournalImpl.SIZE_DELETE_RECORD_TX), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
List<String> files8 = fileFactory.listFiles(fileExtension);
- assertEquals(23, files8.size());
-
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength, 200, JournalImpl.SIZE_DELETE_RECORD_TX) + 1, files8.size());
+
for (String file: files1)
{
assertTrue(files8.contains(file));
@@ -701,6 +843,10 @@
rollback(1);
}
+ // If this change, we need to consider commit or rollback size on the test
+ assertEquals(JournalImpl.SIZE_ROLLBACK_RECORD, JournalImpl.SIZE_COMMIT_RECORD);
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(), 200, recordLength, 200, JournalImpl.SIZE_DELETE_RECORD_TX, 1, JournalImpl.SIZE_COMMIT_RECORD), journal.getDataFilesCount());
+
//Add more records to make sure we get to the next file
for (int i = 200; i < 210; i++)
@@ -708,14 +854,24 @@
add(i);
}
- assertEquals(23, journal.getDataFilesCount());
+
+
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(),
+ 200, recordLength,
+ 200, JournalImpl.SIZE_DELETE_RECORD_TX,
+ 1, JournalImpl.SIZE_COMMIT_RECORD,
+ 10, JournalImpl.SIZE_ADD_RECORD + recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(10, journal.getIDMapSize());
List<String> files9 = fileFactory.listFiles(fileExtension);
- assertEquals(24, files9.size());
-
+ assertEquals(calculateNumberOfFiles(fileSize , journal.getAlignment(),
+ 200, recordLength,
+ 200, JournalImpl.SIZE_DELETE_RECORD_TX,
+ 1, JournalImpl.SIZE_COMMIT_RECORD,
+ 10, JournalImpl.SIZE_ADD_RECORD + recordLength) + 1, files9.size());
+
for (String file: files1)
{
assertTrue(files9.contains(file));
@@ -724,19 +880,20 @@
journal.checkAndReclaimFiles();
//Most Should now be reclaimed - leaving 10 left in total
-
- assertEquals(1, journal.getDataFilesCount());
- assertEquals(8, journal.getFreeFilesCount());
+
+ assertEquals(journal.getAlignment()==1?1:2, journal.getDataFilesCount());
+ assertEquals(journal.getAlignment()==1?8:7, journal.getFreeFilesCount());
assertEquals(10, journal.getIDMapSize());
List<String> files10 = fileFactory.listFiles(fileExtension);
- assertEquals(10, files10.size());
+ assertEquals(10, files10.size());
}
public void testReclaimTransactionalSimple() throws Exception
{
- setup(2, 1054, true);
+ setup(2, calculateRecordSize(JournalImpl.SIZE_HEADER, getAlignment()) +
+ calculateRecordSize(recordLength, getAlignment()), true);
createJournal();
startJournal();
load();
@@ -748,7 +905,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
addTx(1, 1); // in file 0
deleteTx(1, 1); // in file 1
@@ -763,7 +920,7 @@
//Make sure we move on to the next file
- add(2); // in file 2
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 2); // in file 2
List<String> files3 = fileFactory.listFiles(fileExtension);
@@ -785,7 +942,7 @@
//Make sure we move on to the next file
- add(3); // in file 4
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 3); // in file 4
List<String> files5 = fileFactory.listFiles(fileExtension);
@@ -805,8 +962,9 @@
assertEquals(1, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(2, journal.getIDMapSize());
+ assertEquals(2, journal.getIDMapSize());
+ Thread.sleep(1000);
//Now restart
stopJournal();
@@ -818,7 +976,7 @@
assertEquals(1, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(2, journal.getIDMapSize());
+ assertEquals(2, journal.getIDMapSize());
}
public void testAddDeleteCommitTXIDMap1() throws Exception
@@ -852,7 +1010,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
- assertEquals(0, journal.getIDMapSize());
+ assertEquals(0, journal.getIDMapSize());
}
public void testAddCommitTXIDMap1() throws Exception
@@ -875,12 +1033,12 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
commit(1);
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
- assertEquals(1, journal.getIDMapSize());
+ assertEquals(1, journal.getIDMapSize());
}
public void testAddDeleteCommitTXIDMap2() throws Exception
@@ -914,10 +1072,10 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
- assertEquals(0, journal.getIDMapSize());
+ assertEquals(0, journal.getIDMapSize());
}
-
+
public void testAddDeleteRollbackTXIDMap1() throws Exception
{
setup(10, 10 * 1024, true);
@@ -949,7 +1107,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
- assertEquals(0, journal.getIDMapSize());
+ assertEquals(0, journal.getIDMapSize());
}
public void testAddRollbackTXIDMap1() throws Exception
@@ -972,12 +1130,12 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
rollback(1);
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
- assertEquals(0, journal.getIDMapSize());
+ assertEquals(0, journal.getIDMapSize());
}
public void testAddDeleteRollbackTXIDMap2() throws Exception
@@ -1011,7 +1169,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(9, journal.getFreeFilesCount());
- assertEquals(1, journal.getIDMapSize());
+ assertEquals(1, journal.getIDMapSize());
}
public void testAddDeleteIDMap() throws Exception
@@ -1045,7 +1203,7 @@
public void testCommitRecordsInFileReclaim() throws Exception
{
- setup(2, 1054, true);
+ setup(2, calculateRecordSize(JournalImpl.SIZE_HEADER, getAlignment()) + calculateRecordSize(recordLength, getAlignment()), true);
createJournal();
startJournal();
load();
@@ -1057,7 +1215,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
addTx(1, 1);
List<String> files2 = fileFactory.listFiles(fileExtension);
@@ -1067,7 +1225,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
//Make sure we move on to the next file
commit(1);
@@ -1080,7 +1238,7 @@
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
- add(2);
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 2);
//Move on to another file
@@ -1102,17 +1260,17 @@
assertEquals(2, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(2, journal.getIDMapSize());
+ assertEquals(2, journal.getIDMapSize());
}
// file 1: add 1 tx,
// file 2: commit 1, add 2, delete 2
// file 3: add 3
-
+
public void testCommitRecordsInFileNoReclaim() throws Exception
{
- setup(2, 1300, true);
+ setup(2, calculateRecordSize(JournalImpl.SIZE_HEADER, getAlignment()) + calculateRecordSize(recordLength, getAlignment()) + 512, true);
createJournal();
startJournal();
load();
@@ -1124,18 +1282,18 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
addTx(1, 1); // in file 0
-
+
//Make sure we move on to the next file
- add(2); // in file 1
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 2); // in file 1
- List<String> files2 = fileFactory.listFiles(fileExtension);
+ List<String> files2 = fileFactory.listFiles(fileExtension);
assertEquals(2, files2.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(), 2, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
@@ -1143,9 +1301,13 @@
List<String> files3 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files3.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_COMMIT_RECORD) +1, files3.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_COMMIT_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(2, journal.getIDMapSize());
@@ -1153,15 +1315,21 @@
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files4.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_COMMIT_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD)+1, files4.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_COMMIT_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
//Move on to another file
- add(3); // in file 2
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 3); // in file 2
List<String> files5 = fileFactory.listFiles(fileExtension);
@@ -1170,7 +1338,7 @@
assertEquals(2, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(2, journal.getIDMapSize());
-
+
journal.checkAndReclaimFiles();
List<String> files6 = fileFactory.listFiles(fileExtension);
@@ -1179,7 +1347,7 @@
assertEquals(2, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
- assertEquals(2, journal.getIDMapSize());
+ assertEquals(2, journal.getIDMapSize());
//Restart
@@ -1199,7 +1367,7 @@
public void testRollbackRecordsInFileNoReclaim() throws Exception
{
- setup(2, 1300, true);
+ setup(2, calculateRecordSize(JournalImpl.SIZE_HEADER, getAlignment()) + calculateRecordSize(recordLength, getAlignment()) + 512, true);
createJournal();
startJournal();
load();
@@ -1211,14 +1379,14 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
addTx(1, 1); // in file 0
-
+
//Make sure we move on to the next file
- add(2); // in file 1
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD ,2); // in file 1
- List<String> files2 = fileFactory.listFiles(fileExtension);
+ List<String> files2 = fileFactory.listFiles(fileExtension);
assertEquals(2, files2.size());
@@ -1230,9 +1398,13 @@
List<String> files3 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files3.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_ROLLBACK_RECORD) +1, files3.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_ROLLBACK_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
@@ -1240,24 +1412,38 @@
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files4.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_ROLLBACK_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD)+1, files4.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_ROLLBACK_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
//Move on to another file
- add(3); // in file 2 (current file)
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD,3); // in file 2 (current file)
List<String> files5 = fileFactory.listFiles(fileExtension);
- assertEquals(3, files5.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_ROLLBACK_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD,
+ 1, recordLength)+1, files5.size());
- assertEquals(2, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_ROLLBACK_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD,
+ 1, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
-
+
journal.checkAndReclaimFiles();
List<String> files6 = fileFactory.listFiles(fileExtension);
@@ -1268,7 +1454,7 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
- assertEquals(1, journal.getIDMapSize());
+ assertEquals(1, journal.getIDMapSize());
//Restart
@@ -1288,7 +1474,7 @@
public void testPrepareNoReclaim() throws Exception
{
- setup(2, 1300, true);
+ setup(2, calculateRecordSize(JournalImpl.SIZE_HEADER, getAlignment()) + calculateRecordSize(recordLength, getAlignment()) + 512, true);
createJournal();
startJournal();
load();
@@ -1300,18 +1486,18 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
addTx(1, 1); // in file 0
-
+
//Make sure we move on to the next file
- add(2); // in file 1
+ addWithSize(1024 - JournalImpl.SIZE_ADD_RECORD,2); // in file 1
- List<String> files2 = fileFactory.listFiles(fileExtension);
+ List<String> files2 = fileFactory.listFiles(fileExtension);
assertEquals(2, files2.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(), 2, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
@@ -1321,7 +1507,9 @@
assertEquals(2, files3.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
@@ -1329,24 +1517,39 @@
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files4.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD) + 1, files4.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
//Move on to another file
- add(3); // in file 2
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 3); // in file 2
List<String> files5 = fileFactory.listFiles(fileExtension);
- assertEquals(3, files5.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD,
+ 1, recordLength) + 1, files5.size());
- assertEquals(2, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD,
+ 1, recordLength), journal.getDataFilesCount());
+
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
-
+
journal.checkAndReclaimFiles();
List<String> files6 = fileFactory.listFiles(fileExtension);
@@ -1357,7 +1560,7 @@
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
- add(4); // in file 3
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 4); // in file 3
List<String> files7 = fileFactory.listFiles(fileExtension);
@@ -1383,12 +1586,12 @@
createJournal();
startJournal();
loadAndCheck();
-
+
}
public void testPrepareReclaim() throws Exception
{
- setup(2, 1300, true);
+ setup(2, calculateRecordSize(JournalImpl.SIZE_HEADER, getAlignment()) + calculateRecordSize(recordLength, getAlignment()) + 512, true);
createJournal();
startJournal();
load();
@@ -1400,26 +1603,26 @@
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
addTx(1, 1); // in file 0
- files1 = fileFactory.listFiles(fileExtension);
+ files1 = fileFactory.listFiles(fileExtension);
assertEquals(2, files1.size());
assertEquals(0, journal.getDataFilesCount());
assertEquals(1, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
-
+
//Make sure we move on to the next file
- add(2); // in file 1
+ addWithSize(recordLength - JournalImpl.SIZE_ADD_RECORD, 2); // in file 1
- List<String> files2 = fileFactory.listFiles(fileExtension);
+ List<String> files2 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files2.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(), 2, recordLength) , journal.getDataFilesCount());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(), 2, recordLength), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
@@ -1437,18 +1640,24 @@
List<String> files4 = fileFactory.listFiles(fileExtension);
- assertEquals(2, files4.size());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD) + 1 , files4.size());
- assertEquals(1, journal.getDataFilesCount());
+ assertEquals(calculateNumberOfFiles(fileSize, journal.getAlignment(),
+ 2, recordLength,
+ 1, JournalImpl.SIZE_PREPARE_RECORD,
+ 1, JournalImpl.SIZE_DELETE_RECORD), journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(0, journal.getIDMapSize());
//Move on to another file
- add(3); // in file 2
+ addWithSize(1024 - JournalImpl.SIZE_ADD_RECORD,3); // in file 2
journal.checkAndReclaimFiles();
-
+
List<String> files5 = fileFactory.listFiles(fileExtension);
assertEquals(3, files5.size());
@@ -1456,7 +1665,7 @@
assertEquals(2, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
-
+
journal.checkAndReclaimFiles();
List<String> files6 = fileFactory.listFiles(fileExtension);
@@ -1467,7 +1676,7 @@
assertEquals(0, journal.getFreeFilesCount());
assertEquals(1, journal.getIDMapSize());
- add(4); // in file 3
+ addWithSize(1024 - JournalImpl.SIZE_ADD_RECORD,4); // in file 3
List<String> files7 = fileFactory.listFiles(fileExtension);
@@ -1491,9 +1700,9 @@
List<String> files9 = fileFactory.listFiles(fileExtension);
- assertEquals(4, files9.size());
+ assertEquals(journal.getAlignment()==1?4:5, files9.size());
- assertEquals(3, journal.getDataFilesCount());
+ assertEquals(journal.getAlignment()==1?3:4, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(2, journal.getIDMapSize());
@@ -1501,19 +1710,19 @@
List<String> files10 = fileFactory.listFiles(fileExtension);
- assertEquals(4, files10.size());
+ assertEquals(journal.getAlignment()==1?4:3, files10.size());
- assertEquals(3, journal.getDataFilesCount());
+ assertEquals(journal.getAlignment()==1?3:2, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(2, journal.getIDMapSize());
- add(5); // in file 4
+ addWithSize(1024 - JournalImpl.SIZE_ADD_RECORD,5); // in file 4
List<String> files11 = fileFactory.listFiles(fileExtension);
- assertEquals(5, files11.size());
+ assertEquals(journal.getAlignment()==1?5:3, files11.size());
- assertEquals(4, journal.getDataFilesCount());
+ assertEquals(journal.getAlignment()==1?4:2, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(3, journal.getIDMapSize());
@@ -1541,16 +1750,18 @@
List<String> files13 = fileFactory.listFiles(fileExtension);
- assertEquals(3, files13.size());
+ assertEquals(journal.getAlignment()==1?3:4, files13.size());
- assertEquals(2, journal.getDataFilesCount());
+ assertEquals(journal.getAlignment()==1?2:3, journal.getDataFilesCount());
assertEquals(0, journal.getFreeFilesCount());
assertEquals(2, journal.getIDMapSize());
- add(6);
+ addWithSize(1024 - JournalImpl.SIZE_ADD_RECORD,6);
List<String> files14 = fileFactory.listFiles(fileExtension);
+ log.info("Debug journal on testPrepareReclaim ->\n" + debugJournal());
+
assertEquals(4, files14.size());
assertEquals(3, journal.getDataFilesCount());
@@ -1572,7 +1783,7 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
// Non transactional tests
@@ -1584,7 +1795,7 @@
createJournal();
startJournal();
load();
- add(1);
+ add(1);
stopJournal();
createJournal();
startJournal();
@@ -1597,7 +1808,7 @@
createJournal();
startJournal();
load();
- add(1,2,3,4,5,6,7,8,9,10);
+ add(1,2,3,4,5,6,7,8,9,10);
stopJournal();
createJournal();
startJournal();
@@ -1610,7 +1821,7 @@
createJournal();
startJournal();
load();
- add(1,3,5,7,10,13,56,100,102,200,201,202,203);
+ add(1,3,5,7,10,13,56,100,102,200,201,202,203);
stopJournal();
createJournal();
startJournal();
@@ -1623,7 +1834,7 @@
createJournal();
startJournal();
load();
- add(1);
+ add(1);
update(1);
stopJournal();
createJournal();
@@ -1637,7 +1848,7 @@
createJournal();
startJournal();
load();
- add(1,2,3,4,5,6,7,8,9,10);
+ add(1,2,3,4,5,6,7,8,9,10);
update(1,2,4,7,9,10);
stopJournal();
createJournal();
@@ -1651,7 +1862,7 @@
createJournal();
startJournal();
load();
- add(1,2,3,4,5,6,7,8,9,10);
+ add(1,2,3,4,5,6,7,8,9,10);
update(1,2,3,4,5,6,7,8,9,10);
stopJournal();
createJournal();
@@ -1665,8 +1876,8 @@
createJournal();
startJournal();
load();
- add(1,3,5,7,10,13,56,100,102,200,201,202,203);
- add(3,7,10,13,56,100,200,202,203);
+ add(1,3,5,7,10,13,56,100,102,200,201,202,203);
+ add(3,7,10,13,56,100,200,202,203);
stopJournal();
createJournal();
startJournal();
@@ -1686,14 +1897,14 @@
startJournal();
loadAndCheck();
}
-
+
public void testSimpleAddUpdateDelete() throws Exception
{
setup(10, 10 * 1024, true);
createJournal();
startJournal();
load();
- add(1);
+ add(1);
update(1);
delete(1);
stopJournal();
@@ -1708,7 +1919,7 @@
createJournal();
startJournal();
load();
- add(1,2,3,4,5,6,7,8,9,10);
+ add(1,2,3,4,5,6,7,8,9,10);
update(1,2,4,7,9,10);
delete(1,4,7,9,10);
stopJournal();
@@ -1723,7 +1934,7 @@
createJournal();
startJournal();
load();
- add(1,2,3,4,5,6,7,8,9,10);
+ add(1,2,3,4,5,6,7,8,9,10);
update(1,2,3,4,5,6,7,8,9,10);
update(1,2,3,4,5,6,7,8,9,10);
stopJournal();
@@ -1738,9 +1949,9 @@
createJournal();
startJournal();
load();
- add(1,3,5,7,10,13,56,100,102,200,201,202,203);
- add(3,7,10,13,56,100,200,202,203);
- delete(3,10,56,100,200,203);
+ add(1,3,5,7,10,13,56,100,102,200,201,202,203);
+ add(3,7,10,13,56,100,200,202,203);
+ delete(3,10,56,100,200,203);
stopJournal();
createJournal();
startJournal();
@@ -1759,7 +1970,7 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testMultipleAddUpdateDeleteDifferentOrder() throws Exception
@@ -1774,9 +1985,9 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
-
+
public void testMultipleAddUpdateDeleteDifferentRecordLengths() throws Exception
{
setup(10, 2048, true);
@@ -1813,7 +2024,7 @@
createJournal();
startJournal();
loadAndCheck();
- stopJournal();
+ stopJournal();
}
@@ -1877,17 +2088,17 @@
}
public void testFillFileExactly() throws Exception
- {
+ {
this.recordLength = 500;
int numRecords = 2;
//The real appended record size in the journal file = SIZE_BYTE + SIZE_LONG + SIZE_INT + recordLength + SIZE_BYTE
- int realLength = 1 + 8 + 4 + this.recordLength + 1;
+ int realLength = calculateRecordSize(JournalImpl.SIZE_ADD_RECORD + this.recordLength, getAlignment());
- int fileSize = numRecords * realLength + 8; //8 for timestamp
-
+ int fileSize = numRecords * realLength + calculateRecordSize(8, getAlignment()); //8 for timestamp
+
setup(10, fileSize, true);
createJournal();
@@ -1913,27 +2124,27 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
// Transactional tests
// ===================
-
- public void testSimpleTransaction() throws Exception
- {
+
+ public void testSimpleTransaction() throws Exception
+ {
setup(10, 10 * 1024, true);
createJournal();
startJournal();
load();
addTx(1, 1);
- updateTx(1, 1);
- deleteTx(1, 1);
+ updateTx(1, 1);
+ deleteTx(1, 1);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
- }
+ loadAndCheck();
+ }
public void testTransactionDontDeleteAll() throws Exception
{
@@ -1942,13 +2153,13 @@
startJournal();
load();
addTx(1, 1, 2, 3);
- updateTx(1, 1, 2);
- deleteTx(1, 1);
+ updateTx(1, 1, 2);
+ deleteTx(1, 1);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testTransactionDeleteAll() throws Exception
@@ -1958,13 +2169,13 @@
startJournal();
load();
addTx(1, 1, 2, 3);
- updateTx(1, 1, 2);
+ updateTx(1, 1, 2);
deleteTx(1, 1, 2, 3);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testTransactionUpdateFromBeforeTx() throws Exception
@@ -1980,7 +2191,7 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testTransactionDeleteFromBeforeTx() throws Exception
@@ -1996,7 +2207,7 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testTransactionChangesNotVisibleOutsideTX() throws Exception
@@ -2012,7 +2223,7 @@
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testMultipleTransactionsDifferentIDs() throws Exception
@@ -2050,14 +2261,14 @@
startJournal();
load();
- addTx(1, 1, 2, 3, 4, 5, 6);
- addTx(3, 21, 22, 23, 24, 25, 26);
- updateTx(1, 1, 3, 5);
- addTx(2, 11, 12, 13, 14, 15, 16);
- deleteTx(1, 1, 2, 3, 4, 5, 6);
- updateTx(2, 11, 13, 15);
- updateTx(3, 21, 23, 25);
- deleteTx(2, 11, 12, 13, 14, 15, 16);
+ addTx(1, 1, 2, 3, 4, 5, 6);
+ addTx(3, 21, 22, 23, 24, 25, 26);
+ updateTx(1, 1, 3, 5);
+ addTx(2, 11, 12, 13, 14, 15, 16);
+ deleteTx(1, 1, 2, 3, 4, 5, 6);
+ updateTx(2, 11, 13, 15);
+ updateTx(3, 21, 23, 25);
+ deleteTx(2, 11, 12, 13, 14, 15, 16);
deleteTx(3, 21, 22, 23, 24, 25, 26);
commit(1);
@@ -2076,18 +2287,18 @@
createJournal();
startJournal();
load();
-
- add(1, 2, 3, 4, 5, 6, 7, 8);
- addTx(1, 9, 10, 11, 12);
- addTx(2, 13, 14, 15, 16, 17);
- addTx(3, 18, 19, 20, 21, 22);
- updateTx(1, 1, 2, 3);
- updateTx(2, 4, 5, 6);
- commit(2);
- updateTx(3, 7, 8);
- deleteTx(1, 1, 2);
- commit(1);
- deleteTx(3, 7, 8);
+
+ add(1, 2, 3, 4, 5, 6, 7, 8);
+ addTx(1, 9, 10, 11, 12);
+ addTx(2, 13, 14, 15, 16, 17);
+ addTx(3, 18, 19, 20, 21, 22);
+ updateTx(1, 1, 2, 3);
+ updateTx(2, 4, 5, 6);
+ commit(2);
+ updateTx(3, 7, 8);
+ deleteTx(1, 1, 2);
+ commit(1);
+ deleteTx(3, 7, 8);
commit(3);
stopJournal();
@@ -2102,17 +2313,17 @@
createJournal();
startJournal();
load();
- add(1,3,5,7,10,13,56,100,102,200,201,202,203);
+ add(1,3,5,7,10,13,56,100,102,200,201,202,203);
addTx(1, 675, 676, 677, 700, 703);
- update(1,3,5,7,10,13,56,100,102,200,201,202,203);
- updateTx(1, 677, 700);
- delete(1,3,5,7,10,13,56,100,102,200,201,202,203);
- deleteTx(1, 703, 675);
+ update(1,3,5,7,10,13,56,100,102,200,201,202,203);
+ updateTx(1, 677, 700);
+ delete(1,3,5,7,10,13,56,100,102,200,201,202,203);
+ deleteTx(1, 703, 675);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testTransactionAddDeleteDifferentOrder() throws Exception
@@ -2120,14 +2331,14 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
- deleteTx(1, 9, 8, 5, 3, 7, 6, 2, 1, 4);
+ load();
+ addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ deleteTx(1, 9, 8, 5, 3, 7, 6, 2, 1, 4);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testAddOutsideTXThenUpdateInsideTX() throws Exception
@@ -2135,7 +2346,7 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3);
updateTx(1, 1, 2, 3);
commit(1);
@@ -2150,7 +2361,7 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3);
deleteTx(1, 1, 2, 3);
commit(1);
@@ -2165,7 +2376,7 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3);
deleteTx(1, 1, 2, 3);
rollback(1);
@@ -2180,7 +2391,7 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3);
deleteTx(1, 1, 2, 3);
addTx(2, 4, 5, 6);
@@ -2197,9 +2408,9 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3);
- deleteTx(1, 1, 2, 3);
+ load();
+ addTx(1, 1, 2, 3);
+ deleteTx(1, 1, 2, 3);
commit(1);
stopJournal();
createJournal();
@@ -2212,8 +2423,8 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3);
+ load();
+ addTx(1, 1, 2, 3);
try
{
update(1);
@@ -2235,8 +2446,8 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3);
+ load();
+ addTx(1, 1, 2, 3);
try
{
delete(1);
@@ -2256,36 +2467,36 @@
// XA tests
// ========
-
- public void testXASimpleNotPrepared() throws Exception
- {
+
+ public void testXASimpleNotPrepared() throws Exception
+ {
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ load();
+ addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
updateTx(1, 1, 2, 3, 4, 7, 8);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
- }
+ loadAndCheck();
+ }
public void testXASimplePrepared() throws Exception
{
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ load();
+ addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
updateTx(1, 1, 2, 3, 4, 7, 8);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
prepare(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXASimpleCommit() throws Exception
@@ -2293,16 +2504,16 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ load();
+ addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
updateTx(1, 1, 2,3, 4, 7, 8);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
prepare(1);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXASimpleRollback() throws Exception
@@ -2310,16 +2521,16 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
- addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ load();
+ addTx(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);
updateTx(1, 1, 2,3, 4, 7, 8);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
prepare(1);
rollback(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXAChangesNotVisibleNotPrepared() throws Exception
@@ -2327,15 +2538,15 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3, 4, 5, 6);
- addTx(1, 7, 8, 9, 10);
+ addTx(1, 7, 8, 9, 10);
updateTx(1, 1, 2, 3, 7, 8, 9);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXAChangesNotVisiblePrepared() throws Exception
@@ -2343,16 +2554,16 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3, 4, 5, 6);
- addTx(1, 7, 8, 9, 10);
+ addTx(1, 7, 8, 9, 10);
updateTx(1, 1, 2, 3, 7, 8, 9);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
prepare(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXAChangesNotVisibleRollback() throws Exception
@@ -2360,17 +2571,17 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3, 4, 5, 6);
- addTx(1, 7, 8, 9, 10);
+ addTx(1, 7, 8, 9, 10);
updateTx(1, 1, 2, 3, 7, 8, 9);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
prepare(1);
rollback(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXAChangesisibleCommit() throws Exception
@@ -2378,17 +2589,17 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3, 4, 5, 6);
- addTx(1, 7, 8, 9, 10);
+ addTx(1, 7, 8, 9, 10);
updateTx(1, 1, 2, 3, 7, 8, 9);
- deleteTx(1, 1, 2, 3, 4, 5);
+ deleteTx(1, 1, 2, 3, 4, 5);
prepare(1);
commit(1);
stopJournal();
createJournal();
startJournal();
- loadAndCheck();
+ loadAndCheck();
}
public void testXAMultiple() throws Exception
@@ -2396,7 +2607,7 @@
setup(10, 10 * 1024, true);
createJournal();
startJournal();
- load();
+ load();
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
addTx(1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
addTx(2, 21, 22, 23, 24, 25, 26, 27);
@@ -2414,30 +2625,39 @@
rollback(2);
commit(3);
}
-
+
public void testTransactionOnDifferentFiles() throws Exception
- {
- setup(2, 512 + 2*1024, true);
+ {
+ setup(2, 512 + 2*1024, true);
+
+ createJournal();
+ startJournal();
+ load();
+
+ addTx(1, 1, 2, 3, 4, 5, 6);
+ updateTx(1, 1, 3, 5);
+ commit(1);
+ deleteTx(2, 1, 2, 3, 4, 5, 6);
+ commit(2);
+
+
+
+// // Just to make sure the commit won't be released. The commit will be on the same file as addTx(3);
+addTx(3, 11);
+addTx(4, 31);
+commit(3);
- createJournal();
- startJournal();
- load();
+log.info("Debug on Journal before stopJournal - \n" + debugJournal());
- addTx(1, 1, 2, 3, 4, 5, 6);
- updateTx(1, 1, 3, 5);
- commit(1);
- deleteTx(2, 1, 2, 3, 4, 5, 6);
- commit(2);
-
- // Just to make sure the commit won't be released. The commit will be on the same file as addTx(3);
- addTx(3, 11, 12);
-
- stopJournal();
- createJournal();
- startJournal();
- loadAndCheck();
-
-
- }
+stopJournal();
+createJournal();
+startJournal();
+loadAndCheck();
+
+ }
+
+ protected abstract int getAlignment();
+
+
}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealAIOJournalImplTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealAIOJournalImplTest.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealAIOJournalImplTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,69 @@
+/*
+ * 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.journal.impl;
+
+import java.io.File;
+
+import org.jboss.messaging.core.journal.SequentialFileFactory;
+import org.jboss.messaging.core.journal.impl.AIOSequentialFileFactory;
+import org.jboss.messaging.core.logging.Logger;
+
+
+/**
+ *
+ * A RealJournalImplTest
+ * you need to define -Djava.library.path=${project-root}/native/src/.libs when calling the JVM
+ * If you are running this test in eclipse you should do:
+ * I - Run->Open Run Dialog
+ * II - Find the class on the list (you will find it if you already tried running this testcase before)
+ * III - Add -Djava.library.path=<your project place>/native/src/.libs
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealAIOJournalImplTest extends JournalImplTestUnit
+{
+ private static final Logger log = Logger.getLogger(RealAIOJournalImplTest.class);
+
+ protected String journalDir = System.getProperty("user.home") + "/journal-test";
+
+ protected SequentialFileFactory getFileFactory() throws Exception
+ {
+ File file = new File(journalDir);
+
+ log.info("deleting directory " + journalDir);
+
+ deleteDirectory(file);
+
+ file.mkdir();
+
+ return new AIOSequentialFileFactory(journalDir);
+ }
+
+ protected int getAlignment()
+ {
+ return 512;
+ }
+
+}
Deleted: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealJournalImplTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealJournalImplTest.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealJournalImplTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -1,56 +0,0 @@
-/*
- * 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.journal.impl;
-
-import java.io.File;
-
-import org.jboss.messaging.core.journal.SequentialFileFactory;
-import org.jboss.messaging.core.journal.impl.NIOSequentialFileFactory;
-import org.jboss.messaging.core.logging.Logger;
-
-/**
- *
- * A RealJournalImplTest
- *
- * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
- *
- */
-public class RealJournalImplTest extends JournalImplTestUnit
-{
- private static final Logger log = Logger.getLogger(RealJournalImplTest.class);
-
- protected String journalDir = System.getProperty("user.home") + "/journal-test";
-
- protected SequentialFileFactory getFileFactory() throws Exception
- {
- File file = new File(journalDir);
-
- log.info("deleting directory " + journalDir);
-
- deleteDirectory(file);
-
- file.mkdir();
-
- return new NIOSequentialFileFactory(journalDir);
- }
-
-}
Added: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealNIOJournalImplTest.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealNIOJournalImplTest.java (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/RealNIOJournalImplTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,65 @@
+/*
+ * 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.journal.impl;
+
+import java.io.File;
+
+import org.jboss.messaging.core.journal.SequentialFileFactory;
+import org.jboss.messaging.core.journal.impl.NIOSequentialFileFactory;
+import org.jboss.messaging.core.logging.Logger;
+
+
+/**
+ *
+ * A RealJournalImplTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealNIOJournalImplTest extends JournalImplTestUnit
+{
+ private static final Logger log = Logger.getLogger(RealNIOJournalImplTest.class);
+
+ protected String journalDir = System.getProperty("user.home") + "/journal-test";
+
+ protected SequentialFileFactory getFileFactory() throws Exception
+ {
+ File file = new File(journalDir);
+
+ log.info("deleting directory " + journalDir);
+
+ deleteDirectory(file);
+
+ file.mkdir();
+
+ return new NIOSequentialFileFactory(journalDir);
+ }
+
+ protected int getAlignment()
+ {
+ return 1;
+ }
+
+
+}
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -40,287 +40,296 @@
*/
public abstract class SequentialFileFactoryTestBase extends UnitTestCase
{
- private static final Logger log = Logger.getLogger(SequentialFileFactoryTestBase.class);
-
-
- protected void setUp() throws Exception
- {
- super.setUp();
-
- factory = createFactory();
- }
-
- protected abstract SequentialFileFactory createFactory();
-
- private SequentialFileFactory factory;
-
- public void testCreateAndListFiles() throws Exception
- {
- List<String> expectedFiles = new ArrayList<String>();
-
- final int numFiles = 10;
-
- for (int i = 0; i < numFiles; i++)
- {
- String fileName = UUID.randomUUID().toString() + ".jbm";
-
- expectedFiles.add(fileName);
-
- SequentialFile sf = factory.createSequentialFile(fileName, false);
-
- sf.open();
-
- assertEquals(fileName, sf.getFileName());
- }
-
- //Create a couple with a different extension - they shouldn't be picked up
-
- SequentialFile sf1 = factory.createSequentialFile("different.file", false);
- sf1.open();
-
- SequentialFile sf2 = factory.createSequentialFile("different.cheese", false);
- sf2.open();
-
- List<String> fileNames = factory.listFiles("jbm");
-
- assertEquals(expectedFiles.size(), fileNames.size());
-
- for (String fileName: expectedFiles)
- {
- assertTrue(fileNames.contains(fileName));
- }
-
- fileNames = factory.listFiles("file");
-
- assertEquals(1, fileNames.size());
-
- assertTrue(fileNames.contains("different.file"));
-
- fileNames = factory.listFiles("cheese");
-
- assertEquals(1, fileNames.size());
-
- assertTrue(fileNames.contains("different.cheese"));
- }
-
-
- public void testFill() throws Exception
- {
- SequentialFile sf = factory.createSequentialFile("fill.jbm", true);
-
- sf.open();
-
- checkFill(sf, 0, 100, (byte)'X');
-
- checkFill(sf, 13, 300, (byte)'Y');
-
- checkFill(sf, 0, 1, (byte)'Z');
-
- checkFill(sf, 100, 1, (byte)'A');
-
- checkFill(sf, 1000, 10000, (byte)'B');
- }
-
- public void testDelete() throws Exception
- {
- SequentialFile sf = factory.createSequentialFile("delete-me.jbm", true);
-
- sf.open();
-
- SequentialFile sf2 = factory.createSequentialFile("delete-me2.jbm", true);
-
- sf2.open();
-
- List<String> fileNames = factory.listFiles("jbm");
-
- assertEquals(2, fileNames.size());
-
- assertTrue(fileNames.contains("delete-me.jbm"));
-
- assertTrue(fileNames.contains("delete-me2.jbm"));
-
- sf.delete();
-
- fileNames = factory.listFiles("jbm");
-
- assertEquals(1, fileNames.size());
-
- assertTrue(fileNames.contains("delete-me2.jbm"));
-
- }
-
- public void testWriteandRead() throws Exception
- {
- SequentialFile sf = factory.createSequentialFile("write.jbm", true);
-
- sf.open();
-
- String s1 = "aardvark";
- byte[] bytes1 = s1.getBytes("UTF-8");
- ByteBuffer bb1 = ByteBuffer.wrap(bytes1);
-
- String s2 = "hippopotamus";
- byte[] bytes2 = s2.getBytes("UTF-8");
- ByteBuffer bb2 = ByteBuffer.wrap(bytes2);
-
- String s3 = "echidna";
- byte[] bytes3 = s3.getBytes("UTF-8");
- ByteBuffer bb3 = ByteBuffer.wrap(bytes3);
-
- int bytesWritten = sf.write(bb1, true);
-
- assertEquals(bytes1.length, bytesWritten);
-
- bytesWritten = sf.write(bb2, true);
-
- assertEquals(bytes2.length, bytesWritten);
-
- bytesWritten = sf.write(bb3, true);
-
- assertEquals(bytes3.length, bytesWritten);
-
- sf.position(0);
-
- byte[] rbytes1 = new byte[bytes1.length];
-
- byte[] rbytes2 = new byte[bytes2.length];
-
- byte[] rbytes3 = new byte[bytes3.length];
-
- ByteBuffer rb1 = ByteBuffer.wrap(rbytes1);
- ByteBuffer rb2 = ByteBuffer.wrap(rbytes2);
- ByteBuffer rb3 = ByteBuffer.wrap(rbytes3);
+ private static final Logger log = Logger.getLogger(SequentialFileFactoryTestBase.class);
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ factory = createFactory();
+ }
+
+ protected abstract SequentialFileFactory createFactory();
+
+ protected SequentialFileFactory factory;
+
+ public void testCreateAndListFiles() throws Exception
+ {
+ List<String> expectedFiles = new ArrayList<String>();
+
+ final int numFiles = 10;
+
+ for (int i = 0; i < numFiles; i++)
+ {
+ String fileName = UUID.randomUUID().toString() + ".jbm";
+
+ expectedFiles.add(fileName);
+
+ SequentialFile sf = factory.createSequentialFile(fileName, false);
+
+ sf.open();
+
+ assertEquals(fileName, sf.getFileName());
+ }
+
+ //Create a couple with a different extension - they shouldn't be picked up
+
+ SequentialFile sf1 = factory.createSequentialFile("different.file", false);
+ sf1.open();
+
+ SequentialFile sf2 = factory.createSequentialFile("different.cheese", false);
+ sf2.open();
+
+ List<String> fileNames = factory.listFiles("jbm");
+
+ assertEquals(expectedFiles.size(), fileNames.size());
+
+ for (String fileName: expectedFiles)
+ {
+ assertTrue(fileNames.contains(fileName));
+ }
+
+ fileNames = factory.listFiles("file");
+
+ assertEquals(1, fileNames.size());
+
+ assertTrue(fileNames.contains("different.file"));
+
+ fileNames = factory.listFiles("cheese");
+
+ assertEquals(1, fileNames.size());
+
+ assertTrue(fileNames.contains("different.cheese"));
+ }
+
+
+ public void testFill() throws Exception
+ {
+ SequentialFile sf = factory.createSequentialFile("fill.jbm", true);
+
+ sf.open();
+
+ 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');
+ }
+
+ public void testDelete() throws Exception
+ {
+ SequentialFile sf = factory.createSequentialFile("delete-me.jbm", true);
+
+ sf.open();
+
+ SequentialFile sf2 = factory.createSequentialFile("delete-me2.jbm", true);
+
+ sf2.open();
+
+ List<String> fileNames = factory.listFiles("jbm");
+
+ assertEquals(2, fileNames.size());
+
+ assertTrue(fileNames.contains("delete-me.jbm"));
+
+ assertTrue(fileNames.contains("delete-me2.jbm"));
+
+ sf.delete();
+
+ fileNames = factory.listFiles("jbm");
+
+ assertEquals(1, fileNames.size());
+
+ assertTrue(fileNames.contains("delete-me2.jbm"));
+
+ }
+
+ public void testWriteandRead() throws Exception
+ {
+ SequentialFile sf = factory.createSequentialFile("write.jbm", true);
+
+ sf.open();
+
+ String s1 = "aardvark";
+ byte[] bytes1 = s1.getBytes("UTF-8");
+ ByteBuffer bb1 = sf.wrapBuffer(bytes1);
+
+ String s2 = "hippopotamus";
+ byte[] bytes2 = s2.getBytes("UTF-8");
+ ByteBuffer bb2 = sf.wrapBuffer(bytes2);
+
+ String s3 = "echidna";
+ byte[] bytes3 = s3.getBytes("UTF-8");
+ ByteBuffer bb3 = sf.wrapBuffer(bytes3);
+
+ int bytesWritten = sf.write(bb1, true);
+
+ assertEquals(calculateRecordSize(bytes1.length, sf.getAlignment()), bytesWritten);
+
+ bytesWritten = sf.write(bb2, true);
+
+ assertEquals(calculateRecordSize(bytes2.length, sf.getAlignment()), bytesWritten);
+
+ bytesWritten = sf.write(bb3, true);
+
+ 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);
- int bytesRead = sf.read(rb1);
- assertEquals(rbytes1.length, bytesRead);
- assertByteArraysEquivalent(bytes1, rbytes1);
-
- bytesRead = sf.read(rb2);
- assertEquals(rbytes2.length, bytesRead);
- assertByteArraysEquivalent(bytes2, rbytes2);
-
- bytesRead = sf.read(rb3);
- assertEquals(rbytes3.length, bytesRead);
- assertByteArraysEquivalent(bytes3, rbytes3);
- }
-
- public void testPosition() throws Exception
- {
- SequentialFile sf = factory.createSequentialFile("position.jbm", true);
-
- sf.open();
-
- String s1 = "orange";
- byte[] bytes1 = s1.getBytes("UTF-8");
- ByteBuffer bb1 = ByteBuffer.wrap(bytes1);
-
- String s2 = "grapefruit";
- byte[] bytes2 = s2.getBytes("UTF-8");
- ByteBuffer bb2 = ByteBuffer.wrap(bytes2);
-
- String s3 = "lemon";
- byte[] bytes3 = s3.getBytes("UTF-8");
- ByteBuffer bb3 = ByteBuffer.wrap(bytes3);
-
- int bytesWritten = sf.write(bb1, true);
-
- assertEquals(bytes1.length, bytesWritten);
-
- bytesWritten = sf.write(bb2, true);
-
- assertEquals(bytes2.length, bytesWritten);
-
- bytesWritten = sf.write(bb3, true);
-
- assertEquals(bytes3.length, bytesWritten);
-
- byte[] rbytes1 = new byte[bytes1.length];
-
- byte[] rbytes2 = new byte[bytes2.length];
-
- byte[] rbytes3 = new byte[bytes3.length];
-
- ByteBuffer rb1 = ByteBuffer.wrap(rbytes1);
- ByteBuffer rb2 = ByteBuffer.wrap(rbytes2);
- ByteBuffer rb3 = ByteBuffer.wrap(rbytes3);
-
- sf.position(bytes1.length + bytes2.length);
-
- int bytesRead = sf.read(rb3);
- assertEquals(rbytes3.length, bytesRead);
- assertByteArraysEquivalent(bytes3, rbytes3);
-
- sf.position(bytes1.length);
-
- bytesRead = sf.read(rb2);
- assertEquals(rbytes2.length, bytesRead);
- assertByteArraysEquivalent(bytes2, rbytes2);
-
- sf.position(0);
-
- bytesRead = sf.read(rb1);
- assertEquals(rbytes1.length, bytesRead);
- assertByteArraysEquivalent(bytes1, rbytes1);
- }
-
- public void testOpenClose() throws Exception
- {
- SequentialFile sf = factory.createSequentialFile("openclose.jbm", true);
-
- sf.open();
-
- String s1 = "cheesecake";
- byte[] bytes1 = s1.getBytes("UTF-8");
- ByteBuffer bb1 = ByteBuffer.wrap(bytes1);
-
- int bytesWritten = sf.write(bb1, true);
-
- assertEquals(bytes1.length, bytesWritten);
-
- sf.close();
-
- try
- {
- sf.write(bb1, true);
-
- fail("Should throw exception");
- }
- catch (Exception e)
- {
- //OK
- }
-
- sf.open();
-
- sf.write(bb1, true);
- }
-
- // Private ---------------------------------
-
- private void checkFill(SequentialFile file, int pos, int size, byte fillChar) throws Exception
- {
- file.fill(pos, size, fillChar);
-
- file.close();
-
- file.open();
-
- file.position(pos);
-
- byte[] bytes = new byte[size];
-
- ByteBuffer bb = ByteBuffer.wrap(bytes);
-
- int bytesRead = file.read(bb);
-
- assertEquals(size, bytesRead);
-
- for (int i = 0; i < size; i++)
- {
- //log.info(" i is " + i);
- assertEquals(fillChar, bytes[i]);
- }
-
- }
-
+ int bytesRead = sf.read(rb1);
+ assertEquals(calculateRecordSize(bytes1.length, sf.getAlignment()), bytesRead);
+
+ for (int i=0; i<bytes1.length; i++)
+ {
+ assertEquals(bytes1[i], rb1.get(i));
+ }
+
+ bytesRead = sf.read(rb2);
+ assertEquals(calculateRecordSize(bytes2.length, sf.getAlignment()), bytesRead);
+ for (int i=0; i<bytes2.length; i++)
+ {
+ assertEquals(bytes2[i], rb2.get(i));
+ }
+
+
+ bytesRead = sf.read(rb3);
+ assertEquals(calculateRecordSize(bytes3.length, sf.getAlignment()), bytesRead);
+ for (int i=0; i<bytes3.length; i++)
+ {
+ assertEquals(bytes3[i], rb3.get(i));
+ }
+
+ }
+
+ public void testPosition() throws Exception
+ {
+ SequentialFile sf = factory.createSequentialFile("position.jbm", true);
+
+ sf.open();
+
+ String s1 = "orange";
+ byte[] bytes1 = s1.getBytes("UTF-8");
+ ByteBuffer bb1 = sf.wrapBuffer(bytes1);
+
+ String s2 = "grapefruit";
+ byte[] bytes2 = s2.getBytes("UTF-8");
+ ByteBuffer bb2 = sf.wrapBuffer(bytes2);
+
+ String s3 = "lemon";
+ byte[] bytes3 = s3.getBytes("UTF-8");
+ ByteBuffer bb3 = sf.wrapBuffer(bytes3);
+
+ int bytesWritten = sf.write(bb1, true);
+
+ assertEquals(bb1.limit(), bytesWritten);
+
+ bytesWritten = sf.write(bb2, true);
+
+ assertEquals(bb2.limit(), bytesWritten);
+
+ bytesWritten = sf.write(bb3, true);
+
+ assertEquals(bb3.limit(), bytesWritten);
+
+ byte[] rbytes1 = new byte[bytes1.length];
+
+ byte[] rbytes2 = new byte[bytes2.length];
+
+ byte[] rbytes3 = new byte[bytes3.length];
+
+ ByteBuffer rb1 = sf.newBuffer(rbytes1.length);
+ ByteBuffer rb2 = sf.newBuffer(rbytes2.length);
+ ByteBuffer rb3 = sf.newBuffer(rbytes3.length);
+
+ sf.position(bb1.limit() + bb2.limit());
+
+ int bytesRead = sf.read(rb3);
+ assertEquals(rb3.limit(), bytesRead);
+ rb3.rewind();
+ rb3.get(rbytes3);
+ assertByteArraysEquivalent(bytes3, rbytes3);
+
+ sf.position(rb1.limit());
+
+ bytesRead = sf.read(rb2);
+ assertEquals(rb2.limit(), bytesRead);
+ rb2.get(rbytes2);
+ assertByteArraysEquivalent(bytes2, rbytes2);
+
+ sf.position(0);
+
+ bytesRead = sf.read(rb1);
+ assertEquals(rb1.limit(), bytesRead);
+ rb1.get(rbytes1);
+
+ assertByteArraysEquivalent(bytes1, rbytes1);
+ }
+
+ public void testOpenClose() throws Exception
+ {
+ SequentialFile sf = factory.createSequentialFile("openclose.jbm", true);
+
+ sf.open();
+
+ String s1 = "cheesecake";
+ byte[] bytes1 = s1.getBytes("UTF-8");
+ ByteBuffer bb1 = sf.wrapBuffer(bytes1);
+
+ int bytesWritten = sf.write(bb1, true);
+
+ assertEquals(bb1.limit(), bytesWritten);
+
+ sf.close();
+
+ try
+ {
+ sf.write(bb1, true);
+
+ fail("Should throw exception");
+ }
+ catch (Exception e)
+ {
+ //OK
+ }
+
+ sf.open();
+
+ sf.write(bb1, true);
+ }
+
+ // Private ---------------------------------
+
+ protected void checkFill(SequentialFile file, int pos, int size, byte fillChar) throws Exception
+ {
+ file.fill(pos, size, fillChar);
+
+ file.close();
+
+ file.open();
+
+ file.position(pos);
+
+ ByteBuffer bb = file.newBuffer(size);
+
+ int bytesRead = file.read(bb);
+
+ assertEquals(calculateRecordSize(size, file.getAlignment()), bytesRead);
+
+ for (int i = 0; i < size; i++)
+ {
+ //log.info(" i is " + i);
+ assertEquals(fillChar, bb.get(i));
+ }
+
+ }
+
}
Deleted: trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFile.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFile.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFile.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -1,6 +0,0 @@
-package org.jboss.messaging.tests.unit.core.journal.impl.fakes;
-
-public class FakeSequentialFile
-{
-
-}
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -27,6 +27,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import org.jboss.messaging.core.journal.IOCallback;
import org.jboss.messaging.core.journal.SequentialFile;
import org.jboss.messaging.core.journal.SequentialFileFactory;
import org.jboss.messaging.core.logging.Logger;
@@ -40,212 +41,250 @@
*/
public class FakeSequentialFileFactory implements SequentialFileFactory
{
- private static final Logger log = Logger.getLogger(FakeSequentialFileFactory.class);
-
- private Map<String, FakeSequentialFile> fileMap = new ConcurrentHashMap<String, FakeSequentialFile>();
-
- public SequentialFile createSequentialFile(final String fileName, final boolean sync) throws Exception
- {
- FakeSequentialFile sf = fileMap.get(fileName);
-
- if (sf == null)
- {
- sf = new FakeSequentialFile(fileName, sync);
-
- fileMap.put(fileName, sf);
- }
- else
- {
- sf.data.position(0);
-
- //log.info("positioning data to 0");
- }
-
- return sf;
- }
-
- public List<String> listFiles(final String extension)
- {
- List<String> files = new ArrayList<String>();
-
- for (String s: fileMap.keySet())
- {
- if (s.endsWith("." + extension))
- {
- files.add(s);
- }
- }
-
- return files;
- }
-
- public Map<String, FakeSequentialFile> getFileMap()
- {
- return fileMap;
- }
-
- public void clear()
- {
- fileMap.clear();
- }
-
- public class FakeSequentialFile implements SequentialFile
- {
- private volatile boolean open;
-
- private final String fileName;
-
- private final boolean sync;
-
- private volatile ByteBuffer data;
-
- public ByteBuffer getData()
- {
- return data;
- }
-
- public boolean isSync()
- {
- return sync;
- }
-
- public boolean isOpen()
- {
- //log.info("is open" + System.identityHashCode(this) +" open is now " + open);
- return open;
- }
-
- public FakeSequentialFile(final String fileName, final boolean sync)
- {
- this.fileName = fileName;
-
- this.sync = sync;
- }
+ private static final Logger log = Logger.getLogger(FakeSequentialFileFactory.class);
+
+ private Map<String, FakeSequentialFile> fileMap = new ConcurrentHashMap<String, FakeSequentialFile>();
+
+ public SequentialFile createSequentialFile(final String fileName, final boolean sync) throws Exception
+ {
+ FakeSequentialFile sf = fileMap.get(fileName);
+
+ if (sf == null)
+ {
+ sf = new FakeSequentialFile(fileName, sync);
+
+ fileMap.put(fileName, sf);
+ }
+ else
+ {
+ sf.data.position(0);
+
+ //log.info("positioning data to 0");
+ }
+
+ return sf;
+ }
+
+ public List<String> listFiles(final String extension)
+ {
+ List<String> files = new ArrayList<String>();
+
+ for (String s: fileMap.keySet())
+ {
+ if (s.endsWith("." + extension))
+ {
+ files.add(s);
+ }
+ }
+
+ return files;
+ }
+
+ public Map<String, FakeSequentialFile> getFileMap()
+ {
+ return fileMap;
+ }
+
+ public void clear()
+ {
+ fileMap.clear();
+ }
+
+ public class FakeSequentialFile implements SequentialFile
+ {
+ private volatile boolean open;
+
+ private final String fileName;
+
+ private final boolean sync;
+
+ private volatile ByteBuffer data;
+
+ public ByteBuffer getData()
+ {
+ return data;
+ }
+
+ public boolean isSync()
+ {
+ return sync;
+ }
+
+ public boolean isOpen()
+ {
+ //log.info("is open" + System.identityHashCode(this) +" open is now " + open);
+ return open;
+ }
+
+ public FakeSequentialFile(final String fileName, final boolean sync)
+ {
+ this.fileName = fileName;
+
+ this.sync = sync;
+ }
- public void close() throws Exception
- {
- open = false;
-
- if (data != null)
- {
- data.position(0);
- }
- }
+ public void close() throws Exception
+ {
+ open = false;
+
+ if (data != null)
+ {
+ data.position(0);
+ }
+ }
- public void delete() throws Exception
- {
- if (!open)
- {
- throw new IllegalStateException("Is closed");
- }
- close();
-
- fileMap.remove(fileName);
- }
+ public void delete() throws Exception
+ {
+ if (!open)
+ {
+ throw new IllegalStateException("Is closed");
+ }
+ close();
+
+ fileMap.remove(fileName);
+ }
- public String getFileName()
- {
- if (!open)
- {
- throw new IllegalStateException("Is closed");
- }
- return fileName;
- }
-
- public void open() throws Exception
- {
- open = true;
- }
+ public String getFileName()
+ {
+ return fileName;
+ }
+
+ public void open() throws Exception
+ {
+ open = true;
+ }
- public void fill(int pos, int size, byte fillCharacter) throws Exception
- {
- if (!open)
- {
- throw new IllegalStateException("Is closed");
- }
-
- checkAndResize(pos + size);
-
- //log.info("size is " + size + " pos is " + pos);
-
- for (int i = pos; i < size + pos; i++)
- {
- data.array()[i] = fillCharacter;
-
- //log.info("Filling " + pos + " with char " + fillCharacter);
- }
- }
-
- public int read(ByteBuffer bytes) throws Exception
- {
- if (!open)
- {
- throw new IllegalStateException("Is closed");
- }
-
- //log.info("read called " + bytes.array().length);
-
- byte[] bytesRead = new byte[bytes.array().length];
-
- //log.info("reading, data pos is " + data.position() + " data size is " + data.array().length);
-
- data.get(bytesRead);
-
- bytes.put(bytesRead);
-
- return bytesRead.length;
- }
+ public void fill(int pos, int size, byte fillCharacter) throws Exception
+ {
+ if (!open)
+ {
+ throw new IllegalStateException("Is closed");
+ }
+
+ checkAndResize(pos + size);
+
+ //log.info("size is " + size + " pos is " + pos);
+
+ for (int i = pos; i < size + pos; i++)
+ {
+ data.array()[i] = fillCharacter;
+
+ //log.info("Filling " + pos + " with char " + fillCharacter);
+ }
+ }
+
+ public int read(ByteBuffer bytes) throws Exception
+ {
+ return read(bytes, null);
+ }
+
+ public int read(ByteBuffer bytes, IOCallback callback) throws Exception
+ {
+ if (!open)
+ {
+ throw new IllegalStateException("Is closed");
+ }
+
+ //log.info("read called " + bytes.array().length);
+
+ byte[] bytesRead = new byte[bytes.array().length];
+
+ //log.info("reading, data pos is " + data.position() + " data size is " + data.array().length);
+
+ data.get(bytesRead);
+
+ bytes.put(bytesRead);
+
+ bytes.rewind();
+
+ if (callback != null) callback.done();
+
+ return bytesRead.length;
+ }
- public void position(int pos) throws Exception
- {
- if (!open)
- {
- throw new IllegalStateException("Is closed");
- }
-
- //log.info("reset called");
-
- data.position(pos);
- }
+ public void position(int pos) throws Exception
+ {
+ if (!open)
+ {
+ throw new IllegalStateException("Is closed");
+ }
+
+ //log.info("reset called");
+
+ data.position(pos);
+ }
- public int write(ByteBuffer bytes, boolean sync) throws Exception
- {
- if (!open)
- {
- throw new IllegalStateException("Is closed");
- }
-
- int position = data == null ? 0 : data.position();
-
- checkAndResize(bytes.capacity() + position);
-
- //log.info("write called, position is " + data.position() + " bytes is " + bytes.array().length);
-
- data.put(bytes);
-
- return bytes.array().length;
- }
-
- private void checkAndResize(int size)
- {
- int oldpos = data == null ? 0 : data.position();
-
- if (data == null || data.array().length < size)
- {
- byte[] newBytes = new byte[size];
-
- if (data != null)
- {
- System.arraycopy(data.array(), 0, newBytes, 0, data.array().length);
- }
-
- data = ByteBuffer.wrap(newBytes);
-
- data.position(oldpos);
- }
- }
+ public int write(ByteBuffer bytes, boolean sync, IOCallback callback) throws Exception
+ {
+ if (!open)
+ {
+ throw new IllegalStateException("Is closed");
+ }
+
+ int position = data == null ? 0 : data.position();
+
+ checkAndResize(bytes.capacity() + position);
+
+ //log.info("write called, position is " + data.position() + " bytes is " + bytes.array().length);
+
+ data.put(bytes);
+
+ if (callback!=null) callback.done();
+
+ return bytes.array().length;
+
+ }
+
+ public int write(ByteBuffer bytes, boolean sync) throws Exception
+ {
+ return write(bytes, sync, null);
+ }
+
+ private void checkAndResize(int size)
+ {
+ int oldpos = data == null ? 0 : data.position();
+
+ if (data == null || data.array().length < size)
+ {
+ byte[] newBytes = new byte[size];
+
+ if (data != null)
+ {
+ System.arraycopy(data.array(), 0, newBytes, 0, data.array().length);
+ }
+
+ data = ByteBuffer.wrap(newBytes);
+
+ data.position(oldpos);
+ }
+ }
+ 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;
+ }
+
+ public int calculateBlockStart(int position) throws Exception
+ {
+ return position;
+ }
+
+ public String toString()
+ {
+ return "FakeSequentialFile:" + this.fileName;
+ }
+
+
+ }
+
}
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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/JournalImplTestUnit.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -21,7 +21,11 @@
*/
package org.jboss.messaging.tests.unit.core.journal.impl.timing;
+import java.util.ArrayList;
+
import org.jboss.messaging.tests.unit.core.journal.impl.JournalImplTestBase;
+import org.jboss.messaging.core.journal.PreparedTransactionInfo;
+import org.jboss.messaging.core.journal.RecordInfo;
import org.jboss.messaging.core.logging.Logger;
/**
@@ -33,138 +37,143 @@
*/
public abstract class JournalImplTestUnit extends JournalImplTestBase
{
- private static final Logger log = Logger.getLogger(JournalImplTestUnit.class);
-
-
-
- public void testAddUpdateDeleteManyLargeFileSize() throws Exception
- {
- final int numberAdds = 10000;
-
- final int numberUpdates = 5000;
-
- final int numberDeletes = 3000;
-
- long[] adds = new long[numberAdds];
-
- for (int i = 0; i < numberAdds; i++)
- {
- adds[i] = i;
- }
-
- long[] updates = new long[numberUpdates];
-
- for (int i = 0; i < numberUpdates; i++)
- {
- updates[i] = i;
- }
-
- long[] deletes = new long[numberDeletes];
-
- for (int i = 0; i < numberDeletes; i++)
- {
- deletes[i] = i;
- }
-
- setup(10, 10 * 1024 * 1024, true);
- createJournal();
- startJournal();
- load();
- add(adds);
- update(updates);
- delete(deletes);
- stopJournal();
- createJournal();
- startJournal();
- loadAndCheck();
-
- }
-
- public void testAddUpdateDeleteManySmallFileSize() throws Exception
- {
- final int numberAdds = 10000;
-
- final int numberUpdates = 5000;
-
- final int numberDeletes = 3000;
-
- long[] adds = new long[numberAdds];
-
- for (int i = 0; i < numberAdds; i++)
- {
- adds[i] = i;
- }
-
- long[] updates = new long[numberUpdates];
-
- for (int i = 0; i < numberUpdates; i++)
- {
- updates[i] = i;
- }
-
- long[] deletes = new long[numberDeletes];
-
- for (int i = 0; i < numberDeletes; i++)
- {
- deletes[i] = i;
- }
-
- setup(10, 10 * 1024, true);
- createJournal();
- startJournal();
- load();
- add(adds);
- update(updates);
- delete(deletes);
- stopJournal();
- createJournal();
- startJournal();
- loadAndCheck();
-
- }
-
- public void testReclaimAndReload() throws Exception
- {
- setup(5, 10 * 1024 * 1024, true);
- createJournal();
- startJournal();
- load();
-
- journal.startReclaimer();
-
- long start = System.currentTimeMillis();
-
- for (int count = 0; count < 100000; count++)
- {
- add(count);
-
- if (count >= 5000)
- {
- delete(count - 5000);
- }
-
- if (count % 10000 == 0)
- {
- log.info("Done: " + count);
- }
- }
-
- long end = System.currentTimeMillis();
-
- double rate = 1000 * ((double)100000) / (end - start);
-
- log.info("Rate of " + rate + " adds/removes per sec");
-
- stopJournal();
- createJournal();
- startJournal();
- loadAndCheck();
-
- assertEquals(5000, journal.getIDMapSize());
-
- stopJournal();
- }
-
+ private static final Logger log = Logger.getLogger(JournalImplTestUnit.class);
+
+
+
+ public void testAddUpdateDeleteManyLargeFileSize() throws Exception
+ {
+ final int numberAdds = 10000;
+
+ final int numberUpdates = 5000;
+
+ final int numberDeletes = 3000;
+
+ long[] adds = new long[numberAdds];
+
+ for (int i = 0; i < numberAdds; i++)
+ {
+ adds[i] = i;
+ }
+
+ long[] updates = new long[numberUpdates];
+
+ for (int i = 0; i < numberUpdates; i++)
+ {
+ updates[i] = i;
+ }
+
+ long[] deletes = new long[numberDeletes];
+
+ for (int i = 0; i < numberDeletes; i++)
+ {
+ deletes[i] = i;
+ }
+
+ setup(10, 10 * 1024 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+ add(adds);
+ update(updates);
+ delete(deletes);
+ stopJournal();
+ createJournal();
+ startJournal();
+ loadAndCheck();
+
+ }
+
+ public void testAddUpdateDeleteManySmallFileSize() throws Exception
+ {
+ final int numberAdds = 10000;
+
+ final int numberUpdates = 5000;
+
+ final int numberDeletes = 3000;
+
+ long[] adds = new long[numberAdds];
+
+ for (int i = 0; i < numberAdds; i++)
+ {
+ adds[i] = i;
+ }
+
+ long[] updates = new long[numberUpdates];
+
+ for (int i = 0; i < numberUpdates; i++)
+ {
+ updates[i] = i;
+ }
+
+ long[] deletes = new long[numberDeletes];
+
+ for (int i = 0; i < numberDeletes; i++)
+ {
+ deletes[i] = i;
+ }
+
+ setup(10, 10 * 1024, true);
+ createJournal();
+ startJournal();
+ load();
+ add(adds);
+ update(updates);
+ delete(deletes);
+ stopJournal();
+ createJournal();
+ startJournal();
+ loadAndCheck();
+
+ }
+
+ public void testReclaimAndReload() throws Exception
+ {
+ setup(2, 10 * 1024 * 1024, false);
+ createJournal();
+ startJournal();
+ load();
+
+ journal.startReclaimer();
+
+ long start = System.currentTimeMillis();
+
+
+ byte[] record = generateRecord(recordLength);
+
+ for (int count = 0; count < 100000; count++)
+ {
+ journal.appendAddRecord(count, record);
+
+ if (count >= 5000)
+ {
+ journal.appendDeleteRecord(count - 5000);
+ }
+
+ if (count % 10000 == 0)
+ {
+ log.info("Done: " + count);
+ }
+ }
+
+ long end = System.currentTimeMillis();
+
+ double rate = 1000 * ((double)100000) / (end - start);
+
+ log.info("Rate of " + rate + " adds/removes per sec");
+
+ log.info("Reclaim status = " + debugJournal());
+
+ stopJournal();
+ createJournal();
+ startJournal();
+ journal.load(new ArrayList<RecordInfo>(), new ArrayList<PreparedTransactionInfo>());
+
+ assertEquals(5000, journal.getIDMapSize());
+
+ stopJournal();
+ }
+
}
Added: 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 (rev 0)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplAIOTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -0,0 +1,210 @@
+/*
+ * 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.journal.impl.timing;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.jboss.messaging.core.asyncio.AIOCallback;
+import org.jboss.messaging.core.journal.IOCallback;
+import org.jboss.messaging.core.journal.Journal;
+import org.jboss.messaging.core.journal.RecordInfo;
+import org.jboss.messaging.core.journal.SequentialFileFactory;
+import org.jboss.messaging.core.journal.impl.AIOSequentialFileFactory;
+import org.jboss.messaging.core.journal.impl.JournalImpl;
+import org.jboss.messaging.core.journal.impl.NIOSequentialFileFactory;
+import org.jboss.messaging.core.logging.Logger;
+
+/**
+ *
+ * A RealJournalImplTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealJournalImplAIOTest extends JournalImplTestUnit
+{
+ private static final Logger log = Logger.getLogger(RealJournalImplAIOTest.class);
+
+ protected String journalDir = System.getProperty("user.home") + "/journal-test";
+
+ protected SequentialFileFactory getFileFactory() throws Exception
+ {
+ File file = new File(journalDir);
+
+ log.info("deleting directory " + journalDir);
+
+ deleteDirectory(file);
+
+ file.mkdir();
+
+ return new NIOSequentialFileFactory(journalDir);
+ }
+
+ public void testSpeedNonTransactional() throws Exception
+ {
+ for (int i=0;i<20;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-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/unit/core/journal/impl/timing/RealJournalImplTest.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -27,6 +27,7 @@
import org.jboss.messaging.core.journal.Journal;
import org.jboss.messaging.core.journal.RecordInfo;
import org.jboss.messaging.core.journal.SequentialFileFactory;
+import org.jboss.messaging.core.journal.impl.AIOSequentialFileFactory;
import org.jboss.messaging.core.journal.impl.JournalImpl;
import org.jboss.messaging.core.journal.impl.NIOSequentialFileFactory;
import org.jboss.messaging.core.logging.Logger;
@@ -57,6 +58,7 @@
return new NIOSequentialFileFactory(journalDir);
}
+
public void testSpeedNonTransactional() throws Exception
{
Journal journal =
@@ -83,6 +85,16 @@
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);
+
}
Modified: trunk/tests/src/org/jboss/messaging/tests/util/UnitTestCase.java
===================================================================
--- trunk/tests/src/org/jboss/messaging/tests/util/UnitTestCase.java 2008-04-30 22:35:42 UTC (rev 4142)
+++ trunk/tests/src/org/jboss/messaging/tests/util/UnitTestCase.java 2008-05-05 21:55:56 UTC (rev 4143)
@@ -265,6 +265,11 @@
}
}
+ protected int calculateRecordSize(int size, int alignment)
+ {
+ return ((size / alignment) + (size % alignment != 0 ? 1 : 0)) * alignment;
+ }
+
}
More information about the jboss-cvs-commits
mailing list