PersistStoreTxn

Transactions

A transaction must be opened before reading or writing objects in one or more PSpaces. Only the thread that opened the transaction is permitted to access the objects, then subsequently close the transaction.

Before accessing objects in a PSpace it is necessary to

  1. Lock the associated CSpaces. Note that multiple CSpaces can be locked, some with exclusive locks and others with shared read locks.
  2. Open a transaction on the PersistStore

In other words PSpaces impose an additional requirement, on top of the CSpaces before their objects can be accessed.

Note that it is necessary to open a transaction even when only read access on a PSpace is required.

There is no concept of aborting a transaction and having objects roll back to an earlier state. Generally speaking, changes should only be made to persistent objects if there is every intention to commit to the changes. As a result it is not usually appropriate to perform fallible work within a transaction.

Opening/creating PSpaces within a transaction

When a store is first created there are no PSpaces. A transaction on the store must be created without actually locking any PSpaces. This is possible because a transaction takes an array of PSpaces, and it is allowable for the array to be empty.

Within a transaction (whether it locked some PSpaces or not), it is possible to create new PSpaces, or open existing PSpaces. It is assumed that this implicitly exclusive locks them, as part of the current transaction. These new PSpaces are added to the "transaction group" that must all have their changes written to the LSS in a single transaction.

If initially there are only PSpaces opened for reading, then no grouping is performed. Despite this they may all be grouped later if a PSpace is created within the scope of the transaction.

CSpace locking

A thread that calls OpenTxn() must have already locked the relevant CSpaces. This allows for locking CSpaces independently of their affinity for particular persistent stores.

However PSpaces are automatically exclusive locked as they are opened, and the PersistStoreTxn takes on the responsibility to automatically release these locks when the transaction closes.

Note that it is allowable to lock a large set of CSpaces that encompasses multiple PersistStores and a single thread can simultaneously open transactions on all the PersistStores. Note however that atomicity across different PersistStores is not supported. I.e. it is possible that one transaction commits and another doesn't.

PersistStoreTxn


$adt+ PersistStoreTxn
{
    void Close();
    PersistStore* GetPersistStore();
    PSpace* OpenPSpace(ConstStringZ name, EOpenMode openMode, CSpace* cspace);
    void TransferPSpace(PSpace* dst, PSpace* src);
    bool DestroyPSpace(ConstStringZ name);
};


void Close()


PersistStore* GetPersistStore()

Get the associated PersistStore. Never returns nullptr.


PSpace* OpenPSpace(
    ConstStringZ name,
    EOpenMode openMode,
    CSpace* cspace = nullptr)

Open or create the PSpace with the given name. The name can be any non-empty null terminated UTF-8 string.

If this creates a PSpace then the creation is committed as part of this transaction.

If cspace is null then the PSpace will create its own CSpace, otherwise it will use the given cspace.

Whether the PSpace is opened or created for the first time, it is assumed that this function implicitly exclusive locks the CSpace associated with that PSpace, and adds it to the set of mutable PSpaces associated with the given transaction.

If name = nullptr then an anonymous PSpace is created. In that case openMode must equal OM_CREATE_NEW. An anonymous PSpace doesn't persist after it is closed.

Throws PSpaceExceptions on failure. If the openMode used requires prior existence of a PSpace or absence and the expectation is not met, an OpenPSpaceException can be thrown. Never returns nullptr.

Example usage...


PSpace* p = OpenPSpace(txn,"x",OM_OPEN_ALWAYS,cspace);
if (CreatedNew(p))
{
    // bootstrap a PSpace root
}

It is an error to open a PSpace that is currently open [this error causes an assertion failure in Debug]


void TransferPSpace(PSpace* dst, PSpace* src)

Transfers all objects from the src PSpace into the dst PSpace. The implementation of this function performs the following steps

  1. Call StopGc() on the associated src CSpace
  2. Call TransferCSpace() on the associated CSpaces
  3. Transfer all entries in the src deletion queue to the dst deletion queue
  4. Transfer all entries in the src ROT to the dst ROT
  5. Transfer all entries in the src DOS to the dst DOS
  6. Remove all src roots

As a result the src PSpace will end up with no objects and no roots. Therefore after the client closes the src PSpace it will be possible to call DestroyPSpace() to delete it.

A precondition of this function is that both the dst and src PSpaces have been exclusive write locked by this transaction [otherwise get an assertion in debug].


bool DestroyPSpace(ConstStringZ name)

Permanently destroy the PSpace with the given name in the PersistStore associated with the given transaction.

The PSpace must be empty i.e. all objects have been deleted, and all roots have been removed.

The PSpace must not be currently open.

Returns false if no PSpace with the given name was found.

This change to the persistent store is committed as part of the transaction.