IPersistable

Interface IPersistable is a sub-interface of IObject. Only objects that implement IPersistable may persist (with an OID) in a PersistStore.

The OID is assigned when (and only when) the object first becomes reachable from a persistent object. Note that it is common for objects to implement IPersistable and never become persistent. The IPersistable interface only represents a capability to become persistent.

A class implements the IPersistable interface in order for object instances of that class to persist on the hard-disk with an independent identity.

The class must be reflected, and have a reflected default constructor and a reflected copy constructor.

An object that implements IPersistable is not necessarily persistent because a PSpace implements persistence by reachability. When an object implements IPersistable, it only means that it is able to persist - it is merely a capability. In that sense type is orthogonal to persistence.


$interface+ IPersistable : IObject
{
    void VisitPrefs(IPrefVisitor& v) const;
    bool RepresentsSubTree() const;
    void Serialise(Archive& ar) const;
    InputArchive Deserialise(InputArchive ar);
    void OnCreate(bool local);
    PersistObjState& GetPersistObjState() const;
};

OnCreate() is called with local equal to true for a bootstrapped root when it is first created. OnCreate() is also called on each object within a working set when the object is first created. It is called with local equal to true if the object was locally generated on that working set, and with local equal to false if the object was created as a result of a received operation.

A mixin named PersistableMixin is used to help implement this interface - for example by providing the PersistObjState for a persistent object.

The serialisation methods (Serialise and Deserialise) must be implemented in order to allow the object state to be converted to or from a sequence of octets.

Tree structures

Often the persistent objects form trees, so every object represents the root node of a subtree.

In that case RepresentsSubTree() should be implemented as returning true.

Trees allow for simple recursive algorithms for operations such as cloning and deleting the objects, rather than more complex algorithms for arbitrary object graphs.

Dynamic creation of IPersistable objects

Objects that implement IPersistable are expected to have a reflected default constructor in order to support dynamic creation. More specificaly this is the m_createFn member of the associated ReflectedClass.

This constructor is run every time the object is loaded into memory, therefore it only relates to in-memory creation, rather than to the original creation. In order to allow for customisation of the latter, classes can implement OnCreate().

OIDs of IPersistable objects

Get the OID allocated to the given persistable object. Returns a null OID if the object has not been made persistent.


$function+ OID GetOid(ptr<const IPersistable> po)

Making objects persist


// Declares that 'child' is reachable from 'parent', so 'child' should have an OID allocated and be
// added to the PSpace
//
// It is not necessary to set the PSpace in thread local storage
$function+ void DeclareReachable(ptr<const IPersistable> parent, ptr<const IPersistable> child,bool trace = true);

Marking objects as dirty

The persist store layer requires that the client mark persistent objects as dirty as required. This is achieved by calling the following global function

void MarkPersistentAsDirty(ptr<const IPersistable> p)

For convenience the mixin provides a MarkAsDirty() function that calls the global function.


// It is vital that the programmer call this for each persistable object that is modified
// as part of a transaction.
//
// Failure to call this function may result in changes not being written to disk.
// Note that this function doesn't allocate OIDs to objects reachable from po.
//
// It is not necessary to set the PSpace in thread local storage
$function+ void MarkPersistentAsDirtyWithoutTrace(ptr<const IPersistable> po);

Copying persistent objects


// Makes a deep copy of the given object which may or may not be persistent (i.e. have an OID)
// The copy is created synchronously and is assumed to fit entirely in memory
// returns null if any object was found which is not reflected or is has no reflected create
// function.
$function+ ptr<IPersistable> SynchronousDeepCopyPersistableObject( ptr<IPersistable> po );

PersistableMixin

When a concrete class implements IPersistable Xcpp generates an implementation that uses a $mixin called PersistableMixin to help implement the interface. For example it adds state to record the OID allocated to the object, if any.

For convenience this mixin provides the method MarkAsDirtyWithoutTrace().


$mixin PersistableMixin
{
    void MarkAsDirtyWithoutTrace() const 
    { 
        if (!IsDirty())
        {
            MarkPersistentAsDirtyWithoutTrace($this); 
        }
    }
    ...
}