Skip to main content

FeltDb

Struct FeltDb 

Source
pub struct FeltDb { /* private fields */ }

Implementations§

Source§

impl FeltDb

Source

pub fn open<P: AsRef<Path>>(path: P) -> Result<Self>

Source

pub fn write_backup(&self, path: &Path) -> Result<BackupVerification>

Write a self-contained durable backup artifact.

The artifact does not depend on this database remaining present: it carries every live record, the revision graph, retention state and the observed operation versions, plus the digests needed to check all of it without a live database.

Source

pub fn restore_backup( backup: &Path, target: &Path, ) -> Result<(Self, BackupVerification)>

Restore a backup artifact into a new database.

Refuses to write over an existing database: a restore that could overwrite the thing an operator is trying to recover is not a recovery tool. The artifact is verified first, and the restored database is verified again afterwards — its meaning is recomputed from the live database and compared with the artifact’s. A restore therefore proves that the result means the same thing, not merely that the file parsed.

Source

pub fn state_digest(&self) -> Result<String>

A digest of this database’s application state: the records an application reads, and nothing else.

Excludes revisions and retention state, so it answers only “do these two databases hold the same values?”. Pair it with StateStore::history_digest to ask the separate and stronger question of whether they hold the same history — two databases can match on this and differ completely on that, which is exactly the failure replication used to have.

Source

pub fn durability_mode(&self) -> DurabilityMode

How far a single-record write is pushed before it returns.

Source

pub fn set_durability_mode(&self, mode: DurabilityMode)

Choose what a successful single-record write guarantees.

This changes the database’s contract, not merely its speed. Transaction commits always issue a stable-storage barrier and are unaffected.

Source

pub fn health(&self) -> DatabaseHealth

What this database knows about itself.

Reports facts the open established — the durable format it was accepted as, and whether replay discarded an incomplete final append. It reports nothing it has not observed: health can expose a proven fact, it cannot create a stronger guarantee.

In particular this says nothing about power-loss durability, which is unproven, nor about replication or backup state, which have no operational contract yet.

Source

pub fn log_recovery(&self) -> LogRecovery

What replaying the durable log had to do for this database to open.

LogRecovery::Clean means every durable byte was a complete, valid record. LogRecovery::RecoveredTornTail means the log ended in an incomplete append that was discarded — the database is usable and its last write did not land, which is a different fact from healthy and one an operator has to be able to learn.

A corrupt log does not reach here at all: it refuses the open.

Source

pub fn insert<T: Serialize>(&self, key: &str, value: T) -> Result<()>

Source

pub fn insert_if_absent<T: Serialize>(&self, key: &str, value: T) -> Result<()>

Insert only if the logical record is absent, deciding presence under the same lock that appends the operation and mints its first revision.

Source

pub fn update<T: Serialize>(&self, key: &str, value: T) -> Result<()>

Update an existing record with vector clock tracking

Source

pub fn compare_and_set_json( &self, key: &str, expected_version: u64, expected_epoch: Option<u64>, expected_lease_id: Option<&str>, reject_if_diverged: bool, value: Value, ) -> Result<JsonCasResult>

Atomically compare the logical record version and authority epoch before durably replacing a JSON object. Failed predicates append no operation and emit no change event.

Source

pub fn delete(&self, key: &str) -> Result<()>

Delete a record with vector clock tracking

Source

pub fn insert_with_authorization<T: Serialize>( &self, key: &str, value: T, context: &AuthorizationContext, ) -> Result<()>

Insert a record with authorization context

Source

pub fn update_with_authorization<T: Serialize>( &self, key: &str, value: T, context: &AuthorizationContext, ) -> Result<()>

Update a record with authorization context

Source

pub fn delete_with_authorization( &self, key: &str, context: &AuthorizationContext, ) -> Result<()>

Delete a record with authorization context

Source

pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>>

Source

pub fn query<T, F>(&self, predicate: F) -> Result<Vec<T>>
where T: DeserializeOwned, F: Fn(&T) -> bool,

Source

pub fn capability(&self, name: &str) -> Capability

Source

pub fn is_auto_indexed<T>(&self) -> bool

Source

pub fn instance_id(&self) -> Result<String>

Get the instance ID for this FeltDB instance

Source

pub fn sequence(&self) -> Result<u64>

