Javadoc
links
The object of object graph that can be persisted are POJO that
do not need to be Serializable, but there is some conditions:
The consideration for better performance is to use collection implementation of JOAFIP ( implements Sun standard interface and more )
To be able to use JOAFIP it is needed to understand the persistence state
of the objects
Notes:
After a data access session closed, persistent object become detached, while transient and detached remains in their state. A call to getObject() in newly opened session allows to obtain a reference on persistent object.
For object not saved
serialized in
one data record, it is not possible to use a persistent object
after data session closed, you have to make a deep copy of the
persistent object, then close data access session and work with the
copy.
IFilePerstence#copy(Object
object) enable to create an copy detached from persistence.
more easy setup can be done using setup facility
Below the basic usage is described.
see also setup facility or builder javadoc
/*
creation of
the file persitence manager */
final
FilePersistenceBuilder
builder = new FilePersistenceBuilder();
builder.setPathName("runtime/database");
builder.setProxyMode(true);
builder.setRemoveFiles(true);
builder.setGarbageManagement(false);
builder.setCrashSafeMode(false);
builder.setFileCache(PAGE_SIZE, NUMBER_OF_PAGE);
IFilePersistence
filePersistence;
try {
filePersistence
= builder.build();
} catch
(FilePersistenceException exception) {
final
EnumFileState fileState = FilePersistence.fileState(exception);
switch(fileState) {
case STATE_OK:
/* exception is not relative to file
state */
throw exception;
case
STATE_CORRUPTED:
/*
file content corrupted */
throw exception;
case
STATE_RESTORED_DATA_LOST:
/* create file persistence using file restored even data lost */
filePersistence
= new
FilePersistence(directory);
break;
case
STATE_RESTORED_NO_DATA_LOST:
/* create file persistence using file restored */
filePersistence
= builder.build();
break;
case
STATE_UNSTABLE:
/* need
file maintenance */
throw exception;
}
}
/*
start data access session */
IDataAccessSession
session =
filePersistence.createDataAccessSession();
session.open();
persistentObject
= session.getObject("name");
if( persistentObject
== null ) {
/* the first time creation */
persistentObject
= new
PersistentObject(...)
session.setObject("name", persistentObject);
}
........
session.closeAndWait(EnumFilePersistenceCloseAction.SAVE);
/*
start data access session */
IDataAccessSession
session =
filePersistence.createDataAccessSession();
session.open();
......
/*
get the object in memory */
persistentObject
= session.getObject("name");
/*
use of persitent object */
persistentObject.setXxx(...);
......
/*
close data access session , saving modifications, waiting save
done*/
session.closeAndWait(EnumFilePersistenceCloseAction.SAVE);
/*
start data access session */
IExclusiveDataAccessSession session=filePersistence.createExclusiveDataAccessSession();
session.open();
......
/*
get the object in memory */
persistentObject
= session.getObject("name");
/*
use of persitent object */
persistentObject.setXxx(...);
......
/* save (do not
close) */
session.save();
......
/* some other operation */
......
/* close data access
session , saving modifications */
session.close();
IDataAccessSession
session =
filePersistence.createDataAccessSession();
session.open();
..........
/*
remove object from the persitente objet pool
*/
session.removeObject("name");
..........
session.closeAndWait(EnumFilePersistenceCloseAction.SAVE);
/*
start data access session */
IExclusiveDataAccessSession session=filePersistence.createExclusiveDataAccessSession();
session.open();
......
/*
remove object from the persitente objet pool
*/
session.removeObject("name");
..........
/* save (do not
close) */
session.save();
......
/* some other operation */
......
/* close data access session , saving
modifications */
session.close();
protection from object
modifications is not possible with exclusive data access session
/*
start data
access session */
IDataAccessSession
session =
filePersistence.createDataAccessSession();
session.open();
......
/*
get the object in memory */
persistentObject
= session.getObject("name");
/*
use of persitent object */
persistentObject.getXxx(...);
......
/*
no save action */
session.closeAndWait(EnumFilePersistenceCloseAction.DO_NOT_SAVE);
not possible with exclusive data access session
/*
start data
access session */
IDataAccessSession
session =
filePersistence.createDataAccessSession();
session.open();
......
/*
get the object in memory */
persistentObject
= session.getObject("name");
/*
use of persitent object */
persistentObject.setXxx(...);
......
/*
close data access session, do not save modifications
*/
session.closeAndWait(EnumFilePersistenceCloseAction.DO_NOT_SAVE);
/*
start a new data access session */
session.open();
/*
persitentObject have the previous state saved on file
*/
persistentObject = session.getObject("name");
It is possible to declare field in enum, so the state of each enum constant must be saved. IFilePersistence#storedMutableEnum, see IFilePersistence#storedImmutableEnum or setup by properties file. The storedMutableEnum and storedImmutableEnum are accessible throught IDataAccessSession interface.
IFilePersistence#storedEnum is deprecated.
/* must
inform file persistence manager of enum class stored
* see
also setup facility for stored
enum
declaration
*/
filePersistence.storedMutableEnum(EnumForTest.class)
final
BobContainer bob1 = new
BobContainer();
bob1.setObject1(EnumForTest.VAL1);
EnumForTest.VAL1.setObject(Integer.valueOf(0));
/*
save the created object*/
session.open();
/* inform that
EnumForTest class instance are persisted */
session.setObject("bob1",
bob1);
session.close(EnumFilePersistenceCloseAction.SAVE);
session.open(); /* enum state is
automaticaly set from file */
/*
deprecated: reload enum state */
/* session.setEnumState(EnumForTest.VAL1);*/
it is possible to force storage in one file data record of all objects instances of a class. There is three ways to do that:
annotate the class with
StoreSerializeAndZippedInOneRecord ( objects are always rewritten in file even if state does not change)
setting file persistence manager invoking one of methods in IFilePersistence
setStoreSerializeAndGZippedInOneRecord
setStoreSerializeAndZippedInOneRecord ( objects are always rewritten in file even if state does not change)
setStoreSerializeInOneRecord
Serialization in one data record side effect.
Instance
o1
references o3 and o4, and o2 references o4 and o5.
Doing a
session.setObject("key1",o1) , session.setObject("key2",o2)
to save objects o1 and o2 serialized in one data record.
Objects
o1 and o2
are stored serialized as below in two data records.
Reading o1 and o2 using
o1=session.getObject("key1") ,
and o2=session.getObject("key2")
After the reading of o1 and
o2, it will have 6 objects in memory: o4' and o4'' have the same
state than the original o4 object, but are not the same instance in
memory.
Since
2.0.0,
storage in joafip data record in file can be driven by standard java
serialization mechanism. This means that joafip invokes readObject
and writeObject methods of classes implementing Serializable
interface, and also invokes readExternal and
writeExternal methods of classes
implementing Externalizable interface.
For class
implementing Serializable interface but not
implementing readObject and writeObject
methods,
joafip uses default read and write object.
Invoking
setStoreNotUseStandardSerialization of IFilePersistence
disables use of standard Java serialization mechanism ( or use
StoreNotUseStandardSerialization
annotation )
File persistence is thread safe and enables to open multiple data access session at the same time in asynchronous mode. It is also possible to have synchronous access.
Since
object
instances accessed through file persistence are the same, there is no
transaction concept like with relational data base, same object are
shared.
The persisted data model should be thread-safe.
The only JOAFIP specific things is the way of
closing and saving when multiple data access sessions are opened.
In
fact the save action will be done only when the last opened data
access session is closed.
Take care: in multi-thread
environment you can have the situation where all data access session
are not closed at the same time. the
IDataAccessSession.closeAndWait(...) method can be used to wait for
modifications saved, or a listener on data access session can be set
to be notified of save operation end.
The data access session
are opened
using IDataAccessSession.open() ; that is asynchronous open
mode.
About rollback:
It is possible to discard modifications done, by closing the session with "do not save" action; this will cancel all save action asked by other data access session close. The close methods and listener enable to know if save operation asked have been done or not.
Using IDataAccessSession.openSynchronized, that is the synchronous open mode, no data access session shares object access with another data access session.
one heap file record by
object
instance
example of objects in relation
saving
object1 will create 4 heap file record for object1, object2, object3,
and object4
Enables to manage a large
amount of
data object without need to load all in memory.
In the below example we can imagine the map has some thousands of
records.
/*
start data access session */
IDataAccessSession
session =
filePersistence.createDataAccessSession();
session.open();
/*
get the map to update */
PTreeMap<String,ClassData>
map=(PTreeMap<String,ClassData>)session.getObject("map1");
/*
do modification */
map.put("key1",data1);
/*
close data access session, saving modifications
*/
session.closeAndWait(EnumFilePersistenceCloseAction.SAVE);
The getObject call will not read all records from the
file.
The put call will only load in memory the nodes of the tree
that needs to be read and modified for insertion.
The close call
will commit only loaded and modified, and added objects. If objects are
unreferenced by other objects ( subject to garbage ) then they are
removed from the file ( this create free space for future storage
).
It is possible to force enhance of classe even if it have
"public final" method, or to force to not use lazy mode:
see IFilePersistence interface or setup
facility.
There is a system of
replication of
data in a second file avec un système de reconstruction d'un fichier
altéré pour être tolérant aux crash.
Les fichiers ne sont jamais maintenus toujours ouvert durant la vie de
l'application.
Un fichier est marqué "instable" avant d'y faire des modifications puis
marqué "stable" après ecriture et fermeture.
Au démarage l'état des fichiers est vérifié et le fichier instable
restauré.
Cela garantie que le dernier commit réussi ne sera pas perdu.
FilePersistence
filePersistence = builder.build();
......
try
{
} catch(FilePersistenceException exception) {
switch (.fileState(exception)) {
case STATE_RESTORED_DATA_LOST:
/* restoration of data from backup: data lost */
case STATE_RESTORED_NO_DATA_LOST:
/* restoration of backup from data: no data lost */
}
}
he file content stable state
management is describe below.
Each record in heap file
have a CRC32.
When reading in file
a FileCorruptedException is thrown if read CRC32 do not match
computed CRC32.
FilePersistence
filePersistence = builder.build();
......
try {
} catch(FilePersistenceException exception) {
switch (.fileState(exception)) {
case STATE_CORRUPTED:
/* cause is file corruption */
................
}
}
Additional check can be done using
AssertNotNull annotation on persistence class' field that can not
have a null value.
Each
time an object is added to the object graph, a data record is added
to the file.
When
an object is detached from the object graph its associated data record
remains
in file but will no more be accessed.
The data record garbage
collector is needed to free space used by this detached data record,
the free space will be used to put new data record.
High
speed clean up: when there is no more persisted object clean up can be
done quickly by erasing the file and creating an empty one.
Two
way for garbage sweeping:
big maintenance:
Calling FilePersistence#garbageSweep
This can take a long time
in background:
Background clean up is disabled by default. Enable it has
a frequency parameter.
Make application continuously running, even if not access to persisted
data, enable background garbage sweeping.
FilePersistence
filePersistence = builder.build();
......
/* this
can take a long time and block all other operation */
int
numberOfSweeped=filePersistence.garbageSweep();
FilePersistence
filePersistence
= builder.build();
......
/* enable
background garbage sweep, one pass every 100 miliSeconds
*/
filePersistence.enableBackgroundGarbageSweep(100);
......
/*
disable background garbage sweep
*/
filePersistence.disableBackgroundGarbageSweep()
see also setup using properties
Instance of a class annotated DeprecatedInStoreClass can exists stored in file but can not be add anymore
A program element annotated Fortest is to use only for test purpose, should not be used for other purpose
Instance of a class annotated NotStorableClass can not be store in file, it concern all manager and entity used for storage management
Instance of a class annotated StorableClass can be
store
in file,
see FilePersistence#setStoreOnlyMarkedStorable
setStorable methods
of IFilePersistence can be used instead.
To mark to not use lazy loading for a type
setNoLazyLoad
methods of IFilePersistence can be used instead.
To mark a serializable class to be store not using standard
serialization (do not use java serialization mechanism
)
setStoreNotUseStandardSerialization methods of IFilePersistence
can be used instead.
To mark a type storable in gzipped serialized form to a file
data
record
setStoreSerializeAndGZippedInOneRecord methods of
IFilePersistence can be used instead.
To mark a type storable in zipped serialized form to a file
data
record. Optional compression level parameter
(0-9)
setStoreSerializeAndZippedInOneRecord methods of
IFilePersistence can be used instead. See also
IFilepersistence#setZipCompressionLevel
To mark a type storable in serialized form to a file data
record
setStoreSerializeAndZippedInOneRecord methods of
IFilePersistence can be used instead.