Class XMLKVDatabase
- All Implemented Interfaces:
KVDatabase
,Serializable
- Direct Known Subclasses:
SpringXMLKVDatabase
MemoryKVDatabase
made persistent by storing its XML content in a file or custom StreamRepository
.
The database XML is rewritten in its entirety after each successful commit, so this class should not be used for high-performance applications.
The XML is persisted in a StreamRepository
which provides atomicity and any durability. When constructed
with a File
for persistence, that file gets wrapped in a FileStreamRepository
.
Initial Content
At startup, if a FileNotFoundException
is caught when trying to read the XML, we assume that the underlying
data has not yet been created and so the database is initialized as empty. Alternatively, you can configure some
default initial content for this scenario via setInitialContentFile()
, or by overriding
getInitialContent()
.
Out-Of-Band Updates
When a FileStreamRepository
is used, instances support "out-of-band" updates of the XML file. In that case,
each time a transaction is accessed the modification timestamp of the XML file is examined. If the XML file has been
updated by some external process since the time the transaction was created, the database will be reloaded from
the XML file and the transaction will fail with a RetryKVTransactionException
.
Note that "out-of-band" updates are not without race conditions: e.g., it's possible for an external process to update the XML file just as a transaction associated with this instance is being committed and written to the file, which will result in overwriting the external process' changes.
Key watches are supported.
Instances are serializable unless a non-serializable StreamRepository
is provided to the constructor.
-
Field Summary
Fields inherited from class io.permazen.kv.simple.SimpleKVDatabase
DEFAULT_HOLD_TIMEOUT, DEFAULT_WAIT_TIMEOUT, kv, log
-
Constructor Summary
ConstructorDescriptionXMLKVDatabase
(File file) Constructor.XMLKVDatabase
(File file, long waitTimeout, long holdTimeout) Constructor.XMLKVDatabase
(StreamRepository repository) Constructor.XMLKVDatabase
(StreamRepository repository, long waitTimeout, long holdTimeout) Constructor. -
Method Summary
Modifier and TypeMethodDescriptionboolean
Check the XML file's timestamp and reload it if it has been modified since the most recent read or write by this instance.protected void
Verify that the given transaction is still usable.Create a new transaction.int
Get the generation number associated with the XML file.protected InputStream
Get the initial content for an uninitialized database.protected void
postCommit
(SimpleKVTransaction tx, boolean successful) Invoked during transaction commit just after writing changes to the underlyingAtomicKVStore
.protected void
readXML()
void
reload()
Forcibly reload this database by re-reading the XML file.void
setInitialContentFile
(File initialContentFile) Configure theFile
containing default initial content for an uninitialized database.void
start()
Start this instance.protected void
writeXML()
Methods inherited from class io.permazen.kv.simple.SimpleKVDatabase
createTransaction, getHoldTimeout, getWaitTimeout, preCommit, setHoldTimeout, setWaitTimeout, stop
-
Constructor Details
-
XMLKVDatabase
Constructor.Uses a
FileStreamRepository
backed by the specified file, with timeouts set toSimpleKVDatabase.DEFAULT_WAIT_TIMEOUT
andSimpleKVDatabase.DEFAULT_HOLD_TIMEOUT
.- Parameters:
file
- persistent XML file- Throws:
IllegalArgumentException
- iffile
is null
-
XMLKVDatabase
Constructor.Uses a
FileStreamRepository
backed by the specified file with configurable lock timeouts.- Parameters:
file
- persistent XML filewaitTimeout
- how long a thread will wait for a lock before throwingRetryKVTransactionException
in milliseconds, or zero for unlimitedholdTimeout
- how long a thread may hold a contestested lock before throwingRetryKVTransactionException
in milliseconds, or zero for unlimited- Throws:
IllegalArgumentException
- ifwaitTimeout
orholdTimeout
is negativeIllegalArgumentException
- iffile
is null
-
XMLKVDatabase
Constructor.Allows storage in any user-supplied
StreamRepository
, with timeouts set toSimpleKVDatabase.DEFAULT_WAIT_TIMEOUT
andSimpleKVDatabase.DEFAULT_HOLD_TIMEOUT
.- Parameters:
repository
- XML file storage- Throws:
IllegalArgumentException
- ifrepository
is null
-
XMLKVDatabase
Constructor.Allows storage in any user-supplied
StreamRepository
with configurable lock timeouts.- Parameters:
repository
- XML file storagewaitTimeout
- how long a thread will wait for a lock before throwingRetryKVTransactionException
in milliseconds, or zero for unlimitedholdTimeout
- how long a thread may hold a contestested lock before throwingRetryKVTransactionException
in milliseconds, or zero for unlimited- Throws:
IllegalArgumentException
- ifwaitTimeout
orholdTimeout
is negativeIllegalArgumentException
- ifrepository
is null
-
-
Method Details
-
getInitialContent
Get the initial content for an uninitialized database. This method is invoked when, on the first load, the backing XML file is not found. It should return a stream that reads initial content for the database, if any, otherwise null.The implementation in
XMLKVDatabase
opens and returns theFile
configured bysetInitialContentFile()
, if any, otherwise null.- Returns:
- default initial XML database content, or null for none
- Throws:
IOException
- if an error occurs accessing the initial content file
-
setInitialContentFile
Configure theFile
containing default initial content for an uninitialized database. This method is invoked bygetInitialContent()
when, on the first load, the backing XML file is not found.- Parameters:
initialContentFile
- file containing default initial XML database content, or null for none
-
start
public void start()Description copied from interface:KVDatabase
Start this instance. This method must be called prior to creating any transactions.This method is idempotent: if this instance is already started, nothing happens.
Whether an instance that has been started and stopped can be restarted is implementation-dependent.
- Specified by:
start
in interfaceKVDatabase
- Overrides:
start
in classSimpleKVDatabase
-
createTransaction
Description copied from interface:KVDatabase
Create a new transaction.- Specified by:
createTransaction
in interfaceKVDatabase
- Overrides:
createTransaction
in classSimpleKVDatabase
- Returns:
- newly created transaction
-
reload
public void reload()Forcibly reload this database by re-reading the XML file.Any transactions that are in-progress when this method is called immediately become unusable.
-
getGeneration
public int getGeneration()Get the generation number associated with the XML file. The generation number is incremented every time the database is wholesale updated by reading the file into memory, e.g., by invokingreload()
.- Returns:
- XML file generation number
- See Also:
-
checkForOutOfBandUpdate
public boolean checkForOutOfBandUpdate()Check the XML file's timestamp and reload it if it has been modified since the most recent read or write by this instance.- Returns:
- true if file was updated and re-read, otherwise false
-
checkState
Description copied from class:SimpleKVDatabase
Verify that the given transaction is still usable.This method is invoked at the start of the
AtomicKVStore
data access andcommit()
methods of theSimpleKVTransaction
associated with this instance. This allows for any checks which depend on a consistent view of the transaction and database together. This instance's lock will be held when this method is invoked. Note: transaction state is also protected by this instance's lock.The implementation in
SimpleKVDatabase
does nothing.- Overrides:
checkState
in classSimpleKVDatabase
- Parameters:
tx
- the transaction being accessed
-
postCommit
Description copied from class:SimpleKVDatabase
Invoked during transaction commit just after writing changes to the underlyingAtomicKVStore
.SimpleKVDatabase
guarantees this method andpreCommit()
will be invoked in matching pairs, and that this instance will be locked when these methods are invoked.This method is invoked even if the underlying
AtomicKVStore
throws an exception while changes were being written to it. In that case,successful
will be false.The implementation in
SimpleKVDatabase
does nothing.- Overrides:
postCommit
in classSimpleKVDatabase
- Parameters:
tx
- the transaction that was committedsuccessful
- true if all changes were written back successfully, false if the underlyingAtomicKVStore
threw an exception during commit update
-
readXML
protected void readXML() -
writeXML
protected void writeXML()
-