Get the current sequence number for this instance

Source

pub fn current_revision(&self) -> Result<u64>

Revision of the snapshot held by this embedded authority instance. In multi-process topology callers must use AuthorityClient::read to cross the authority boundary and obtain a current authoritative value.

Source

pub fn collection_cardinality(&self, capability: &str) -> Result<u64>

Get the maintained cardinality (record count) for a collection capability. Returns the count of non-deleted records in the collection.

Source

pub fn list_cardinalities(&self) -> Result<Vec<(String, u64)>>

Diagnostic: List all collection capabilities and their cardinalities. Used to detect capability format mismatches.

Source

pub fn diagnostic_row_count(&self, capability_pattern: &str) -> Result<usize>

Diagnostic: Count actual rows for a given capability pattern. Used to verify that rows exist even if cardinality is 0.

Source

pub fn diagnostic_capability_keys( &self, capability_pattern: &str, ) -> Result<Vec<String>>

Diagnostic: Get actual persisted capability strings matching a pattern. Used to identify capability identity formats in use.

Source

pub fn committed_transaction( &self, transaction_id: &str, payload_hash: Option<&str>, ) -> Result<Option<AtomicCommit>>

The original commit of a transaction id, if it committed, exactly as a retry of it through apply_atomic_transaction_* would report it: the original revisions and positions (duplicate: true), or TransactionIdPayloadMismatch when payload_hash differs from the one the id was committed with. Read-only.

Source

pub fn has_applied_transaction(&self, transaction_id: &str) -> Result<bool>

Source

pub fn applied_transaction_payload_hash( &self, transaction_id: &str, ) -> Result<Option<String>>

Source

pub fn apply_atomic_transaction( &self, transaction_id: &str, expected_parent: Option<u64>, preconditions: &[AtomicPrecondition], mutations: &[AtomicMutation], audit: Option<Value>, ) -> Result<AtomicCommit>

Atomically validates and durably applies an ordered mutation batch. The complete transaction is represented by one log record and becomes visible in memory only after that record has been appended successfully.

Source

pub fn apply_atomic_transaction_content_addressed( &self, transaction_id: &str, payload_hash: Option<&str>, expected_parent: Option<u64>, preconditions: &[AtomicPrecondition], mutations: &[AtomicMutation], audit: Option<Value>, ) -> Result<AtomicCommit>

Applies a transaction whose identifier is durably bound to a canonical payload hash. The same ID with a different payload is always a conflict.

Source

pub fn apply_atomic_transaction_guarded( &self, transaction_id: &str, payload_hash: Option<&str>, expected_parent: Option<u64>, preconditions: &[AtomicPrecondition], record_preconditions: &[RecordPrecondition], mutations: &[AtomicMutation], audit: Option<Value>, ) -> Result<AtomicCommit>

Commit a transaction only if every record precondition holds.

The preconditions are evaluated inside the same lock as the writes and before any of them, so there is no state in which one record is checked while the others commit. A failure returns FlowError::PreconditionFailed and applies nothing – not a prefix, not the guarded record, nothing.

A failed precondition does not consume the transaction id. The id is recorded only after a commit, so a caller that loses a race may retry the same id once it has re-read state, and a caller that wants the retry to be a distinct decision may use a new one. Both work; the choice is the caller’s and is asserted in the tests rather than left implied.

Source

pub fn read_basis(&self, reads: &ReadSet) -> Result<ReadBasis>

Capture a read basis on the direct route, under the same lock every commit takes.

Source

pub fn read_basis_in( &self, reads: &ReadSet, layout: &ReadLayout, ) -> Result<ReadBasis>

Capture a read basis in a storage layout, under the same lock every commit takes.

Source

pub fn apply_atomic_transaction_fenced( &self, transaction_id: &str, payload_hash: Option<&str>, expected_parent: Option<u64>, preconditions: &[AtomicPrecondition], record_preconditions: &[RecordPrecondition], fences: &[ReadBasis], mutations: &[AtomicMutation], audit: Option<Value>, ) -> Result<AtomicCommit>

apply_atomic_transaction_guarded, additionally fenced by read bases.

Each basis is re-evaluated inside the same lock as the writes, after the record preconditions and before anything is staged. If the state it names differs from what was read – whichever write path changed it – the transaction fails with PreconditionFailed(Fence) and applies nothing. State outside every basis is never read and never conflicts.

