ILssTransaction

A transaction is associated with mutative work on the LSS - i.e. for creating, rewriting or deleting serial elements.

During a transaction it is possible to delete or write serial elements. Writing a serial element encompasses creation of a new serial element as well as rewriting an existing serial element.

There is no concept of clients aborting a transaction. If a thread begins a transaction then it must eventually commit the transaction. As such there is no concept of roll-back during the normal operation of the LSS. Roll-back only occurs during recovery (i.e. when the store is opened when it was not previously closed gracefully)

Only a single thread can open a transaction on a given LSS at a time. This is enforced by a mutex within the implementation of the LSS. The mutex is locked by OpenTransaction() and unlocked when Close() is called on the transaction.

An exception may occur in the middle of a transaction. For example, a call to ReadSerialElement() may fail because of a low level I/O error, throwing a FileException. It is vital that the client still calls Close() even though an exception occurred. Otherwise the mutex will not be closed, and there could be a subsequent dead-lock - such as when the client tries to close the LSS.

Note that when such an internal I/O error occurds, the LSS will enter an "error" state, preventing any transactions from being propagated to disk, even though the transaction is explcitly closed. In other words, closing a transaction normally but doesn't always mean it is being committed.

The best way to ensure correctness in the face of exceptions is to declare an instance of an AutoCloser<ILssTransaction> on the frame in order to perform a transaction on the LSS within a lexical scope.


struct ILssTransaction
{
    virtual void Close() = 0;
    virtual void FlushWhenClose() = 0;
    virtual ICloseableOutputStream* WriteSerialElement(Seid seid) = 0;
    virtual bool DeleteSerialElement(Seid seid) = 0;
    virtual void DeleteSeidSpace(SeidHigh seidHigh) = 0;
};


void Close()

A transaction must be explicitly closed, even if exceptions have been thrown by the LSS. Must only be called by the thread that originally opened this transaction. It is an error to close the transaction before the current serial element being written is closed.

If FlushWhenClose() has previously been called on this transaction then Close() will synchronously flush this and all previous transactions on the LSS.


void FlushWhenClose()

Puts this transaction into a mode where it will synchronously flush all data written to the LSS when this transaction is closed.

Must only be called by the thread that originally opened this transaction The subsequent Close() will only return after the transaction (and all previous transactions) have been written to disk - at least according to the Win32 calls. Note that the LSS file is opened with "no write through cache". Despite this hard-disks that have their local cache enabled may defeat the assumption that the data is made durable. This could be a problem for a multi-phase commit protocol (for example).


ICloseableOutputStream* WriteSerialElement(Seid seid)

Returns a stream to be used to write the serial element with the given Seid. If the serial element already exists then the previous rendition will be replaced by a new one. The returned stream must be closed after it is used. Furthermore, it must be closed before the next call to WriteSerialElement(), DeleteSerialElement(), DeleteSeidSpace() or Close() on this transaction.

Never returns nullptr.

Must only be called by the thread that originally opened this transaction It is an error to call this function on a serial element that is currently opened for reading

For more details see writing serial elements.


bool DeleteSerialElement(Seid seid)

Permanently delete the serial element with the given Seid Must only be called by the thread that originally opened this transaction It is an error to delete a serial element that is currently opened for reading or writing Returns false if there is no serial element with the given Seid.


void DeleteSeidSpace(SeidHigh seidHigh)

Delete the Seid space associated with the given SeidHigh. The Seid space must be empty - i.e. by calling DeleteSerialElement() as required to delete all serial elements in the Seid space. Must only be called by the thread that originally opened this transaction