PSpace

A PSpace contains the set of persistable objects belonging to its associated CSpace. An object implementing interface IObject belongs to at most one CSpace (and hence at most one PSpace).

The persistable objects in a PSpace implement IPersistable which is a sub-interface of IObject.

The persistable objects in a PersistStore are partitioned into mutually exclusive PSpaces. The independence between PSpaces helps to promote concurrency in multi-threaded systems.

Persistent objects in a PSpace may only pref other other objects in the same PSpace.

Persistence by reachability

A PSpace implements persistence by reachability: an object is persistent if and only if it is reachable from a persistent root of the PSpace.

When MarkAsDirty() is called on a persistable object, its outgoing pointers are tested to see whether:

  1. they implement IPersistable; and
  2. the object has been reached for the first time.

If so then that object is allocated an OID and added to the PersistStore. All reachable persistent objects are found in a similar fashion to the tracing garbage collector.

Note that MarkAsDirty() is a no-op on a persistable object that doesn't yet persist.

Associated CSpace

Each PSpace has exactly one associated CSpace. A PSpace follows the threading model prescribed for CSpaces. For example, a thread needs an exclusive lock on the associated CSpace before it can modify any of the objects. A thread needs either a shared read or exclusive lock on the associated CSpace before it can read-access any of the objects in the PSpace.

Conceptually a CSpace contains its associated PSpace.

In other words, there can be objects in the CSpace associated with the PSpace that don't persist. All objects in the CSpace, including the transient objects outside the PSpace are protected by the CSpace shared read / exclusive write mutex.

Name

Each PSpace has a name which can be any nonempty UTF-8 string. Within a given PersistStore, the PSpaces are uniquely identified by their name. The name is provided at the time the PSpace is first created. The name cannot be changed afterwards.

Pointer to the current PSpace in thread local storage

Many functions make use of a pointer to a PSpace in thread local storage, to avoid the need to explicitly pass a pointer to the PSpace around all the time.

In particular this is needed to support a dereference operation on a pref or cref.

See PSpace in thread local storage.

API


$adt+ PSpace
{
    void Close();
    bool CreatedNew() const;
    CSpace* GetCSpace();
    PersistStore* GetPersistStore();
    ConstStringZ GetName() const;
    void WriteDirtyObjectsToLss(bool flushToDisk);
    void MarkPersistableAsDirtyWithoutTrace(ptr<const IPersistable> po);
    ptr<IPersistable> BindObject(OID oid);
    ptr<IPersistable> BindObjectIfMemoryResident(OID oid);
    ptr<IPersistable> TryBindObject(OID oid);
    void MakeMemoryResident(OID oid);
    MAsyncBind AsyncBind2(OID oid);
    ptr<IPersistable> AsyncBind(OID oid);
    ptr<IAsyncBindRequestHandler> GetAsyncBindRequestHandler() const;
    void SetAsyncBindRequestHandler(ptr<IAsyncBindRequestHandler> h);
    void DeclareObjectDoesNotExist(OID oid);
    void MakeObjectPersist(OidLow affiliateOidLow, ptr<IPersistable> po);
    OID AllocateOid(OidHigh oidHigh, bool useIncrementalOidAllocations);
    OidHigh GetOidHighForOidAllocations() const;
    void SetOidHighForOidAllocations(OidHigh oidHigh, bool useIncrementalOidAllocations);
    bool MakeObjectPersistWithGivenOID(ptr<IPersistable> po, OID oid, bool trace);
    void DeclareReachable(ptr<const IPersistable> parent, ptr<const IPersistable> child, bool trace);
    void MakeReachableObjectsPersist(ptr<IPersistable> po);
    ptr<IPersistable> GetRoot(ConstStringZ name);
    bool AddRoot(ConstStringZ name, ptr<IPersistable> root);
    bool RemoveRoot(ConstStringZ name);
    void AsyncPermanentlyDeleteSubTree(ptr<IPersistable> obj);
    void AsyncPermanentlyDeleteObject(ptr<IPersistable> obj);
    void SyncPermanentlyDeleteSubTree(ptr<IPersistable> obj);
    void SyncPermanentlyDeleteObject(ptr<IPersistable> obj);
};

These methods are discussed in the the following sections:


void Close()

Close this PSpace, A transaction is not required to close a PSpace. Closing a PSpace has the effect of destroying its associated CSpace, and all the objects in the CSpace. This includes the objects in the PSpace currently resident in memory. There cannot be any open locks on the associated CSpace. This call will synchronously write any dirty objects to the LSS. Therefore it may block on I/O. Different PSpaces can be closed from different threads simultaneously.


bool CreatedNew() const

Indicates whether PSpace was created for the first time, in the call to OpenPSpace().


CSpace* GetCSpace()

Get the associated CSpace. Never returns nullptr.


PersistStore* GetPersistStore()

Get the associated PersistStore. Never returns nullptr.


ConstStringZ GetName() const


void WriteDirtyObjectsToLss(bool flushToDisk)

Ensure that all dirty objects in this PSpace (and any other PSpaces in the group that have been tied to this PSpace for the purposes of ensuring transaction atomicity) are written to the LSS using a single LSS transaction. If flushToDisk = true then the LSS transaction is also flushed to disk before this function returns. Must be called without a lock on any of the applicable PSpaces


void MarkPersistableAsDirtyWithoutTrace(ptr<const IPersistable> po)

Used for marking objects in the PSpace as dirty. Mark po as dirty. Does not trace from po in order to allocate OIDs.

Additional functions relevant to PSpaces


$function+ PSpace* GetPSpaceOfCSpace(CSpace* cs)

Get the PSpace associated with the given CSpace or else returns nullptr if the CSpace doesn't have an associated PSpace.


$function+ PSpace* OpenPSpace(
    PersistStore* ps,
    ConstStringZ name,
    EOpenMode openMode = OM_OPEN_ALWAYS,
    CSpace* cspace = nullptr)

Open or create a PSpace with the given name on the given PersistStore