Source

pub fn apply_atomic_transaction_fenced_in( &self, transaction_id: &str, payload_hash: Option<&str>, expected_parent: Option<u64>, preconditions: &[AtomicPrecondition], record_preconditions: &[RecordPrecondition], layout: &ReadLayout, fences: &[ReadBasis], mutations: &[AtomicMutation], audit: Option<Value>, ) -> Result<AtomicCommit>

apply_atomic_transaction_fenced, with the read bases addressed in layout. The same evaluation, inside the same lock, for every route.

Source

pub fn apply_atomic_transaction_with_authorization( &self, transaction_id: &str, expected_parent: Option<u64>, preconditions: &[AtomicPrecondition], mutations: &[AtomicMutation], audit: Option<Value>, context: &AuthorizationContext, ) -> Result<AtomicCommit>

Apply atomic transaction with authorization context (atomic rejection on deny)

Source

pub async fn live_query<T, F>( &self, predicate: F, ) -> Result<LiveQuerySubscription<T>>
where T: DeserializeOwned + Send + Sync + 'static, F: Fn(&T) -> bool + Send + Sync + 'static,

The subscription returns an initial set of matching results, and provides a stream of updated results whenever records matching the predicate are inserted or updated.

§Example
ⓘ
use feltdb::open;
let db = open("app.data")?;
let mut subscription = db.live_query::<User, _>(|u| u.active).await?;
let initial_users = subscription.initial_results();

while let Some(users) = subscription.next().await {
    println!("Active users: {:?}", users);
}
Source

pub fn sync_info(&self) -> Result<SyncState>

Get current sync state information

Source

pub fn authority_time_ms(&self) -> u64

The authority’s wall-clock time in milliseconds.

The same reading the commit-time lease predicate uses, exposed so a decision that depends on lease expiry can be made against the clock that will later judge the commit. A caller’s own clock is never a substitute.

Source

pub fn get_value(&self, key: &str) -> Result<Option<Value>>

Read an untyped value for protocol adapters such as the HTTP server.

Source

pub fn list_collection(&self, capability: &str) -> Result<Vec<StoredRow>>

Source

pub fn query_collection<F>( &self, capability: &str, limit: Option<usize>, predicate: F, ) -> Result<Vec<StoredRow>>
where F: FnMut(&StoredRow) -> bool,

Evaluate a predicate over one collection without materializing it.

The predicate observes each live row borrowed from state, so a record the predicate rejects is never cloned. Only retained rows are cloned, which happens while state protection is still held: the returned rows are owned, so nothing the caller keeps can reference storage a concurrent mutation may move or drop after the lock is released.

Traversal is the collection’s own record-key order, the same order FeltDb::list_collection_page walks. limit bounds accumulation and stops the traversal as soon as it is satisfied; because early stopping truncates in record-key order, a caller that must order results by some other field has to pass None and bound its own already-filtered set.

The predicate runs under the state lock, so it must not call back into the database or block.

Source

pub fn create_equality_index( &self, collection: &str, field: &str, ) -> Result<bool>

Declare an equality index on one collection field and populate it from authoritative state. Returns whether this call created the index.

Creation and population happen under one lock, so an index is never observable in a half-built state. Declaring an index that already exists is not an error and does not rebuild it.

recordId is refused: on the query surface it is authority metadata that shadows a document field of the same name on object-valued records only, so an index over the document field would answer a different question from the one the predicate asks.

Source

pub fn drop_equality_index(&self, collection: &str, field: &str) -> Result<bool>

Drop an equality index and its buckets. Returns whether one existed.

Source

pub fn equality_indexes(&self) -> Result<Vec<(String, String)>>

Every declared index, as (collection, field) in a stable order.

Source

pub fn rebuild_equality_indexes(&self) -> Result<EqualityIndexStats>

Re-derive every declared index from authoritative records.

This is the recovery path. An index is never read from disk and never received from a peer: after a restart, a snapshot install, or any other reload of authoritative state, the index is whatever this produces.

Source

pub fn equality_index_stats(&self) -> Result<EqualityIndexStats>

Index size, as counts. Never a value, never a record id.

Source

