pub trait Store: Resolver + Sealed {
Show 29 methods
// Required methods
fn put_descriptor(&self, bytes: &[u8]) -> Result<String>;
fn put_receipt(&self, bytes: &[u8]) -> Result<String>;
fn put_blob(&self, bytes: &[u8]) -> Result<String>;
fn blob(&self, sha256: &str) -> Result<Option<Cow<'_, [u8]>>>;
fn put_version(
&self,
cell_id: &str,
tx: &str,
receipt_hash: &str,
) -> Result<()>;
fn version_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>;
fn versions(
&self,
cell_id: &str,
from: &str,
to: &str,
) -> Result<Vec<Version>>;
fn latest(&self, cell_id: &str) -> Result<Option<Version>>;
fn dependents(&self, receipt_hash: &str) -> Result<Vec<String>>;
fn inputs(&self, receipt_hash: &str) -> Result<Vec<String>>;
fn put_namespace(
&self,
host: &str,
keydoc_bytes: &[u8],
validated_at: &str,
) -> Result<()>;
fn namespace(&self, host: &str) -> Result<Option<Namespace>>;
fn bind_name(&self, fn_name: &str, fn_hash: &str, tx: &str) -> Result<()>;
fn resolve_name(&self, fn_name: &str, asof: &str) -> Result<Option<String>>;
fn resolve_binding(
&self,
fn_name: &str,
asof: &str,
) -> Result<Option<Binding>>;
fn put_computed(
&self,
cell_id: &str,
tx: &str,
receipt_hash: &str,
) -> Result<()>;
fn computed_asof(
&self,
cell_id: &str,
asof: &str,
) -> Result<Option<Version>>;
fn stored_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>;
fn cell_dependents(&self, cell_id: &str) -> Result<Vec<String>>;
fn put_manifest(&self, bytes: &[u8]) -> Result<String>;
fn member_manifests(&self, receipt_hash: &str) -> Result<Vec<String>>;
fn slice_entries(&self, receipt_hash: &str) -> Result<Vec<String>>;
fn slice_dependents(&self, entry: &str) -> Result<Vec<String>>;
fn slice_members(
&self,
slice: &Slice,
asof: &str,
) -> Result<Vec<SliceMember>>;
fn versions_between(
&self,
cell_id: &str,
from: &str,
to: &str,
asof: &str,
) -> Result<Vec<SliceMember>>;
fn slice_values(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceValue>>;
fn slice_changed_after(&self, slice: &Slice, asof: &str) -> Result<bool>;
// Provided methods
fn computed_asof_with_receipt(
&self,
cell_id: &str,
asof: &str,
) -> Result<Option<(Version, Cow<'_, [u8]>)>> { ... }
fn stored_asof_with_receipt(
&self,
cell_id: &str,
asof: &str,
) -> Result<Option<(Version, Cow<'_, [u8]>)>> { ... }
}Expand description
A Datumesh store: a Resolver that can also be written to.
Instants are SPEC 3.3 instants (YYYY-MM-DDTHH:MM:SS.ffffffZ), hashes and cell ids 64
lowercase hex digits, hosts DNS names and function names fully qualified. Every method,
read or write, refuses anything else with the core’s error code (Error::Invalid),
and reports a database failure as Error::Database (or Error::PoolTimeout): a read
answers Ok(None) / Ok(vec![]) only when the store really holds nothing.
The Resolver methods keep the core’s Option signatures: there a malformed argument
or a database failure is None (logged with tracing when it is a failure), which
verify reports as unavailable.
Only this crate implements Store (it is sealed, since 0.3.0): the store is the trust
boundary, where every receipt is verified against its host’s key document before it is
kept, and what a store answers is relied on as checked. An implementation elsewhere
could answer anything. Store stays object-safe (Arc<dyn Store + Send + Sync>). Even a complete implementation that
delegates every method to a PgStore is refused (E0277: the private supertrait is
not implemented; tests/sealed.rs checks that this is the only error):
use std::borrow::Cow;
use datumesh_core::{Cell, Scalar};
use datumesh_core::Slice;
use datumesh_store::{Binding, Namespace, PgStore, Resolver, Result, SliceMember, SliceValue, Store, Version};
struct Wrapper(PgStore);
impl Resolver for Wrapper {
fn descriptor(&self, h: &str) -> Option<Cow<'_, [u8]>> { self.0.descriptor(h) }
fn receipt(&self, h: &str) -> Option<Cow<'_, [u8]>> { self.0.receipt(h) }
fn evaluate(&self, c: &Cell, a: &str) -> Option<Scalar> { self.0.evaluate(c, a) }
fn manifest(&self, e: &str) -> Option<Cow<'_, [u8]>> { self.0.manifest(e) }
}
impl Store for Wrapper {
fn put_descriptor(&self, b: &[u8]) -> Result<String> { self.0.put_descriptor(b) }
fn put_receipt(&self, b: &[u8]) -> Result<String> { self.0.put_receipt(b) }
fn put_blob(&self, b: &[u8]) -> Result<String> { self.0.put_blob(b) }
fn blob(&self, s: &str) -> Result<Option<Cow<'_, [u8]>>> { self.0.blob(s) }
fn put_version(&self, c: &str, t: &str, r: &str) -> Result<()> { self.0.put_version(c, t, r) }
fn version_asof(&self, c: &str, a: &str) -> Result<Option<Version>> { self.0.version_asof(c, a) }
fn versions(&self, c: &str, f: &str, t: &str) -> Result<Vec<Version>> { self.0.versions(c, f, t) }
fn latest(&self, c: &str) -> Result<Option<Version>> { self.0.latest(c) }
fn dependents(&self, r: &str) -> Result<Vec<String>> { self.0.dependents(r) }
fn inputs(&self, r: &str) -> Result<Vec<String>> { self.0.inputs(r) }
fn put_namespace(&self, h: &str, k: &[u8], v: &str) -> Result<()> { self.0.put_namespace(h, k, v) }
fn namespace(&self, h: &str) -> Result<Option<Namespace>> { self.0.namespace(h) }
fn bind_name(&self, n: &str, f: &str, t: &str) -> Result<()> { self.0.bind_name(n, f, t) }
fn resolve_name(&self, n: &str, a: &str) -> Result<Option<String>> { self.0.resolve_name(n, a) }
fn resolve_binding(&self, n: &str, a: &str) -> Result<Option<Binding>> { self.0.resolve_binding(n, a) }
fn put_computed(&self, c: &str, t: &str, r: &str) -> Result<()> { self.0.put_computed(c, t, r) }
fn computed_asof(&self, c: &str, a: &str) -> Result<Option<Version>> { self.0.computed_asof(c, a) }
fn stored_asof(&self, c: &str, a: &str) -> Result<Option<Version>> { self.0.stored_asof(c, a) }
fn cell_dependents(&self, c: &str) -> Result<Vec<String>> { self.0.cell_dependents(c) }
fn put_manifest(&self, b: &[u8]) -> Result<String> { self.0.put_manifest(b) }
fn member_manifests(&self, r: &str) -> Result<Vec<String>> { self.0.member_manifests(r) }
fn slice_entries(&self, r: &str) -> Result<Vec<String>> { self.0.slice_entries(r) }
fn slice_dependents(&self, e: &str) -> Result<Vec<String>> { self.0.slice_dependents(e) }
fn slice_members(&self, s: &Slice, a: &str) -> Result<Vec<SliceMember>> { self.0.slice_members(s, a) }
fn versions_between(&self, c: &str, f: &str, t: &str, a: &str) -> Result<Vec<SliceMember>> { self.0.versions_between(c, f, t, a) }
fn slice_values(&self, s: &Slice, a: &str) -> Result<Vec<SliceValue>> { self.0.slice_values(s, a) }
fn slice_changed_after(&self, s: &Slice, a: &str) -> Result<bool> { self.0.slice_changed_after(s, a) }
}Required Methods§
Sourcefn put_descriptor(&self, bytes: &[u8]) -> Result<String>
fn put_descriptor(&self, bytes: &[u8]) -> Result<String>
Stores a descriptor (checked and canonicalised by the core); returns its function hash. Idempotent.
Sourcefn put_receipt(&self, bytes: &[u8]) -> Result<String>
fn put_receipt(&self, bytes: &[u8]) -> Result<String>
Stores a receipt that verifies (SPEC 10.1 steps 1-6) against the key document stored
for its signer host with put_namespace, in canonical form,
with an edge to each of its inputs; returns its hash. An input that is a slice entry
(slice:<slice id>:<members hash>, since 0.3.1) is recorded as such
(slice_entries); its manifest need not be stored, before or
after (it is needed only to recompute, SPEC 10.1 step 7.5). The receipt’s cell is
indexed by its typed arguments (slice_members). A receipt that does not verify
is refused with verify’s code (no key document for the host: E_KEY_UNAVAILABLE).
Idempotent: bytes whose canonical form is the stored copy return its hash without
checking the signature again (it verified when stored), even if the key has since
been revoked. Other bytes with a stored hash are verified first, then refused as
Error::Conflict.
Sourcefn put_blob(&self, bytes: &[u8]) -> Result<String>
fn put_blob(&self, bytes: &[u8]) -> Result<String>
Stores blob content; returns its SHA-256 (lowercase hex). Idempotent.
Sourcefn put_version(&self, cell_id: &str, tx: &str, receipt_hash: &str) -> Result<()>
fn put_version(&self, cell_id: &str, tx: &str, receipt_hash: &str) -> Result<()>
Appends a version: from tx on, cell_id has the value of receipt receipt_hash,
which must be stored, of that cell and at that tx. tx must be later than the cell’s
latest version (Error::NotLater).
Sourcefn version_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>
fn version_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>
The cell’s latest version with tx <= asof.
Sourcefn versions(&self, cell_id: &str, from: &str, to: &str) -> Result<Vec<Version>>
fn versions(&self, cell_id: &str, from: &str, to: &str) -> Result<Vec<Version>>
The cell’s versions with from <= tx <= to, in tx order.
Sourcefn dependents(&self, receipt_hash: &str) -> Result<Vec<String>>
fn dependents(&self, receipt_hash: &str) -> Result<Vec<String>>
The stored receipts that list receipt_hash among their inputs, by hash. Only as
an input of its own: a receipt read as a member of a slice is found through its
manifests (member_manifests, then
slice_dependents).
Sourcefn inputs(&self, receipt_hash: &str) -> Result<Vec<String>>
fn inputs(&self, receipt_hash: &str) -> Result<Vec<String>>
The inputs of a stored receipt that are receipt hashes (whether or not they are
stored). Its slice entries are slice_entries.
Sourcefn put_namespace(
&self,
host: &str,
keydoc_bytes: &[u8],
validated_at: &str,
) -> Result<()>
fn put_namespace( &self, host: &str, keydoc_bytes: &[u8], validated_at: &str, ) -> Result<()>
Records a host’s key document, checked as a 200 response for that host would be
(SPEC 9.2, 9.3), validated at validated_at. Re-validation replaces the document; a
validated_at earlier than the recorded one is Error::NotLater. Receipts already
stored are not re-checked: they verified when they were stored (and putting one again
stays idempotent).
Sourcefn bind_name(&self, fn_name: &str, fn_hash: &str, tx: &str) -> Result<()>
fn bind_name(&self, fn_name: &str, fn_hash: &str, tx: &str) -> Result<()>
Appends a binding: from tx on, the fully qualified function name fn_name means
fn_hash, whose descriptor must be stored. tx must be later than the name’s latest
binding (Error::NotLater).
Sourcefn resolve_name(&self, fn_name: &str, asof: &str) -> Result<Option<String>>
fn resolve_name(&self, fn_name: &str, asof: &str) -> Result<Option<String>>
The function hash fn_name meant as of asof: the hash of
resolve_binding’s binding.
Sourcefn resolve_binding(&self, fn_name: &str, asof: &str) -> Result<Option<Binding>>
fn resolve_binding(&self, fn_name: &str, asof: &str) -> Result<Option<Binding>>
The binding of fn_name that answers as of asof: the one with the latest tx <= asof, with its function hash and its tx, when it began; None before the first.
A name bound again to a hash it meant before (even the hash of the binding before
it) begins again: the later binding’s tx. Since 0.3.0.
Sourcefn put_computed(
&self,
cell_id: &str,
tx: &str,
receipt_hash: &str,
) -> Result<()>
fn put_computed( &self, cell_id: &str, tx: &str, receipt_hash: &str, ) -> Result<()>
Records that receipt_hash (stored, a receipt of cell_id at tx) is a computed
version of the cell. Insert-only, in any order (an older version may be added after a
newer one): tx need not be later than anything. The version’s asof is the
receipt’s. Idempotent for the same (cell_id, tx, asof, receipt_hash); another receipt
for an existing (cell_id, tx, asof) is Error::Conflict (its hash is the receipt
refused) and the stored one is kept. The receipt is checked as for
put_version: Error::NotFound when it is not stored,
Error::Mismatch when it is of another cell or at another tx. Since 0.2.0.
Sourcefn computed_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>
fn computed_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>
The computed version that answers as of asof: the one with the greatest asof <=
asof (between equal asof, the greatest tx), or None. Since 0.2.0.
Sourcefn stored_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>
fn stored_asof(&self, cell_id: &str, asof: &str) -> Result<Option<Version>>
The stored version that answers as of asof: the latest version (by tx) with tx <= asof whose receipt’s asof is also <= asof, or None. A version whose receipt is
late-signed (asof later than tx) answers only from its asof on; until then the
version before it answers. (version_asof keeps its tx-only
meaning.) Since 0.2.0.
Sourcefn cell_dependents(&self, cell_id: &str) -> Result<Vec<String>>
fn cell_dependents(&self, cell_id: &str) -> Result<Vec<String>>
The cells that read cell_id: the cell ids of the stored receipts that list, among
their inputs, any stored receipt of cell_id (lineage: edges joined to receipts),
or (since 0.3.1) a slice entry whose stored manifest lists one as a member.
Ascending, each once. Since 0.2.0.
Sourcefn put_manifest(&self, bytes: &[u8]) -> Result<String>
fn put_manifest(&self, bytes: &[u8]) -> Result<String>
Stores a manifest (SPEC 15.13), {"members": [...], "slice": {...}}: parsed strictly
and checked by the core (Manifest::from_json: structure, members, their order and
limit, the slice object), kept in canonical form under its entry
slice:<slice id>:<members hash>, which it returns, and recorded for each member
(member_manifests). The members need not be stored.
Idempotent; insert-only (the entry is a hash of the content, so a stored entry
always has these bytes). Served by manifest. Since 0.3.1.
Sourcefn member_manifests(&self, receipt_hash: &str) -> Result<Vec<String>>
fn member_manifests(&self, receipt_hash: &str) -> Result<Vec<String>>
The entries of the stored manifests that list receipt_hash among their members,
ascending: from a member, the slices it was read in (then
slice_dependents). Since 0.3.1.
Sourcefn slice_entries(&self, receipt_hash: &str) -> Result<Vec<String>>
fn slice_entries(&self, receipt_hash: &str) -> Result<Vec<String>>
The slice entries among the inputs of a stored receipt, ascending. Since 0.3.1.
Sourcefn slice_dependents(&self, entry: &str) -> Result<Vec<String>>
fn slice_dependents(&self, entry: &str) -> Result<Vec<String>>
The stored receipts whose inputs list the slice entry entry, by hash, ascending.
An entry is slice: and two 64-digit hashes (E_CANON_HEX otherwise). Since 0.3.1.
Sourcefn slice_members(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceMember>>
fn slice_members(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceMember>>
The members of slice as of asof (SPEC 15.13), with the stored version of each
that answers as of asof and its receipt’s bytes.
For a slice of cells: the cells of the slice’s function (its fn_hash, ns and
fn, with the same argument names) whose bound arguments are the same typed scalar,
whose ranged arguments are of the range’s type and within it (lo <= v <= hi,
inclusive, in the type’s order: numbers as exact decimals, dates and instants
chronologically, strings by code point; lo after hi is empty), any value for an
open argument, and that have a stored version answering as of asof: as
stored_asof, the latest version with tx <= asof whose
receipt’s asof <= asof (so a late-signed version is not a member’s answer before
its asof, and a correction replaces a member’s version from its asof on). Computed
versions are not members. In key order: by the open and ranged arguments in
ascending name order, each in its type’s order (false before true; blobs as
text); the cell id last, for two cells whose key arguments are of different types.
For a version slice {"cell", "from", "to"}: versions_between
of its cell. Empty when nothing matches. Since 0.3.1.
Sourcefn versions_between(
&self,
cell_id: &str,
from: &str,
to: &str,
asof: &str,
) -> Result<Vec<SliceMember>>
fn versions_between( &self, cell_id: &str, from: &str, to: &str, asof: &str, ) -> Result<Vec<SliceMember>>
The stored versions of cell_id with from <= tx <= to that answer as of asof
(tx <= asof and the receipt’s asof <= asof), ascending by tx, each with its
receipt’s bytes: SPEC 15.13’s version slice. Empty when from is after to. Since
0.3.1.
Sourcefn slice_values(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceValue>>
fn slice_values(&self, slice: &Slice, asof: &str) -> Result<Vec<SliceValue>>
The members slice_members gives, in its order and by its
answering rule, each as its version, its receipt’s typed value and its cell (with its
arguments), without the receipt’s bytes (the value is a stored column of the receipt
and the cell comes from the typed-argument index, neither parsed per call).
Since 0.3.2.
Sourcefn slice_changed_after(&self, slice: &Slice, asof: &str) -> Result<bool>
fn slice_changed_after(&self, slice: &Slice, asof: &str) -> Result<bool>
Whether the members of slice, or their versions, may answer differently as of some
time after asof: whether a cell matching the slice has a stored version whose
receipt’s asof is after asof (its tx is never later than that), for a version
slice one with tx in [from, to]. false means slice_members
(and slice_values) give the same answer as of every time from asof on, until a
version is stored with an asof after it; true may be conservative (a late-signed
version superseded before its asof never answers). Index scans only, whatever the
slice’s size: two bounded probes (at most 10,001 entries each) choose whether to walk
the function’s receipts with an asof after asof or the slice’s candidate cells,
whichever is fewer, and one query walks it, stopping at the first match. Since 0.3.2.
Provided Methods§
Sourcefn computed_asof_with_receipt(
&self,
cell_id: &str,
asof: &str,
) -> Result<Option<(Version, Cow<'_, [u8]>)>>
fn computed_asof_with_receipt( &self, cell_id: &str, asof: &str, ) -> Result<Option<(Version, Cow<'_, [u8]>)>>
computed_asof and the bytes of the version’s receipt (as
receipt returns them), which is what a caller reads next.
The default asks for the two in turn (a receipt that cannot be read then is
Error::NotFound); PgStore answers both with one query. Since 0.2.0.
Sourcefn stored_asof_with_receipt(
&self,
cell_id: &str,
asof: &str,
) -> Result<Option<(Version, Cow<'_, [u8]>)>>
fn stored_asof_with_receipt( &self, cell_id: &str, asof: &str, ) -> Result<Option<(Version, Cow<'_, [u8]>)>>
stored_asof and the bytes of the version’s receipt, as
computed_asof_with_receipt does. Since 0.2.0.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".