pub struct EntityCache { /* private fields */ }Expand description
Entity cache that maintains full projected entities with LRU eviction.
The cache is populated as mutations flow through the projector, regardless of subscriber state. When a new subscriber connects, they receive snapshots of all cached entities for their requested view.
§Only whole entities
Source mutations carry only the fields that changed. A patch for a key a view holds merges into the whole entity. A patch for a key it does not hold is stored only if it is the whole entity: storing a few changed fields would serve them as though they were the entity, in snapshots and in every derived view.
A VM linked through crate::EntityResync marks the mutation that creates
each entity (PatchOrigin::Creation), which is stored as-is. Any other
patch from it for a key a view does not hold (PatchOrigin::Change) is
refused with CacheWrite::Refused — whether the view evicted the key or
never held it, as after a restore. The projector then asks the VM for the
whole entity, which follows in the VM’s next batch and is stored with
EntityCache::store_whole. That holds however many entities the VM
keeps and however long ago the view evicted the key.
A source that marks nothing (PatchOrigin::Unknown) leaves a new key and
an evicted one looking alike. Each view therefore remembers the keys it
evicted (bounded, most recent first) and refuses patches for them; a key
evicted so long ago that it has been forgotten is taken for new. A source
delete also ends an eviction.
Implementations§
Source§impl EntityCache
impl EntityCache
Sourcepub fn with_config(config: EntityCacheConfig) -> Self
pub fn with_config(config: EntityCacheConfig) -> Self
Create a new entity cache with custom configuration
Sourcepub fn max_entities_per_view(&self) -> usize
pub fn max_entities_per_view(&self) -> usize
Maximum number of entities cached per view.
Derived sorted view caches are bounded by the same value so they never hold more entities than their source view caches.
Sourcepub async fn upsert(&self, view_id: &str, key: &str, patch: Value) -> CacheWrite
pub async fn upsert(&self, view_id: &str, key: &str, patch: Value) -> CacheWrite
Write a patch from a source that does not mark creations
(PatchOrigin::Unknown).
Sourcepub async fn upsert_with_append(
&self,
view_id: &str,
key: &str,
patch: Value,
append_paths: &[String],
origin: PatchOrigin,
) -> CacheWrite
pub async fn upsert_with_append( &self, view_id: &str, key: &str, patch: Value, append_paths: &[String], origin: PatchOrigin, ) -> CacheWrite
Merge patch into the cached entity, store it as a new entity, or
refuse it as part of an entity the cache does not hold (see the type
docs).
Sourcepub async fn upsert_with_lifetime(
&self,
view_id: &str,
key: &str,
patch: Value,
append_paths: &[String],
origin: PatchOrigin,
account_position: Option<AccountPosition>,
) -> CacheWrite
pub async fn upsert_with_lifetime( &self, view_id: &str, key: &str, patch: Value, append_paths: &[String], origin: PatchOrigin, account_position: Option<AccountPosition>, ) -> CacheWrite
Apply a projected patch with optional authoritative account ordering.
_seq is consulted for lifetime changes only when no account position
exists; the two ordering domains are never compared.
Sourcepub async fn upsert_with_ordering(
&self,
view_id: &str,
key: &str,
patch: Value,
append_paths: &[String],
origin: PatchOrigin,
ordering: LifetimeOrdering<'_>,
) -> CacheWrite
pub async fn upsert_with_ordering( &self, view_id: &str, key: &str, patch: Value, append_paths: &[String], origin: PatchOrigin, ordering: LifetimeOrdering<'_>, ) -> CacheWrite
Apply a projected patch with both ordering domains supplied
explicitly. Projections may omit _seq, so the projector passes its
source cursor separately here.
Sourcepub async fn store_whole(&self, view_id: &str, key: &str, entity: Value) -> bool
pub async fn store_whole(&self, view_id: &str, key: &str, entity: Value) -> bool
Store entity as the whole entity for key, replacing anything held
and clearing an eviction: the source vouched for it being complete
(see arete_interpreter::Mutation::mark_whole_entity).
Sourcepub async fn store_whole_for_lifetime(
&self,
view_id: &str,
key: &str,
entity: Value,
requested_account_position: Option<AccountPosition>,
) -> bool
pub async fn store_whole_for_lifetime( &self, view_id: &str, key: &str, entity: Value, requested_account_position: Option<AccountPosition>, ) -> bool
Store a requested whole entity only if the request was made for the account lifetime that is still current.
pub async fn store_whole_for_ordering( &self, view_id: &str, key: &str, entity: Value, requested_account_position: Option<AccountPosition>, requested_source_seq: Option<&str>, ) -> bool
pub async fn store_whole_for_ordering_in_domain( &self, view_id: &str, key: &str, entity: Value, requested_account_position: Option<AccountPosition>, requested_source_seq: Option<&str>, requested_source_domain: SlotIndexDomain, ) -> bool
pub async fn account_position( &self, view_id: &str, key: &str, ) -> Option<AccountPosition>
pub async fn accepts_mutation( &self, view_id: &str, key: &str, _entity: &Value, creation: bool, ) -> bool
pub async fn accepts_lifetime_mutation( &self, view_id: &str, key: &str, creation: bool, account_position: Option<AccountPosition>, ) -> bool
pub async fn accepts_ordered_lifetime_mutation( &self, view_id: &str, key: &str, creation: bool, account_position: Option<AccountPosition>, source_seq: Option<&str>, ) -> bool
pub async fn accepts_ordered_lifetime_mutation_in_domain( &self, view_id: &str, key: &str, creation: bool, account_position: Option<AccountPosition>, source_seq: Option<&str>, source_domain: SlotIndexDomain, ) -> bool
Sourcepub async fn delete(
&self,
view_id: &str,
key: &str,
account_position: Option<AccountPosition>,
) -> bool
pub async fn delete( &self, view_id: &str, key: &str, account_position: Option<AccountPosition>, ) -> bool
Apply an ordered source deletion. A delayed deletion never removes a newer recreation. Only a newer, explicitly marked creation can restart a deleted row; sparse patches and resends cannot resurrect it.
Sourcepub async fn delete_current(&self, view_id: &str, key: &str) -> bool
pub async fn delete_current(&self, view_id: &str, key: &str) -> bool
Delete the lifetime currently held by the cache when the producer has
no cursor to attach. This is an explicit, trusted operation: callers
with ordering evidence must use Self::delete_ordered instead.
Sourcepub async fn delete_ordered(
&self,
view_id: &str,
key: &str,
account_position: Option<AccountPosition>,
source_seq: Option<&str>,
) -> bool
pub async fn delete_ordered( &self, view_id: &str, key: &str, account_position: Option<AccountPosition>, source_seq: Option<&str>, ) -> bool
Delete using the producer’s own _seq ordering only when no
authoritative account position is present.
pub async fn delete_ordered_in_domain( &self, view_id: &str, key: &str, account_position: Option<AccountPosition>, source_seq: Option<&str>, source_domain: SlotIndexDomain, ) -> bool
pub async fn dump_lifetimes(&self) -> EntityLifetimes
pub async fn hydrate_lifetimes(&self, lifetimes: EntityLifetimes)
Sourcepub async fn hydrate_legacy_tombstones(&self, tombstones: EntityTombstones)
pub async fn hydrate_legacy_tombstones(&self, tombstones: EntityTombstones)
Restore the old _seq barriers as account positions. Those barriers
were written only by authoritative account deletion/recreation paths;
whether the row exists distinguishes a live recreation from deletion.
Sourcepub async fn deletion_is_current(&self, view_id: &str, key: &str) -> bool
pub async fn deletion_is_current(&self, view_id: &str, key: &str) -> bool
Whether the shared cache says a published delete still represents the latest lifetime. Subscription tasks use this without mutating the cache a second time after the projector has already applied the delete.
Sourcepub fn merge_patch(
&self,
base: &mut Value,
patch: Value,
append_paths: &[String],
)
pub fn merge_patch( &self, base: &mut Value, patch: Value, append_paths: &[String], )
Merge a source patch into base with this cache’s append and array
rules, for callers that keep their own full copy of an entity.
Self::merge_patch for a SharedEntity: copies its fields first
if another holder shares them, so the merge never reaches that holder.
Sourcepub async fn remember_evicted(
&self,
view_id: &str,
keys: impl IntoIterator<Item = String>,
)
pub async fn remember_evicted( &self, view_id: &str, keys: impl IntoIterator<Item = String>, )
Treat keys as evicted from view_id unless the view holds them, so
patches for them from a source that does not mark creations are
refused. Used after a restore, when the VM holds entities the restored
cache does not; a VM that marks creations makes this moot, and the
view drops the memory with its first patch.
Sourcepub async fn get_all(&self, view_id: &str) -> Vec<(String, Value)>
pub async fn get_all(&self, view_id: &str) -> Vec<(String, Value)>
Get all cached entities for a view.
Returns a vector of (key, entity) pairs for sending as snapshots
to new subscribers. Each is a copy; Self::get_all_shared returns
the cached entities themselves.
Every entity cached for a view, most recently used first, sharing their fields with the cache rather than copying them.
Sourcepub async fn get_after(
&self,
view_id: &str,
cursor: &str,
limit: Option<usize>,
) -> Vec<(String, Value)>
pub async fn get_after( &self, view_id: &str, cursor: &str, limit: Option<usize>, ) -> Vec<(String, Value)>
Get entities with _seq greater than the provided cursor.
Returns entities that have been updated after the given cursor, sorted by _seq in ascending order. Useful for resuming from a specific point in the stream.
Sourcepub async fn get(&self, view_id: &str, key: &str) -> Option<Value>
pub async fn get(&self, view_id: &str, key: &str) -> Option<Value>
Get a copy of a specific entity from the cache.
A specific cached entity, sharing its fields with the cache rather than copying them.
Sourcepub async fn remove(&self, view_id: &str, key: &str) -> Option<Value>
pub async fn remove(&self, view_id: &str, key: &str) -> Option<Value>
Remove one entity after a source-wide delete.
The delete ends the entity, so the key is also forgotten as evicted: a later patch for it creates a new entity.
Sourcepub fn snapshot_config(&self) -> SnapshotBatchConfig
pub fn snapshot_config(&self) -> SnapshotBatchConfig
Get the snapshot batch configuration
pub async fn clear_all(&self)
Sourcepub async fn dump(&self) -> Vec<(String, Vec<(String, Value)>)>
pub async fn dump(&self) -> Vec<(String, Vec<(String, Value)>)>
Dump every view’s entities for a state snapshot.
Entries are ordered most-recently-used first; Self::hydrate relies
on that to reconstruct LRU eviction order. Each is a copy;
Self::dump_shared returns the cached entities themselves.
Self::dump, sharing the entities’ fields with the cache rather
than copying them. They serialize exactly as the copies would.
Sourcepub async fn hydrate(&self, views: Vec<(String, Vec<(String, Value)>)>)
pub async fn hydrate(&self, views: Vec<(String, Vec<(String, Value)>)>)
Restore entities dumped by Self::dump, preserving LRU order.
Entities are inserted as-is (no merge): a snapshot holds fully
projected entities, not patches. A snapshot saves each view’s copy of
an entity on its own, so views of one export ({export}/{mode}) whose
copies have the same fields (all but _version) share them again, as
they did when saved. Only copies of one export are compared.