pub trait Storage: Send + Debug {
// Required methods
fn get(&self, key: &[u8]) -> Option<Bytes>;
fn insert(&self, key: &[u8], value: Bytes, origin: Origin) -> Insertion;
fn replace(&self, key: &[u8], value: Bytes, origin: Origin) -> Insertion;
fn scan(&self, visit: &mut dyn FnMut(&[u8], &[u8]));
fn purge(&self);
fn purge_key(&self, key: &[u8]);
fn describe(&self) -> String;
// Provided methods
fn insert_many(
&self,
entries: &mut dyn Iterator<Item = (Bytes, Bytes)>,
origin: Origin,
) -> InsertSummary { ... }
fn loading(&self) -> bool { ... }
}Expand description
Where the entries of a single namespace are kept, and written to.
A storage is bound to one namespace at construction (a /-separated name
such as autotune/0.11.0/cuda-0/matmul) and addresses entries by their
serialized key bytes.
This is the only thing read at runtime. Bundles are an import format: they
fill a storage once through crate::bundle::import and are never
consulted again.
§Contract
insertis insert-only between twoOrigin::Localvalues: it leaves the stored value untouched and reportsInsertion::Conflictwith it.- A
Origin::Localvalue replaces anOrigin::Importedone, so a stale bundle entry can never wedge the application that imported it. AnOrigin::Importedvalue never replaces anything. replaceignores both rules. It exists for one caller: repairing a row whose bytes no longer decode, which noinsertcould ever agree with.purgeandpurge_keyare the deletions: the whole namespace, or one entry. Everything else is insert-only.- The check and the write must be atomic with respect to other processes.
- A read that fails reports a miss: a cache entry we can’t read is one we
recompute. A write that fails reports
Insertion::Failedrather than passing for success, so a caller can tell “someone else got there first” from “the write did not happen”. Implementations log failures but never panic on them. scanmay run the visitor while holding the backend’s lock, and several namespaces of one environment share that lock. The visitor must therefore not touch any other store of the same environment: doing so deadlocks.
Methods take &self because reads happen behind shared references on the
hot path; implementations use interior mutability.
Required Methods§
Sourcefn insert(&self, key: &[u8], value: Bytes, origin: Origin) -> Insertion
fn insert(&self, key: &[u8], value: Bytes, origin: Origin) -> Insertion
Stores value under key. See the trait contract for when the write
is declined.
Sourcefn replace(&self, key: &[u8], value: Bytes, origin: Origin) -> Insertion
fn replace(&self, key: &[u8], value: Bytes, origin: Origin) -> Insertion
Stores value under key, overwriting whatever is there.
Bypasses the insert-only rule, so it never reports a conflict. Only for
repairing an entry that can’t be decoded; ordinary writes go through
insert.
Sourcefn scan(&self, visit: &mut dyn FnMut(&[u8], &[u8]))
fn scan(&self, visit: &mut dyn FnMut(&[u8], &[u8]))
Visits every entry of the namespace.
The visitor must not read or write another store of the same environment; see the trait contract.
Sourcefn purge(&self)
fn purge(&self)
Deletes every entry of the namespace, durably.
A failed delete is logged, not reported: the entries were expendable cache content either way, and whatever survives is arbitrated like any other pre-existing entry.
Provided Methods§
Sourcefn insert_many(
&self,
entries: &mut dyn Iterator<Item = (Bytes, Bytes)>,
origin: Origin,
) -> InsertSummary
fn insert_many( &self, entries: &mut dyn Iterator<Item = (Bytes, Bytes)>, origin: Origin, ) -> InsertSummary
Stores many entries under the same rules as
insert.
Backends that can commit a batch atomically override this; the default
is one insert per entry.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".