CommitDatabase

class dsviper.CommitDatabase(commit_databasing)

Bases: object

A Commit database keeps the history of mutations in a DAG of commits.

Use the static factory method create_in_memory(), create(…), open(…), connect(…) or connect_local(…).

Writes here need NO transaction, unlike a Database, where every write requires one already open. A blob stored here survives without any commit; a commit records mutations of documents, not of blobs.

One file may be open in several processes; SQLite locks it. A commit writes in one short statement, while extend_definitions, reduce_heads and the transfers hold the file exclusively as they run. A call from another process meanwhile waits for up to 10 seconds, then raises ViperError: the database is busy.

blob(blob_id: ValueBlobId) → ValueBlob | None

Return the bytes of the blob blob_id names, or None if it is not held here.

Raises past 2 GB, where the bytes cannot be handed over in one piece. Ask blob_info(blob_id).chunked() first, and read such a blob with read_blob.

A blob commit_databasing().create_zero_blob reserved raises until commit_databasing().freeze_blob seals it; blob_info answers None for it meanwhile.

blob_getting() → BlobGetting

Return the BlobGetting interface.

blob_ids() → set[ValueBlobId]

Return the set of blob_id of every sealed blob.

A blob commit_databasing().create_zero_blob reserved joins it once commit_databasing().freeze_blob seals it.

blob_info(blob_id: ValueBlobId) → BlobInfo | None

Return the BlobInfo for blob_id, or None if there is no such blob.

It gives the layout, the size, whether the blob is chunked, and the rowid that reaches it. A blob commit_databasing().create_zero_blob reserved answers None until commit_databasing().freeze_blob seals it.

blob_infos(blob_ids: set[ValueBlobId]) → list[BlobInfo]

Return one BlobInfo per blob_id of blob_ids the database holds.

An unknown blob_id is left out, so the list may be shorter than blob_ids.

blob_statistics() → BlobStatistics

Return the statistics for blobs.

blob_stream_append(blob_stream: BlobStream, blob: ValueBlob) → None

Append blob to blob_stream, after the bytes already written.

A failure here closes the stream and discards what it collected, so nothing partial is left behind and there is nothing to clean up.

blob_stream_close(blob_stream: BlobStream) → ValueBlobId

Close blob_stream and return its blob_id.

The blob_id is computed from everything written into it.

A failure here closes the stream and discards what it collected, so nothing partial is left behind and there is nothing to clean up.

blob_stream_create(blob_layout: BlobLayout, size: int) → BlobStream

Return a BlobStream to fill a blob of size bytes laid out by blob_layout.

children_commit_ids(commit_id: ValueCommitId) → set[ValueCommitId]

Return a set of commit_id for the children of the commit.

close() → None

Close the database.

codec_name() → str

Return the name of the codec.

commit(commit_id: ValueCommitId) → Commit

Return the commit commit_id names, header and opcodes.

commit_databasing() → CommitDatabasing

Return the CommitDatabasing interface.

commit_exists(commit_id: ValueCommitId) → bool

Return True if the database holds the commit commit_id names.

commit_header(commit_id: ValueCommitId) → CommitHeader

Return the CommitHeader of the commit commit_id names - its label, its type, its parent and its timestamp.

commit_ids() → set[ValueCommitId]

Return a set of commit_id for all available commits.

A set: these are the commits, without duplicates and in no order. Iterating one twice gives the same sequence, but it means nothing - sort the ids for a reproducible listing, a commit_id having a total order.

The history’s order is a different thing and no sort gives it: walk CommitNode.build. CommitHeader.timestamp does not, for the reason written there.

commit_mutations(label: str, commit_mutable_state: CommitMutableState) → ValueCommitId

Append what commit_mutable_state recorded as a new commit under label.

It returns the new commit_id. The commit’s PARENT is the state commit_mutable_state was built from, so the returned commit_id is what the next mutation starts from: pass it to CommitStateBuilder.state to carry on in one line. Building the next mutation from initial_state instead diverges from the root, and the database then has two heads.

static connect(host: str, service: str = '54321') → CommitDatabase

Return a CommitDatabase served by host on service, over TCP.

static connect_local(socket_path: str) → CommitDatabase

Connect to a socket located at socket_path.

static create(file_path: str, *, documentation: str | None = None) → CommitDatabase

Create a database at file_path and return it.

documentation is stored in the file and read back by documentation().

Requires that nothing exist at file_path, and raises without creating anything when something does.

create_blob(blob_layout: BlobLayout, blob: ValueBlob) → ValueBlobId

