public class AsyncWriteEngine extends EngineWrapper implements Engine
Engine wrapper which provides asynchronous serialization and asynchronous write.
This class takes an object instance, passes it to background writer thread (using Write Queue)
where it is serialized and written to disk. Async write does not affect commit durability,
Write Queue is flushed into disk on each commit. Modified records are held in small instance cache,
until they are written into disk.
This feature is disabled by default and can be enabled by calling DBMaker.asyncWriteEnable().
Write Cache is flushed in regular intervals or when it becomes full. Flush interval is 100 ms by default and
can be controlled by DBMaker.asyncWriteFlushDelay(int). Increasing this interval may improve performance
in scenarios where frequently modified items should be cached, typically BTreeMap import where keys
are presorted.
Asynchronous write does not affect commit durability. Write Queue is flushed during each commit, rollback and close call.
Those method also block until all records are written.
You may flush Write Queue manually by using clearCache() method.
There is global lock which prevents record being updated while commit is in progress.
This wrapper starts one threads named `MapDB writer #N` (where N is static counter).
Async Writer takes modified records from Write Queue and writes them into store.
It also preallocates new recids, as finding empty `recids` takes time so small stash is pre-allocated.
It runs as `daemon`, so it does not prevent JVM to exit.
Asynchronous Writes have several advantages (especially for single threaded user). But there are two things
user should be aware of:
* Because data are serialized on back-ground thread, they need to be thread safe or better immutable.
When you insert record into MapDB and modify it latter, this modification may happen before item
was serialized and you may not be sure what version was persisted
* Inter-thread communication has some overhead.
There is also only single Writer Thread, which may create single bottle-neck.
This usually not issue for
single or two threads, but in multi-threaded environment it may decrease performance.
So in truly concurrent environments with many updates (network servers, parallel computing )
you should keep Asynchronous Writes disabled.Engine,
EngineWrapper| Modifier and Type | Class and Description |
|---|---|
protected static class |
AsyncWriteEngine.WriterRunnable |
EngineWrapper.CloseOnJVMShutdown, EngineWrapper.ImmutabilityCheckEngine, EngineWrapper.ReadOnlyEngine, EngineWrapper.SerializerCheckEngineWrapper, EngineWrapper.SynchronizedEngineWrapper| Modifier and Type | Field and Description |
|---|---|
protected java.util.concurrent.atomic.AtomicReference<java.util.concurrent.CountDownLatch> |
action |
protected java.util.concurrent.CountDownLatch |
activeThreadsCount
number of active threads running, used to await thread termination on close
|
protected int |
asyncFlushDelay
flush Write Queue every N milliseconds
|
protected boolean |
closeInProgress
indicates that `close()` was called and background threads are being terminated
|
protected java.util.concurrent.locks.ReentrantReadWriteLock |
commitLock
Each insert to Write Queue must hold read lock.
|
protected int |
maxSize |
protected java.util.concurrent.atomic.AtomicInteger |
size |
protected static java.util.concurrent.atomic.AtomicLong |
threadCounter
ensures thread name is followed by number
|
protected java.lang.Throwable |
threadFailedException
If background thread fails with exception, it is stored here, and rethrown to all callers.
|
protected static java.lang.Object |
TOMBSTONE
used to signal that object was deleted
|
protected LongConcurrentHashMap<Fun.Tuple2<java.lang.Object,Serializer>> |
writeCache
Associates `recid` from Write Queue with record data and serializer.
|
CLOSEDCATALOG_RECID, CHECK_RECORD, CLASS_INFO_RECID, LAST_RESERVED_RECID| Constructor and Description |
|---|
AsyncWriteEngine(Engine engine) |
AsyncWriteEngine(Engine engine,
int _asyncFlushDelay,
int queueSize,
java.util.concurrent.Executor executor)
Construct new class and starts background threads.
|
| Modifier and Type | Method and Description |
|---|---|
protected void |
checkState()
checks that background threads are ready and throws exception if not
|
void |
clearCache()
clears any underlying cache
|
void |
close()
Close store/cache.
|
void |
commit()
Makes all changes made since the previous commit/rollback permanent.
|
void |
compact()
This method blocks all put/update/delete operations until it finishes (via global ReadWrite Commit Lock).
|
<A> boolean |
compareAndSwap(long recid,
A expectedOldValue,
A newValue,
Serializer<A> serializer)
Updates existing record in atomic (Compare And Swap) manner.
|
<A> void |
delete(long recid,
Serializer<A> serializer)
Remove existing record from store/cache
Recid must be a number returned by 'put' method.
|
<A> A |
get(long recid,
Serializer<A> serializer)
Get existing record.
|
<A> long |
put(A value,
Serializer<A> serializer)
Insert new record.
|
void |
rollback()
Undoes all changes made in the current transaction.
|
protected boolean |
runWriter()
runs on background thread.
|
protected void |
startThreads(java.util.concurrent.Executor executor)
Starts background threads.
|
<A> void |
update(long recid,
A value,
Serializer<A> serializer)
Update existing record with new value.
|
protected void |
waitForAction(int actionNumber) |
canRollback, canSnapshot, checkClosed, closeListenerRegister, closeListenerUnregister, getSerializerPojo, getWrappedEngine, isClosed, isReadOnly, preallocate, preallocate, snapshotclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitcanRollback, canSnapshot, closeListenerRegister, closeListenerUnregister, getSerializerPojo, isClosed, isReadOnly, preallocate, preallocate, snapshotprotected static final java.util.concurrent.atomic.AtomicLong threadCounter
protected static final java.lang.Object TOMBSTONE
protected final int maxSize
protected final java.util.concurrent.atomic.AtomicInteger size
protected final LongConcurrentHashMap<Fun.Tuple2<java.lang.Object,Serializer>> writeCache
protected final java.util.concurrent.locks.ReentrantReadWriteLock commitLock
protected final java.util.concurrent.CountDownLatch activeThreadsCount
protected volatile java.lang.Throwable threadFailedException
protected volatile boolean closeInProgress
protected final int asyncFlushDelay
protected final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.CountDownLatch> action
public AsyncWriteEngine(Engine engine, int _asyncFlushDelay, int queueSize, java.util.concurrent.Executor executor)
engine - which stores data._asyncFlushDelay - flush Write Queue every N millisecondsexecutor - optional executor to run tasks. If null daemon threads will be createdpublic AsyncWriteEngine(Engine engine)
protected void startThreads(java.util.concurrent.Executor executor)
executor - optional executor to run tasks, if null deamon threads will be createdprotected boolean runWriter()
throws java.lang.InterruptedException
java.lang.InterruptedExceptionprotected void checkState()
public <A> long put(A value,
Serializer<A> serializer)
put in interface Engineput in class EngineWrappervalue - records to be addedserializer - used to convert record into/from binary formpublic <A> A get(long recid,
Serializer<A> serializer)
get in interface Engineget in class EngineWrapperrecid - (record identifier) under which record was persistedserializer - used to deserialize record from binary formpublic <A> void update(long recid,
A value,
Serializer<A> serializer)
update in interface Engineupdate in class EngineWrapperrecid - (record identifier) under which record was persisted.value - new record value to be storedserializer - used to serialize record into binary formpublic <A> boolean compareAndSwap(long recid,
A expectedOldValue,
A newValue,
Serializer<A> serializer)
oldValue==expectedOldValue when old value is found in instance cacheoldValue using serializer and checking oldValue.equals(expectedOldValue)expectedOldValue using serializer and comparing binary array with already serialized oldValue
compareAndSwap in interface EnginecompareAndSwap in class EngineWrapperrecid - (record identifier) under which record was persisted.expectedOldValue - old value to be compared with existing recordnewValue - to be written if values are matchingserializer - used to serialize record into binary formpublic <A> void delete(long recid,
Serializer<A> serializer)
delete in interface Enginedelete in class EngineWrapperrecid - (record identifier) under which was record persistedserializer - which may be used in some circumstances to deserialize and store old objectpublic void close()
NullPointerException
There is an configuration option DBMaker.closeOnJvmShutdown() which uses shutdown hook to automatically
close Engine when JVM shutdowns.
This method blocks until Write Queue is flushed and Writer Thread writes all records and finishes.
When this method was called `closeInProgress` is set and no record can be modified.close in interface Engineclose in class EngineWrapperprotected void waitForAction(int actionNumber)
public void commit()
commit in interface Enginecommit in class EngineWrapperpublic void rollback()
UnsupportedOperationException.
This method blocks until Write Queue is cleared.
All put/update/delete methods are blocked while rollback is in progress (via global ReadWrite Commit Lock).
After this method returns, commit lock is released and other operations may continuerollback in interface Enginerollback in class EngineWrapperpublic void compact()
compact in interface Enginecompact in class EngineWrapperpublic void clearCache()
clearCache in interface EngineclearCache in class EngineWrapper