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§
Sourcefn put_blob(&self, bytes: &[u8]) -> Result<BlobId>
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.
Sourcefn get_blob(&self, id: &BlobId) -> Result<Option<Vec<u8>>>
fn get_blob(&self, id: &BlobId) -> Result<Option<Vec<u8>>>
The bytes at this address, or None if nothing was ever stored there.
Sourcefn read_doc(&self, name: &str) -> Result<Option<BlobId>>
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.
Sourcefn commit_doc(
&self,
name: &str,
expected: Option<BlobId>,
new: BlobId,
) -> Result<bool>
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.
Provided Methods§
Sourcefn put_blob_unsynced(&self, bytes: &[u8]) -> Result<BlobId>
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".