Store blob under blob_layout, and return the blob_id computed from its content and that layout.

create_blob_from_buffer(buffer) → ValueBlobId

Store the bytes of a buffer or a ValueBlob; return their blob_id.

static create_in_memory() → CommitDatabase

Create a database in memory.

definitions() → DefinitionsConst

Return the Definitions every value in the database is typed by.

It is a SNAPSHOT: extending the database afterwards does not show through the handle you hold, so ask again. A view obtained from Definitions.const() is live instead - same class, opposite liveness.

definitions_hexdigest() → str

Return the SHA1 of the definitions, as a hex string.

delete_commit(commit_id: ValueCommitId) → None

Delete the commit commit_id names.

Breaks the append-only invariant every other reader relies on, and only makes sense on a head: deleting any other commit orphans its descendants. Kept for rewinding an interactive demonstration, not for storage management.

disable_commit(label: str, parent_commit_id: ValueCommitId, disabled_commit_id: ValueCommitId) → ValueCommitId

Append a commit under label that hides disabled_commit_id.

It sits on top of parent_commit_id, and its commit_id is returned.

Nothing is removed: the evaluator skips the hidden commit from here on.

documentation() → str

Return the free text stored with the database at create(). One made without any answers ‘not documented.’, one made in memory answers ‘In Memory’ - both are placeholders written in at create(), not substituted on read.

enable_commit(label: str, parent_commit_id: ValueCommitId, enabled_commit_id: ValueCommitId) → ValueCommitId

Append a commit under label that unhides enabled_commit_id, on top of parent_commit_id, and return its commit_id.

extend_definitions(other: DefinitionsConst) → DefinitionsExtendInfo

Add every type and attachment of other that the database does not already hold.

first_commit_id() → ValueCommitId | None

Return the commit_id of the first commit or None.

First in creation order, which is the root of the DAG CommitNode.build walks.

head_commit_ids() → set[ValueCommitId]

Return a set of commit_id for the available heads.

in_memory() → bool

Return True if the database is in memory.

is_ancestor(commit_id: ValueCommitId, descendant_id: ValueCommitId) → bool

Return True if commit_id is an ancestor of descendant_id.

A commit is its own ancestor. A merge commit is reached through both its parent and its target.

is_closed() → bool

Return True if the database is closed.

static is_compatible(file_path: str) → bool

Return True if the file at file_path carries the expected SQL schema.

is_mergeable(parent_commit_id: ValueCommitId, merged_commit_id: ValueCommitId) → bool

Return True if parent_commit_id and merged_commit_id have diverged - neither is an ancestor of the other.

last_commit_id() → ValueCommitId | None

Return the commit_id of the last commit or None.

Last in creation order: the one a new commit follows, and the one CommitStore.use resumes from.

merge_commit(label: str, parent_commit_id: ValueCommitId, merged_commit_id: ValueCommitId) → ValueCommitId

Append a commit under label joining two heads, and return its commit_id.

The commit records the pair (parent_commit_id, merged_commit_id); nothing is composed here. At reconstruction merged_commit_id’s mutations land last, which makes the join deterministic but not commutative: swapping the two gives a different commit.

On a path both heads wrote, merged_commit_id wins and the other is dropped; nothing is signalled. CommitMergeAnalyzer reconstructs, after the fact, what a merge did not keep.

nephew_commit_ids(commit_id: ValueCommitId) → set[ValueCommitId]

Return a set of commit_id for the nephew of the commit.

static open(file_path: str, readonly: bool = False) → CommitDatabase

Open the database at file_path and return it.

readonly opens it without allowing a commit.

Requires a file at file_path, and raises when there is none.

path() → str

Return the file path the database was opened from.

A database made in memory answers ‘InMemory’ rather than a path, and that exact string is how the runtime recognises one, so no file may take it: creating or opening a file of that path raises. Over a socket the answer is whatever the server answers for its own database.

read_blob(blob_id: ValueBlobId, size: int, offset: int) → ValueBlob

Return size bytes of the blob blob_id names, starting at offset.

The read side of blob_stream_create, blob_stream_append and blob_stream_close, and the only way to read a blob past 2 GB, which blob() refuses.

reset_commits() → None

Remove all commits except the first one.

Breaks the append-only invariant every other reader relies on. Kept for replaying an interactive demonstration from a known baseline, not for storage management.

stream_codec_instancing() → StreamCodecInstancing

Return the StreamCodecInstancing interface used to encode the binary data.

uuid() → ValueUUId

Return the uuid identifying this database, generated at create().