C · Transactions

Transactions

#include <ustore/db.h> 1.0.0-rc.1 · d6d40961

§ Transactions and Views

A transaction groups reads and writes across collections and modalities, and commits all of them or none. Writes take the transaction itself, while reads take a view of it, which also chooses whether the read registers its keys so the commit fails if another writer changed them since:

ustore_transaction_t transaction = NULL;
ustore_transaction_init(&(ustore_transaction_init_t){
    .transaction = &transaction,
    .database = database,
    .outcome = &outcome,
});

ustore_blobs_write(&(ustore_blobs_write_t){.database = database, .outcome = &outcome, .transaction = transaction, /* ... */});
ustore_blobs_read(&(ustore_blobs_read_t){
    .database = database, .outcome = &outcome,
    .view = ustore_transaction_view(transaction, ustore_watch_keys_k), /* ... */});

ustore_transaction_commit(&(ustore_transaction_commit_t){
    .database = database,
    .outcome = &outcome,
    .transaction = transaction,
});
ustore_transaction_free(transaction);

ustore_transaction_init begins a new transaction into a NULL handle, left NULL on failure, and resets a transaction of the same database in place, keeping its handle whatever the outcome, so a reset that fails leaves it fit only to be freed or initialized again. A failed commit keeps the contents of the transaction for a retry. ustore_transaction_rollback withdraws a stage, releasing whatever it claimed, while keeping the reads and writes, so the transaction can stage again or be reset through ustore_transaction_init. ustore_transaction_stage stages the transaction for a two-phase commit and can export its read_stamp, the ustore_stamp_t the transaction reads at and its commit validates against. A commit can export its commit_stamp, its position in commit order, which every snapshot at or above it sees, and is never below the stage’s read_stamp.

API

Types

ustore_transaction_tAn opaque handle to an optimistic transaction that groups operations across collections and modalities.
db.h:34 ↗
typedef struct ustore_transaction_handle_t * ustore_transaction_t;

It serves one call at a time, so a call on a transaction that serves an unfinished one finishes with ustore_status_contended_k, and holds its database open until ustore_transaction_free.

ustore_view_tAn opaque handle to what a read sees: the head of the database, a transaction or a snapshot.
db.h:45 ↗
typedef struct ustore_view_handle_t * ustore_view_t;

NULL is the head. Others come from ustore_transaction_view and ustore_snapshot_view, which tag the parent's pointer and allocate nothing, so a view needs no free and dies with its parent, which a cursor reading through it holds until the cursor is freed. A view names its parent, not a moment: after a commit, a transaction's view reads the transaction's next generation. Writes take a transaction instead, so nothing can write through a snapshot.

ustore_stamp_tA position in the order commits apply in, which grows with every commit: where a commit landed, or the newest commit a transaction or a snapshot reads.
db.h:79 ↗
typedef uint64_t ustore_stamp_t;
ustore_watch_tWhether a transaction records the keys a call reads or writes, to refuse its commit when another writer changes them first.
db.h:179 ↗
enum ustore_watch_t

Values

ustore_watch_keys_k0Records the keys, so a concurrent change to any of them fails the commit with a conflict.
ustore_watch_none_k1Records nothing, so concurrent changes to these keys never fail the commit.

Spellings

char const * ustore_watch_name(ustore_watch_t watch);
ustore_watch_t ustore_watch_from_name(ustore_bytes_view_t name);
ustore_isolation_tHow the transactions of the in-memory engine see each other's writes.
db.h:243 ↗
enum ustore_isolation_t

Values

ustore_isolation_strict_serializable_k0Every transaction appears to run alone at one moment between its start and its commit.
ustore_isolation_snapshot_k1Every transaction reads the state its start saw and conflicts only over what it writes.

Spellings

char const * ustore_isolation_name(ustore_isolation_t isolation);
ustore_isolation_t ustore_isolation_from_name(ustore_bytes_view_t name);

Functions

ustore_transaction_initBegins a transaction, or resets an existing one.
db.h:1212 ↗
void ustore_transaction_init(ustore_transaction_init_t *arguments);

Parameters

transactionustore_transaction_t *In and out: a NULL handle here begins a new transaction, which the caller frees with ustore_transaction_free, written on success and left NULL on failure; a transaction of database is reset in place onto a fresh snapshot, dropping its reads and writes, and keeps its handle whatever the outcome, so after a failed reset it can only be freed or initialized again.
databaseustore_database_tAn open database.
executorustore_executor_tExecutor that runs the call, where NULL runs it on the calling thread.
outcomeustore_outcome_t *Output for the outcome, final once its status leaves ustore_status_deferred_k.
completionustore_completion_tWhether the call returns final, the default, or once submitted.

Statuses

ustore_transaction_viewNames a transaction as the view a read sees, without allocating.
db.h:1220 ↗
ustore_view_t ustore_transaction_view(
    ustore_transaction_t transaction,
    ustore_watch_t watch);

Parameters

transactioninA transaction, which the view dies with.
watchinWhether reads through the view record their keys for conflicts.

Returns

The view, or NULL, the head, for a NULL transaction.

ustore_transaction_stageStages a transaction as the first phase of a two-phase commit.
db.h:1269 ↗
void ustore_transaction_stage(ustore_transaction_stage_t *arguments);

Parameters

databaseustore_database_tAn open database.
executorustore_executor_tExecutor that runs the call, where NULL runs it on the calling thread.
outcomeustore_outcome_t *Output for the outcome, final once its status leaves ustore_status_deferred_k.
completionustore_completion_tWhether the call returns final, the default, or once submitted.
transactionustore_transaction_tAn initialized transaction.
read_stampustore_stamp_t *Optional output for the stamp the transaction reads at, which its commit validates against; zeroed on failure.

Statuses

ustore_transaction_commitCommits a transaction.
db.h:1322 ↗
void ustore_transaction_commit(ustore_transaction_commit_t *arguments);

Parameters

databaseustore_database_tAn open database.
executorustore_executor_tExecutor that runs the call, where NULL runs it on the calling thread.
outcomeustore_outcome_t *Output for the outcome, final once its status leaves ustore_status_deferred_k.
completionustore_completion_tWhether the call returns final, the default, or once submitted.
transactionustore_transaction_tAn initialized transaction, staged first when the caller did not.
commit_stampustore_stamp_t *Optional output for the commit's position in commit order, visible to every snapshot at or above it; zeroed on failure.
durabilityustore_durability_tHow durable the writes are once the commit finishes.

Statuses

ustore_transaction_rollbackWithdraws a stage, releasing whatever it claimed, while keeping the reads and writes, so the transaction can stage again or be reset through ustore_transaction_init.
db.h:1358 ↗
void ustore_transaction_rollback(
    ustore_transaction_rollback_t *arguments);

Parameters

databaseustore_database_tAn open database.
executorustore_executor_tExecutor that runs the call, where NULL runs it on the calling thread.
outcomeustore_outcome_t *Output for the outcome, final once its status leaves ustore_status_deferred_k.
completionustore_completion_tWhether the call returns final, the default, or once submitted.
transactionustore_transaction_tA transaction, staged or not.

Statuses

ustore_transaction_freeWaits until every deferred call naming the transaction finishes, then resets it and frees its memory with every view of it once no cursor reads through it.
db.h:1365 ↗
void ustore_transaction_free(ustore_transaction_t transaction);

Parameters

transactioninoutThe transaction to be freed; NULL is safe.