Skip to main content

ControlStore

Trait ControlStore 

Source
pub trait ControlStore:
    Send
    + Sync
    + 'static {
    // Required methods
    fn put_blob(&self, bytes: &[u8]) -> Result<BlobId>;
    fn get_blob(&self, id: &BlobId) -> Result<Option<Vec<u8>>>;
    fn read_doc(&self, name: &str) -> Result<Option<BlobId>>;
    fn commit_doc(
        &self,
        name: &str,
        expected: Option<BlobId>,
        new: BlobId,
    ) -> Result<bool>;
    fn history(&self, name: &str) -> Result<Vec<DocVersion>>;

    // Provided method
    fn put_blob_unsynced(&self, bytes: &[u8]) -> Result<BlobId> { ... }
}
Expand description

Where a control document is kept.

A trait rather than the concrete store, for one reason, and it is measure, never assert: tests/control_cost.rs proves the compare-and-swap by running the same concurrency test against a store that ignores the expectation, in the same run, and asserting that acknowledged writes are lost. A guard that cannot be broken is a guard nobody has seen fail. The counting decorator that measures what a connection costs lives on the same seam.

Required Methods§

Source

fn put_blob(&self, bytes: &[u8]) -> Result<BlobId>

Store these bytes and return their address. Idempotent: storing the same bytes twice is one row and the same id.

Source

fn get_blob(&self, id: &BlobId) -> Result<Option<Vec<u8>>>

The bytes at this address, or None if nothing was ever stored there.

Source

fn read_doc(&self, name: &str) -> Result<Option<BlobId>>

Which version name is at, or None for a document that has never been written.

None is a legitimate state and a fault is not. A read that could not distinguish them would report an unreadable identity table as no principals are registered, which is the failure that opens a server up.

Source

fn commit_doc( &self, name: &str, expected: Option<BlobId>, new: BlobId, ) -> Result<bool>

The compare-and-swap. Move name from expected to new, and append the new version to the audit trail, atomically.

Ok(false) means the document was not at expected — another writer committed in between — and the caller must re-read and re-apply. It is deliberately not an error: losing a race is an ordinary outcome of a contended document and a caller that retried on Err would also retry on a broken disk.

Source

fn history(&self, name: &str) -> Result<Vec<DocVersion>>

Every version name has had, oldest first (the control plane’s audit trail).

Provided Methods§

Source

fn put_blob_unsynced(&self, bytes: &[u8]) -> Result<BlobId>

ControlStore::put_blob for a blob that only a LATER ControlStore::commit_doc makes part of any state (perf twin-apply-fsync, 2026-10-06): the store may keep it without making it durable on its own, because the pointer move that publishes it is durable and persists it — redb’s durable commit persists every earlier commit. Until then it is an unreferenced, content-addressed row nothing can reach, and a crash that takes it takes nothing anybody could see. The default is the durable put_blob.

The primary’s tee uses it for a document’s shards. A replay that re-applies only its head entry after a crash (a box being restored) must NOT: its blob frames are durable one by one and the document that publishes them may be several frames on.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§