29 PersistStore implementation

This describes the implementation of the PersistStore.

A PersistStore is associated with a single LSS store. It can host any number of PSpaces. Each PSpace is uniquely identified by name. It is currently assumed there aren't too many PSpaces, so it is reasonable to index them all in memory using an std::map.

The PersistStore maintains a bidirectional mapping between an integer CID (Class Identifier) and fully qualified class name. The CID is written before the serialised state of an object to support dynamic creation. Note that all PSpaces share the same CidMap.

The PersistStore stores the CidMap in the root serial element - i.e. with oid 00000001.00000000 (was 01010101.01010101)

The PSpaceMap stores a map from name of the PSpace to OID. This is stored in the serial element with oid 00000001.00000001 (was 01010101.01010102)

Both the CidMap and PSpaceMap are loaded as soon as the store is opened.

Each PSpace object is stored in its own serial element. To support lazy loading of PSpaces each PSpaceMap entry stores both the OID and PSpace memory pointer.

struct PSpaceMap::Entry
{
    OID m_oid;
    bool m_committed;
    PSpace* m_ptr;
};

Persistent object lifetime management

We allow a PSpace to get very large - making it impossible to load all the objects into memory at the same time. Therefore, a persistent version of tracing collection will not work very well.

It is proposed that at the coarsest level persistent objects in a PSpace are regarded a forming a simple tree structure. This can be compared to a file system. A given tree node can itself be a root for a graph of objects that are garbage collected in a different way.

The tree structure is imposed for practical reasons. It allows large numbers of objects to be deleted or moved around very quickly. It is not suggesting that a tree structure is always the right way to store data. On the contrary, it often isn't. For that reason the tree may represent a very course level system. If it is not appropriate at all then then the tree only contains a single node!

It is assumed that operations can represent changes to the tree structure. This allows PSpace trees to synchronise.

An operation may need to move a tree from one parent to another. Operations can host "holding areas". This allows for operations to insert and delete trees of objects.

Eviction of persistent objects

The CSpace system offers an efficient LRU eviction system that is suitable for persistent objects.

As the GC thread runs it may choose to zero the m_ptr member of all prefs that point at an object to be evicted. This allows the object to become unreachable and therefore to be deleted from memory.

TODO... The PersistStore system is responsible for calling SetEvictableObjectSize() after serialising persistent objects to provide information to the garbage collector about the (estimated) size of objects in memory. SetEvictableObjectSize() should be called after reading or writing a persistent object.

When an persistent object is modified it is marked as dirty and becomes strongly reachable via the Dirty Object Set (DOS). Therefore the object is pinned in memory and can't be evicted. As a result there is no need to estimate its new size. That can wait until after the object is written back to disk.

Note that dirty persistent objects are strongly referenced by the DOS, and therefore are pinned in memory.

Allowing for anonymous PSpaces

If we use a map indexed by name to store all the PSpaces then we can't represent anonymous PSpaces.

It is proposed that the anonymous PSpaces are stored in a separate area. Just a vector will do. The vector needs to persist. However at startup the system will automatically delete any anonymous spaces.

For now we won't bother with anonymous spaces!

Links

PersistStore.h

Source: Ceda/cxPersistStore/src/PersistStore.h

PersistStore.cpp

Source: Ceda/cxPersistStore/src/PersistStore.cpp