pub fn verify_equality_index(&self) -> Result<Result<(), String>>

The index invariant: the live index equals one derived from records now.

Returns a description of the first divergence rather than a bare bool, so a failing assertion says what diverged. This is the strongest statement available about index maintenance, because it compares the maintained structure against the authoritative state it claims to describe rather than against a second copy of its own bookkeeping.

Source

pub fn equality_index_candidates( &self, collection: &str, field: &str, value: &Value, ) -> Result<Option<Vec<String>>>

Candidate record keys for one equality condition, copied out of the index.

None means the index cannot answer that condition — the field is not indexed, or the value is not an indexable scalar — and the caller must fall back to a scan. Some(empty) is an answer, not a failure.

The keys are copied while the state lock is held. Nothing borrowed from the index or from the record map escapes this call.

Source

pub fn query_collection_by_equality<F>( &self, capability: &str, equalities: &[(&str, &Value)], predicate: F, ) -> Result<Option<Vec<StoredRow>>>
where F: FnMut(&StoredRow) -> bool,

Execute a bounded query through the equality index when one applies.

equalities are the query’s equality conditions, in the caller’s order. At least one of them must be indexed and hold an indexable value, or this returns Ok(None) and the caller falls back to FeltDb::query_collection. Returning None rather than an empty result is the difference between “the index does not apply” and “nothing matches”, and conflating the two would silently drop records.

When the index does apply, every applicable condition contributes a candidate set and the sets are intersected smallest-first. The result is still only candidates: predicate — the caller’s existing, unmodified predicate — decides what matches, evaluated against authoritative records. The index therefore cannot change what a query returns, only how many records the predicate has to look at.

Candidate keys, the record lookups they drive and the predicate all run under one acquisition of the state lock, so a query observes one coherent committed state exactly as a scan does. Records are cloned only when the predicate keeps them, and nothing borrowed from state outlives the lock.

Source

pub fn list_collection_page( &self, capability: &str, after: Option<&str>, limit: usize, ) -> Result<Vec<StoredRow>>

Traverse one collection in immutable record-key order without materializing it.

Source

pub fn get_collection_record( &self, capability: &str, key: &str, ) -> Result<Option<StoredRow>>

Fetch one live collection record without materializing collection state.

Source

pub fn get_collection_records<'a>( &self, capability: &str, keys: impl IntoIterator<Item = &'a str>, ) -> Result<Vec<StoredRow>>

Fetch several live collection records without materializing collection state.

Source

pub fn subscribe_changes(&self) -> Receiver<ChangeEvent>

Subscribe to canonical mutation events.

Source

pub fn add_sync_peer(&self, peer_id: String) -> Result<()>

Add a peer for synchronization

Source

pub fn remove_sync_peer(&self, peer_id: &str) -> Result<()>

Remove a peer from synchronization

Source

pub fn get_pending_for_peer( &self, _peer_id: &str, since_sequence: u64, ) -> Result<Vec<Operation>>

Get pending operations for a peer

Source

pub fn operations_since( &self, versions: &HashMap<String, u64>, ) -> Result<Vec<Operation>>

Return operations missing from a peer’s per-origin version vector.

Source

pub fn operation_versions(&self) -> Result<HashMap<String, u64>>

Return the highest durable operation sequence observed from each origin.

Source

pub fn export_snapshot(&self) -> Result<DatabaseSnapshot>

Source

pub fn state_rows(&self) -> Result<Vec<StoredRow>>

Current materialized rows including their causal operation envelopes. State-contract execution uses this for record-version preconditions; portable snapshots intentionally continue to strip those envelopes.

Source

pub fn state_rows_for_namespace( &self, state_namespace: &str, ) -> Result<Vec<StoredRow>>

Materialized rows belonging to one application state namespace.

State-contract capabilities are encoded as <state namespace>:<collection>. Selecting the capability buckets before cloning prevents one application’s read snapshot from materializing every other application’s durable rows.

Source

pub fn can_install_snapshot(&self) -> Result<bool>

Source

pub fn install_snapshot(&self, snapshot: DatabaseSnapshot) -> Result<()>

Install a verified bootstrap snapshot into a pristine node. A node with local history must converge through operations rather than overwrite it.

Source

pub fn acknowledge_peer_operations( &self, peer_id: String, sequence: u64, ) -> Result<()>

