pub struct PimdirStore { /* private fields */ }client only.Expand description
A pimdir store held as its owner: the write surface, over the read surface every role shares.
It carries what only an owner may do, none of which consults a
source: retention and purge, the sweep and its repairs, and the queue
rows a drain or a cancellation removes. The sync seam does consult
one, and lives on PimdirSourceStore, which
for_source yields. Reading is not an owner’s
privilege, so the reads live on PimdirReader and this handle
dereferences to one.
Implementations§
Source§impl PimdirStore
impl PimdirStore
Sourcepub fn open(dir: impl AsRef<Path>) -> Result<Self, PimdirError>
pub fn open(dir: impl AsRef<Path>) -> Result<Self, PimdirError>
Opens (creating if absent) the store rooted at dir, as its owner.
The handle takes the store’s exclusive advisory lock (spec §8) and
holds it until it drops, so a store has one owner process at a
time; one already owned elsewhere is PimdirError::Owned
immediately, never a wait. Several handles of one process share
that lock: one per source, or one per account, is still one owner.
A fresh database is created at the current schema version. A store
stamped with a higher user_version than this crate services is
refused with PimdirError::Version rather than half-read: the
spec is a draft, so such a store is recreated, never migrated.
Sourcepub fn open_with_hash(
dir: impl AsRef<Path>,
hash: Option<PimdirHashAlgo>,
) -> Result<Self, PimdirError>
pub fn open_with_hash( dir: impl AsRef<Path>, hash: Option<PimdirHashAlgo>, ) -> Result<Self, PimdirError>
Opens (creating if absent) the store rooted at dir, declaring the hash
its objects are named by (spec §5).
A store records its algorithm once, at creation, in
store_meta.hash_algo: every blob is a file named by it, so it
cannot change afterwards. hash therefore applies to a store this
call creates, and an existing store whose algorithm differs is
refused with PimdirError::HashAlgo rather than opened into a
handle that would hash bodies to names it does not use. None
adopts what the store records, creating with
PimdirHashAlgo::default.
A consumer hashes through hash or
hasher rather than choosing an algorithm of its
own, which is what keeps two implementations of one store naming
the same body the same way.
Sourcepub fn open_read_only(dir: impl AsRef<Path>) -> Result<Self, PimdirError>
👎Deprecated since 0.3.0: use PimdirReader::open, which carries the reads and no write at all
pub fn open_read_only(dir: impl AsRef<Path>) -> Result<Self, PimdirError>
use PimdirReader::open, which carries the reads and no write at all
Opens an existing store rooted at dir read-only.
The database is opened with SQLITE_OPEN_READ_ONLY: nothing is
created, so a missing database errors, one no owner has stamped
yet is PimdirError::Uncreated, and any other schema version is
refused with PimdirError::Version. The returned handle exposes
the full read surface; any write through it fails at the SQLite
layer.
A reader owns nothing and takes no lock: any number of them may run against a store an owner holds.
Sourcepub fn for_account(self, account: impl Into<String>) -> Self
pub fn for_account(self, account: impl Into<String>) -> Self
Binds this handle to an account, so every collection it creates is grouped under it (spec §9.2).
A single-account store never calls this and its collections carry
a NULL account, which is what every by-account read matches when
given None. A multi-account owner opens one handle per account,
the way it already opens one per source; §8’s single-owner rule is
unchanged by how many a process holds.
The account groups and nothing more: it partitions no identifier,
so two accounts holding one link id still share a seq, and one
body reaching both is still stored once. Where an identity or a
body occurs is reported by
link_placements and
object_placements.
Sourcepub fn account(&self) -> Option<&str>
pub fn account(&self) -> Option<&str>
The account this handle writes under, None in a single-account store.
Sourcepub fn for_source(self, source: impl Into<String>) -> PimdirSourceStore
pub fn for_source(self, source: impl Into<String>) -> PimdirSourceStore
Binds this handle to a source, yielding the sync seam: load projects
the hub for that side and write folds its decisions back.
A source is a side this store syncs with ("left", "right",
"phone", …), so it is only ever named by an operation acting as
one. Everything else, the reads, retention and the queue, stays on
the source-less handle and is still reachable through this one.
Sourcepub fn load_hub(&self, collection: &str) -> Result<ReplicaHub, PimdirError>
pub fn load_hub(&self, collection: &str) -> Result<ReplicaHub, PimdirError>
Loads a collection’s full ReplicaHub: every source’s items and
bindings, not only this handle’s source.
load projects the hub for one source; a
multi-source consumer reads the whole hub to project each side and
to spot items held by a single source.
Sourcepub fn ensure_collection(
&self,
collection: &str,
kind: &str,
) -> Result<(), PimdirError>
pub fn ensure_collection( &self, collection: &str, kind: &str, ) -> Result<(), PimdirError>
Declares a collection’s media type (kind), creating the collection if
absent and updating its kind otherwise.
The kind is an IANA media
type
(message/rfc822, text/vcard, text/calendar, …), static
consumer configuration rather than something the sync engine
derives, so a consumer sets it out of band from the
ReplicaStorage seam. That is what makes the store
self-describing (§4.3) and lets one store hold several kinds. The
lazy creation inside write uses
ON CONFLICT DO NOTHING, so it never clobbers a kind set here.
The collection is grouped under this handle’s account
(for_account); an existing row keeps the
account it had, and only the kind is updated.
Sourcepub fn set_collection_account(
&self,
collection: &str,
account: Option<&str>,
) -> Result<(), PimdirError>
pub fn set_collection_account( &self, collection: &str, account: Option<&str>, ) -> Result<(), PimdirError>
Regroups a collection under account, or out of one with None.
Safe at any time: the account partitions no identifier (spec §9.2), so
the move leaves the collection’s seqs, link ids and objects alone.
Sourcepub fn set_sort_key(
&self,
collection: &str,
link_id: &str,
sort_key: &str,
) -> Result<(), PimdirError>
pub fn set_sort_key( &self, collection: &str, link_id: &str, sort_key: &str, ) -> Result<(), PimdirError>
Restates one item’s ordering key (spec §9.3).
For a re-projection: a store written before its kind had a
sort-key convention, one whose convention changed, or a consumer
deriving the key from the meta it wrote itself. Not part of the
ordinary write path, which preserves a key by never naming it.
Sourcepub fn rename_collection(
&self,
collection: &str,
new_id: &str,
) -> Result<(), PimdirError>
pub fn rename_collection( &self, collection: &str, new_id: &str, ) -> Result<(), PimdirError>
Gives a collection a new id, carrying its whole contents with it.
Every foreign key onto collections(id) is ON UPDATE CASCADE,
so the items, bindings, sources, queue rows and child collections
follow in the same statement (spec §14). This is the only safe way
to change an id: recreating the collection under the new one takes
every item and binding with it through ON DELETE CASCADE,
turning a rename into a full re-download and discarding any staged
local change.
Two things make an id change: a server renaming the collection, and an owner renaming an account whose id it namespaced its collection ids with. An account rename is one call per collection; run them in one transaction and the account moves atomically.
Source§impl PimdirStore
The retention surface (spec §11): the trash a store keeps instead of
losing items, and the only operations that truly destroy one.
impl PimdirStore
The retention surface (spec §11): the trash a store keeps instead of losing items, and the only operations that truly destroy one.
An item whose last source binding vanished is retained, not deleted:
hidden from the sync seam and from the live client reads, but kept
whole, body included. It comes back by revival, its link id
reappearing from a source or a client add, or not at all until a
purge reclaims it. Retention is unconditional; when to reclaim is the
owner’s schedule, which is why every purge takes its boundary from the
caller.
Sourcepub fn purge(
&mut self,
collection: &ReplicaCollectionId,
seq: i64,
) -> Result<bool, PimdirError>
pub fn purge( &mut self, collection: &ReplicaCollectionId, seq: i64, ) -> Result<bool, PimdirError>
Purges one retained item by its public id, returning whether there was one to purge.
The row goes, its bindings cascade, and the body it released is unlinked by the ordinary sweep once nothing else references it: a purge collects nothing itself. A live item is never reached, the statement being guarded on the retention stamp, so an operator emptying the trash cannot destroy synced data.
Sourcepub fn purge_retained_before(
&mut self,
cutoff: &str,
) -> Result<PimdirPurgeReport, PimdirError>
pub fn purge_retained_before( &mut self, cutoff: &str, ) -> Result<PimdirPurgeReport, PimdirError>
The scheduled sweep: purges every item retired strictly before
cutoff (RFC 3339), store-wide, reporting how many it retired.
The boundary is the caller’s, not the store’s clock: an owner
computes it from its own retention duration, so the store holds no
policy and the sweep stays deterministic. An item retained exactly
at cutoff is kept, and a cutoff of now reproduces the
terminal-delete behaviour of a store that never retained, which is
why there is no on/off switch.
Source§impl PimdirStore
Reclamation and repair (spec §5, §7): the two things a store does not
do to itself.
impl PimdirStore
Reclamation and repair (spec §5, §7): the two things a store does not do to itself.
No write collects. An object at refcount zero is unreferenced rather than deleted, and stays until a collector runs, which is what lets a consumer store a body in one batch and attach it in a later one (spec §14). Repair is the other half: a refcount is maintained incrementally, so recomputing it from the pointers that justify it is how a drift is settled rather than reported for ever.
Sourcepub fn collect_garbage(&mut self) -> Result<PimdirGcReport, PimdirError>
pub fn collect_garbage(&mut self) -> Result<PimdirGcReport, PimdirError>
Reclaims what nothing references: the object rows at refcount zero, the bodies they held, and any orphan blob a crash left behind.
Takes the store’s staging lock exclusively, so no producer is between a blob write and the queue row that pins it, and runs on an owning handle, which already holds the store against other owners. Those two let the sweep take a body the moment nothing references it, with no grace window standing in for a lock.
The rows go inside a transaction and the files after it, in the order a crash can afford: a body without its row is an orphan the next collection takes, where a row without its body fails a read.
Sourcepub fn recompute_refcounts(&self) -> Result<usize, PimdirError>
pub fn recompute_refcounts(&self) -> Result<usize, PimdirError>
Recomputes every object’s refcount from the five columns that pin one (spec §7), returning how many rows disagreed and were corrected.
The counterpart of the incremental maintenance every write does: a count that drifted, from a bug here or a foreign writer, is otherwise reported for ever. A whole-store pass, so it belongs to a repair verb rather than to a write.
Sourcepub fn clear_dangling_bindings(&self) -> Result<usize, PimdirError>
pub fn clear_dangling_bindings(&self) -> Result<usize, PimdirError>
Deletes the bindings whose item is gone, returning how many, and leaves every other dangling row alone.
A binding with no item is unreachable: nothing reads it and no sync projects it. The other dangling rows a check reports are not like that, an item whose object row is missing being still the item and a queue row whose body is missing still an intent, so deleting them would destroy data rather than repair it.
Source§impl PimdirStore
The action-queue owner surface (spec §15) and collection generations
(spec §12): the single owning process drains producer-requested
mutations into the store, and marks a rebuild for readers.
impl PimdirStore
The action-queue owner surface (spec §15) and collection generations (spec §12): the single owning process drains producer-requested mutations into the store, and marks a rebuild for readers.
Sourcepub fn cancel_action(
dir: impl AsRef<Path>,
id: i64,
) -> Result<bool, PimdirError>
pub fn cancel_action( dir: impl AsRef<Path>, id: i64, ) -> Result<bool, PimdirError>
Cancels one queue row (spec §15.5) as the store’s owner, holding that role only for the length of the call.
Cancelling is an owner write, and it is the only retraction a
queued create has: the kinds that address an existing item are
retracted by their inverse instead, set-flags being absolute
rather than a delta. A consumer that is otherwise a reader and a
producer needs the role for this one statement, so it takes it
here rather than by holding a handle that could also drain the
queue or sweep the objects.
The store must exist: this never creates one, so a mistyped path
is PimdirError::Uncreated rather than an empty store. A store
another process owns is PimdirError::Owned at once, never a
wait, and the caller reports it as a sync being in flight: the
action is still queued, and may have been applied in the meantime.
Sourcepub fn drop_action(&mut self, id: i64) -> Result<bool, PimdirError>
pub fn drop_action(&mut self, id: i64) -> Result<bool, PimdirError>
Removes one queue row by request rather than by application, pending or parked, returning whether there was a row to remove (spec §15.5).
One verb for the two ways a row leaves the queue unapplied: a producer cancelling a queued action, and an owner acknowledging an intent it performed out of band, which the drain could only skip. The row’s body pin is released in the same transaction, so a blob nothing else references falls to the ordinary sweep.
Sourcepub fn fail_action(
&self,
id: i64,
error: Option<&str>,
) -> Result<(), PimdirError>
pub fn fail_action( &self, id: i64, error: Option<&str>, ) -> Result<(), PimdirError>
Records a failed apply an owner performed itself (spec §15.2).
None is the transient case: the attempt counter advances and the
row stays pending for the next drain. Some(error) is the
permanent one: the row parks with the failure, visible to
operators instead of blocking its collection. An unknown id is a
no-op, since the row may have been applied or cancelled meanwhile.
Methods from Deref<Target = PimdirReader>§
Sourcepub fn object_stats(&self) -> Result<PimdirObjectStats, PimdirError>
pub fn object_stats(&self) -> Result<PimdirObjectStats, PimdirError>
How many objects are indexed and what they weigh in total.
Sourcepub fn live_bytes(&self) -> Result<u64, PimdirError>
pub fn live_bytes(&self) -> Result<u64, PimdirError>
The bytes held by objects at least one live item still binds.
An object a live and a retained item share counts here, since purging the retained one would not free it.
Sourcepub fn object_size(&self, hash: &str) -> Result<Option<u64>, PimdirError>
pub fn object_size(&self, hash: &str) -> Result<Option<u64>, PimdirError>
One object’s stored size.
Sourcepub fn retained_before(&self, cutoff: &str) -> Result<(u64, u64), PimdirError>
pub fn retained_before(&self, cutoff: &str) -> Result<(u64, u64), PimdirError>
What a purge with this cutoff would retire: how many retained items, and the bytes their bodies weigh.
A preview, so a confirmation can say what is at stake; the purge itself is the authority, and the collector is what frees the bytes.
Sourcepub fn indexed_hashes(&self) -> Result<BTreeSet<String>, PimdirError>
pub fn indexed_hashes(&self) -> Result<BTreeSet<String>, PimdirError>
Every hash the index knows, to diff against the blob directory: the
index half of what PimdirBlobs::files
reads from disk.
Sourcepub fn refcount_drift(&self) -> Result<Vec<PimdirRefcountDrift>, PimdirError>
pub fn refcount_drift(&self) -> Result<Vec<PimdirRefcountDrift>, PimdirError>
The objects whose stored refcount disagrees with their references.
The expected count is exactly what the write path maintains
incrementally: an item’s body, an item’s conflict copy, each source’s
stored base, and each queue row pinning a body it enqueued.
recompute_refcounts is what
settles what this reports.
Sourcepub fn minted_keys(&self) -> Result<Vec<PimdirMinted>, PimdirError>
pub fn minted_keys(&self) -> Result<Vec<PimdirMinted>, PimdirError>
The minted keys each collection holds, where it holds any.
Not a defect and nothing to repair: two copies of one identity is redundancy, and the store holds both rather than judging them. It is reported because a collection whose count climbs every sync is a source handing over the same duplicate under a new handle each run, which an operator has no other way to see.
Sourcepub fn dangling(&self) -> Result<Vec<PimdirDangling>, PimdirError>
pub fn dangling(&self) -> Result<Vec<PimdirDangling>, PimdirError>
Every row pointing at something absent: a binding whose item is gone, an item or a queue row whose object is not indexed.
Only the first is repairable (clear_dangling_bindings);
the other two still hold data, so they are reported and left alone.
Sourcepub fn overlays_pending(&self) -> bool
pub fn overlays_pending(&self) -> bool
Whether this reader folds the pending queue over its item reads.
Sourcepub fn hash_algo(&self) -> PimdirHashAlgo
pub fn hash_algo(&self) -> PimdirHashAlgo
The hash this store names its objects by (spec §5).
Sourcepub fn blobs(&self) -> PimdirBlobs
pub fn blobs(&self) -> PimdirBlobs
A blob handle over this store’s object directory, bound to the hash the store names its bodies by.
Independent of the SQLite connection, so a body can be read while the store is mutably borrowed servicing a sync.
Sourcepub fn hash(&self, bytes: &[u8]) -> ReplicaHash
pub fn hash(&self, bytes: &[u8]) -> ReplicaHash
The content hash of a whole body, under this store’s algorithm.
Sourcepub fn hasher(&self) -> PimdirHasher
pub fn hasher(&self) -> PimdirHasher
An incremental hasher for a body streamed into the blob store
rather than held whole in memory, paired with
PimdirBlobs::writer.
Sourcepub fn collection_account(
&self,
collection: &str,
) -> Result<Option<Option<String>>, PimdirError>
pub fn collection_account( &self, collection: &str, ) -> Result<Option<Option<String>>, PimdirError>
The account a collection is grouped under.
The outer Option is whether the collection exists, the inner one
whether it is grouped: Ok(None) for an unknown collection,
Ok(Some(None)) for one in a single-account store.
Sourcepub fn collection_kind(
&self,
collection: &str,
) -> Result<Option<String>, PimdirError>
pub fn collection_kind( &self, collection: &str, ) -> Result<Option<String>, PimdirError>
The declared media type of a collection, or None if the store
has never seen it. An empty string means the collection exists but
was created lazily by a sync before any
ensure_collection declared its kind.
Sourcepub fn list_collections(&self) -> Result<Vec<PimdirCollection>, PimdirError>
pub fn list_collections(&self) -> Result<Vec<PimdirCollection>, PimdirError>
Lists every collection in the store (client read surface).
Ordered by sort_order then id, unordered collections last. A
direct getter: it observes the shared truth and never mutates, and
writes go through io-replica’s write.
Sourcepub fn list_collections_by_account(
&self,
account: Option<&str>,
) -> Result<Vec<PimdirCollection>, PimdirError>
pub fn list_collections_by_account( &self, account: Option<&str>, ) -> Result<Vec<PimdirCollection>, PimdirError>
Lists one account’s collections, the filter axis of a merged view (spec §9.2).
None selects the collections of a single-account store, matching on
IS so a NULL account matches itself; = would match nothing.
Sourcepub fn list_accounts(&self) -> Result<Vec<String>, PimdirError>
pub fn list_accounts(&self) -> Result<Vec<String>, PimdirError>
The accounts owning at least one collection.
Not a configured roster: a store learns an account only through its collections (spec §9.2), so one with none yet does not appear here and a consumer holding the real roster reads its own config.
Sourcepub fn link_placements(
&self,
link_id: &str,
) -> Result<Vec<PimdirPlacement>, PimdirError>
pub fn link_placements( &self, link_id: &str, ) -> Result<Vec<PimdirPlacement>, PimdirError>
Every live placement of one identity, with the collection and account it sits in (spec §9.2).
The store reports where a link id occurs and takes no position on whether the placements are one thing. A mail view lists them, two receipts of a newsletter having two read states; a contact view may offer to merge them. Both read these rows.
Sourcepub fn object_placements(
&self,
hash: &str,
) -> Result<Vec<PimdirPlacement>, PimdirError>
pub fn object_placements( &self, hash: &str, ) -> Result<Vec<PimdirPlacement>, PimdirError>
Every live placement of one body, by content hash: the dedup axis rather than the identity one, so it pairs placements two servers gave different link ids.
Sourcepub fn list_items(
&self,
collection: &str,
after: Option<&str>,
limit: usize,
) -> Result<Vec<PimdirItem>, PimdirError>
pub fn list_items( &self, collection: &str, after: Option<&str>, limit: usize, ) -> Result<Vec<PimdirItem>, PimdirError>
A keyset page of a collection’s live items (client read surface).
after is the exclusive lower bound on link_id, None starting
from the beginning; at most limit items come back ordered by
link_id, so the last item’s link_id is
the next page’s cursor. Tombstones are excluded, and each item
carries its level, so a body’s absence shows without probing the
blobs.
Sourcepub fn list_items_page_asc(
&self,
collection: &str,
after: Option<(&str, i64)>,
limit: usize,
) -> Result<Vec<PimdirItem>, PimdirError>
pub fn list_items_page_asc( &self, collection: &str, after: Option<(&str, i64)>, limit: usize, ) -> Result<Vec<PimdirItem>, PimdirError>
A keyset page of a collection’s live items in the kind’s own ascending order (spec §9.3): A to Z for contacts, earliest first for mail and calendars.
after is the previous page’s last (sort_key, seq), None
starting from the beginning. The pair is the cursor because a sort
key is not unique and seq, unique per collection, is what makes
the page total: no item is skipped or repeated across a boundary.
Sourcepub fn list_items_page_desc(
&self,
collection: &str,
after: Option<(&str, i64)>,
limit: usize,
) -> Result<Vec<PimdirItem>, PimdirError>
pub fn list_items_page_desc( &self, collection: &str, after: Option<(&str, i64)>, limit: usize, ) -> Result<Vec<PimdirItem>, PimdirError>
The same page descending: newest first for mail and calendars, Z to A for contacts.
None starts from the end, which the statement expresses by
binding a key above every representable one, so a caller never
invents that sentinel itself.
Sourcepub fn get_item(
&self,
collection: &str,
seq: i64,
) -> Result<Option<PimdirItem>, PimdirError>
pub fn get_item( &self, collection: &str, seq: i64, ) -> Result<Option<PimdirItem>, PimdirError>
One live item by its public id (collection, seq), or None. A
tombstoned item reads as None, and the returned item carries its
internal link_id for the caller to edit by.
Sourcepub fn seq_for_link(
&self,
collection: &str,
link_id: &str,
) -> Result<Option<i64>, PimdirError>
pub fn seq_for_link( &self, collection: &str, link_id: &str, ) -> Result<Option<i64>, PimdirError>
Resolves an item’s public id (seq) from its internal link_id,
the inverse of get_item, for a consumer that
just staged an add and wants the id it now shows under.
Sourcepub fn item_bindings(
&self,
collection: &str,
link_id: &str,
) -> Result<BTreeMap<ReplicaSourceId, ReplicaSourceBinding>, PimdirError>
pub fn item_bindings( &self, collection: &str, link_id: &str, ) -> Result<BTreeMap<ReplicaSourceId, ReplicaSourceBinding>, PimdirError>
Every source’s binding of one item, keyed by source: the handle it is bound to, the base the last sync agreed on, and the conflict its own sync is stuck on (spec §13).
The same shape a hub carries per item, read for one item rather than a collection: an operator asking why a placement stopped moving is asking about exactly these columns, and nothing else exposes them.
Sourcepub fn list_conflicts(
&self,
account: Option<&str>,
) -> Result<Vec<PimdirConflict>, PimdirError>
pub fn list_conflicts( &self, account: Option<&str>, ) -> Result<Vec<PimdirConflict>, PimdirError>
The bindings waiting for a decision, across one account’s collections, ordered by collection then link id then source.
None lists a single-account store whole, the account grouping
nothing there. Each row carries the three bodies the divergence
is between, so a resolver holding no credentials reads base,
local and remote from the store alone (spec §13).
The question a sync answers at the end of every run, and the one a listing command asks directly. Both are served by the partial index over the flag, so a store with nothing outstanding pays for an empty index rather than for a pass over every collection.
Sourcepub fn distinct_sources(&self) -> Result<Vec<String>, PimdirError>
pub fn distinct_sources(&self) -> Result<Vec<String>, PimdirError>
The distinct source names the store has synced against, across all collections. A client attributes its writes with this: a store synced as a single source has exactly one, so the app writes as it without configuration.
Sourcepub fn count_items(&self, collection: &str) -> Result<u64, PimdirError>
pub fn count_items(&self, collection: &str) -> Result<u64, PimdirError>
A collection’s live (non-tombstone) item count (client read surface).
Sourcepub fn list_retained(
&self,
collection: &ReplicaCollectionId,
after: Option<i64>,
limit: usize,
) -> Result<Vec<PimdirItem>, PimdirError>
pub fn list_retained( &self, collection: &ReplicaCollectionId, after: Option<i64>, limit: usize, ) -> Result<Vec<PimdirItem>, PimdirError>
A keyset page of a collection’s retained items.
after is the exclusive lower bound on the public seq, None
starting from the beginning; at most limit items come back
ordered by seq, so the last item’s seq is
the next page’s cursor. The only read that returns retained items:
a caller presents them as a trash view, never merged into the live
listing.
Sourcepub fn count_retained(
&self,
collection: &ReplicaCollectionId,
) -> Result<i64, PimdirError>
pub fn count_retained( &self, collection: &ReplicaCollectionId, ) -> Result<i64, PimdirError>
A collection’s retained item count, the counterpart of
count_items.
Sourcepub fn retained_bytes(&self) -> Result<u64, PimdirError>
pub fn retained_bytes(&self) -> Result<u64, PimdirError>
The bytes retention is holding across the whole store, each distinct body counted once.
An upper bound on what a purge would reclaim: a body a live item also points at keeps that reference and survives the sweep. Reported so an operator can price a retention duration.
Sourcepub fn generation(&self, collection: &str) -> Result<Option<i64>, PimdirError>
pub fn generation(&self, collection: &str) -> Result<Option<i64>, PimdirError>
A collection’s handle-space epoch (spec §12), or None when the
store has never seen it. Starts at 1, bumped only by
write_rekeyed, so a frontend
derives an IMAP UIDVALIDITY from it alone.
Sourcepub fn queued_collections(&self) -> Result<Vec<String>, PimdirError>
pub fn queued_collections(&self) -> Result<Vec<String>, PimdirError>
The collections with pending (non-parked) queue work, for the owner’s drain loop.
Sourcepub fn pending_actions(
&self,
collection: &str,
) -> Result<Vec<PimdirPendingAction>, PimdirError>
pub fn pending_actions( &self, collection: &str, ) -> Result<Vec<PimdirPendingAction>, PimdirError>
A collection’s pending (non-parked) actions in append order, decoded (spec §15.4): a frontend overlays them on its item projection for read-your-writes. An undecodable payload errors, and the owner’s next drain parks such a row.
Sourcepub fn parked_actions(&self) -> Result<Vec<PimdirParkedAction>, PimdirError>
pub fn parked_actions(&self) -> Result<Vec<PimdirParkedAction>, PimdirError>
Every parked action across the store, in append order, for status surfaces and operator repair. Parked rows are skipped by the drain and never silently deleted.
Sourcepub fn pending_creates(
&self,
collection: &str,
) -> Result<Vec<PimdirPendingAction>, PimdirError>
pub fn pending_creates( &self, collection: &str, ) -> Result<Vec<PimdirPendingAction>, PimdirError>
The queued creates targeting a collection, in append order (spec §15.4).
Reported apart from the items because a create has no public id until the owner applies it, so there is nothing to address it by and no envelope to put it in. A consumer surfaces them its own way: a count under a listing, a queue view of its own, or the operator CLI’s.
Sourcepub fn count_pending_creates(
&self,
collection: &str,
) -> Result<usize, PimdirError>
pub fn count_pending_creates( &self, collection: &str, ) -> Result<usize, PimdirError>
How many creates the collection has queued, the count a listing reports so a staged item reads as queued rather than as lost.