feedback / send your comments
mail to luc peuvrier
chat channel
joafip users mailing list
forums

BACK

En Français

JOAFIP features and usage

summary

the different kind of data access session

"transactionnal" data access session and "exclusive" data access session.
As many you want "transactionnal" data access session can be created at same time ( see multi data access session )
"exlucusive" data access session must be create alone, no other data access session created ( exclusive data access session )

The main diferrence is the save feature. "transactionnal" data access session is called "transactionnal" because change in memory are commited to file at data access session close, may be also rollback (no back end of modification in memory to file). "Exclusive" data access session allow save without close the modification done in memory, anay modification is saved, no rollback possibilities.

Save meaning

Saving mean store in file objects created and modified, no write of unchanged objects.
When use "transactional" data access session:
When use "exclusive" data access session:

Easy to use

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:

Below the basic usage is described.

Creation of the persistence manager

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;
    }
}

First access ( the data files not exist )

/* 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);



Access cycle

using "transactional" 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 , saving modifications, waiting save done*/
session.closeAndWait(EnumFilePersistenceCloseAction.SAVE);

using "exclusive" data access session

/* 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();

Remove object

using "transactional" data access session

IDataAccessSession session = filePersistence.createDataAccessSession();
session.open();
..........

/* remove object from the persitente objet pool */
session.removeObject("name");
..........
session.closeAndWait(EnumFilePersistenceCloseAction.SAVE);

using "exclusive" data access session

/* 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();

read only access (write protection)

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);

rollback modifications made in memory

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");

enum state management

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);*/

serialize an object in one file data record

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:

Shown below: one data record in file per object in memory

Below shows when object o1 and o2 are serialized in on file data record

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.
 

java serialization mechanism

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 )

exclusive data access session (auto save)

Exclusive data access session can not be openned if other(s) data access session are openned.

An exclusive data access session make able to save modification without closing the session:

Auto save feature is available with exclusive data access session.

Multi data access session 

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.

asynchronous mode:

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.

Synchronous mode:

Using IDataAccessSession.openSynchronized, that is the synchronous open mode, no data access session shares object access with another data access session.

save all objects in relation

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

Lazy loading of object

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.

Crash safe

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.




file corruption detection

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.

File data record garbage collector

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:

foreground garbage sweep


FilePersistence filePersistence 
= builder.build();
......
/* this can take a long time and block all other operation */
int numberOfSweeped=filePersistence.garbageSweep();

background garbage sweep

FilePersistence filePersistence = builder.build();
......
/* enable background garbage sweep, one pass every 100 miliSeconds */
filePersistence.enableBackgroundGarbageSweep(100);
......
/* disable background garbage sweep */
filePersistence.disableBackgroundGarbageSweep()



usable annotations summary / object storage setup

see also setup using properties

@DeprecatedInStoreClass

Instance of a class annotated DeprecatedInStoreClass can exists stored in file but can not be add anymore

@Fortest

A program element annotated Fortest is to use only for test purpose, should not be used for other purpose

@NotStorableClass

Instance of a class annotated NotStorableClass can not be store in file, it concern all manager and entity used for storage management

@StorableClass

Instance of a class annotated StorableClass can be store in file, see FilePersistence#setStoreOnlyMarkedStorable
setStorable methods of IFilePersistence can be used instead.

@StoreNoLazyLoad

To mark to not use lazy loading for a type
setNoLazyLoad methods of IFilePersistence can be used instead.

@StoreNotUseStandardSerialization

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.

@StoreSerializeAndGZippedInOneRecord

To mark a type storable in gzipped serialized form to a file data record
setStoreSerializeAndGZippedInOneRecord methods of IFilePersistence can be used instead.

@StoreSerializeAndZippedInOneRecord

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

@StoreSerializeInOneRecord

To mark a type storable in serialized form to a file data record
setStoreSerializeAndZippedInOneRecord methods of IFilePersistence can be used instead.


feedback / send your comments
mail to luc peuvrier
chat channel
joafip users mailing list
forums

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
© 2007-2012, joafip