Acknowledge receipt of operations from a peer

Source

pub fn acknowledge_peer_versions( &self, peer_id: String, versions: HashMap<String, u64>, ) -> Result<()>

Durably record a peer’s per-origin acknowledgement vector.

Source

pub fn acknowledged_peer_versions( &self, peer_id: &str, ) -> Result<HashMap<String, u64>>

Source

pub fn recent_transactions( &self, limit: usize, ) -> Result<Vec<TransactionAttribution>>

Earliest operation still available for incremental replay, by origin. Recent commits and who made them, newest first.

Bounded by [TRANSACTION_ATTRIBUTION_WINDOW]. A transaction older than the window is not absent from history — it is in the durable log — it is simply no longer answerable from memory, and callers that present this to a human must say which of the two they are showing.

Source

pub fn transaction_attribution( &self, transaction_id: &str, ) -> Result<Option<TransactionAttribution>>

One transaction’s durable attribution, regardless of the operator window. This lookup is canonical historical provenance.

Source

pub fn committed_transactions_after( &self, commit_revision: u64, limit: usize, ) -> Result<Vec<TransactionAttribution>>

Canonical commit history in authority order, suitable for resumable event projection and historical provenance reconstruction.

Source

pub fn transactions_touching( &self, capability: &str, key: &str, limit: usize, ) -> Result<Vec<TransactionAttribution>>

Durable commits that named this record, newest first.

This deliberately reads complete canonical history rather than the bounded operator window. Historical provenance must not disappear when a cache rolls over.

Source

pub fn transaction_attribution_window(&self) -> Result<(usize, usize)>

How much of the attribution window is in use, and what it can hold.

Reported so a reader can tell an idle system from a window that has already rolled over.

Source

pub fn retained_operation_floors(&self) -> Result<HashMap<String, u64>>

Source

pub fn acknowledged_operation_count( &self, active_peers: &[String], ) -> Result<usize>

Source

pub fn compact_operation_log(&self, active_peers: &[String]) -> Result<usize>

Atomically replace acknowledged history with a state snapshot and any operations still needed by at least one configured peer.

Source

pub fn maybe_compact_operation_log( &self, active_peers: &[String], ) -> Result<CompactionOutcome>

Compact under the database’s CompactionPolicy.

Prunes acknowledged operations from memory whenever it can, and rewrites the durable log only when enough has accumulated to justify the stall. Use this on a timer; use compact_operation_log when a caller is explicitly asking for a rewrite now.

The distinction is the whole point. Pruning is cheap and in memory. Rewriting serializes every row in the database and fsyncs it while holding the one lock that serializes every read and every write, so doing it on a short timer stops the world on that timer.

Source

pub fn compaction_policy(&self) -> CompactionPolicy

The policy deciding when a timer-driven compaction rewrites the log.

Source

pub fn set_compaction_policy(&self, policy: CompactionPolicy)

Set the policy deciding when a timer-driven compaction rewrites the log.

Source

pub fn register_peer(&self, advertisement: PeerAdvertisement) -> Result<()>

Register a peer in the distributed fabric

Source

pub fn get_peer(&self, peer_id: &PeerId) -> Result<Option<PeerAdvertisement>>

Get a peer’s advertisement

Source

pub fn peers_for_namespace( &self, namespace: &str, ) -> Result<Vec<PeerAdvertisement>>

Find all peers providing a namespace

Source

pub fn peers_for_capability( &self, capability: &str, ) -> Result<Vec<PeerAdvertisement>>

Find all peers providing a capability

Source

pub fn all_peers(&self) -> Result<Vec<PeerAdvertisement>>

Get all registered peers

Source

pub fn resolve_ref<T: DeserializeOwned>( &self, flow_ref: &FlowRef, ) -> Result<Option<T>>

Resolve a FlowRef locally

Source

pub fn sync_state(&self) -> Result<SyncState>

Get current sync state

Source

pub fn apply_remote_operation(&self, op: Operation) -> Result<()>

Apply an operation from a remote peer This merges the vector clock, resolves conflicts, and applies the mutation

Source

pub fn get_vector_clock(&self) -> Result<Option<HashMap<String, u64>>>

Get the current vector clock state

Trait Implementations§

Source§

impl Clone for FeltDb

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V