Skip to main content

MemStorage

Struct MemStorage 

pub struct MemStorage { /* private fields */ }
Expand description

The reference in-memory Storage backend: RwLock-guarded, copy-on-write reads.

This is the default backend, the one tests use, the one a wasm32 build uses, and — because it is the simplest thing that can uphold every invariant the seam states — the oracle the journal (M2), sqlite (M4) and remote (M5) backends are compared against through the shared conformance suite (atune_core’s conformance feature).

Send + Sync and usable from any number of threads (and from wasm32, where there is only one). Nothing is persisted: dropping the value drops the studies.

§Model

One RwLock around one struct, copy-on-write reads: every read clones the snapshot it returns, so a caller may hold a FrozenTrial for as long as it likes while other workers advance the study. Writes take the write lock, validate the whole operation before mutating anything, and then bump the study’s sequence number exactly once. That ordering is what makes write_params atomic and what makes sync observe either all of a write or none of it.

§Time

Storage never reads a clock of its own. The timestamp the trait passes in (heartbeat) is stored verbatim; the two the trait has no parameter for (created_at_millis, finished_at_millis) come from a Clock injected at construction. MemStorage::new injects a ManualClock frozen at 0, so the default backend is fully deterministic and wasm32-clean; MemStorage::with_clock takes a real one.

use atune_core::prelude::*;
use atune_core::storage::MemStorage;

let storage = MemStorage::new();
let study = storage.create_study(StudyConfig::new("demo").with_seed(7))?;
let trial = storage.create_trial(study, None)?;

assert_eq!(trial.number, TrialNumber::new(0));
assert!(storage.try_transition(trial.id, TrialState::Waiting, TrialState::Running)?);
storage.set_values(trial.id, &[0.25])?;
assert!(storage.try_transition(trial.id, TrialState::Running, TrialState::Complete)?);

let frozen = storage.get_trial(trial.id)?;
assert_eq!(frozen.objective_value(), Some(&[0.25][..]));

Implementations§

§

impl MemStorage

pub fn new() -> Self

An empty backend whose clock is frozen at 0.

Deterministic on purpose: created_at_millis and finished_at_millis are 0 for every trial unless a real clock is injected with with_clock.

pub fn with_clock(clock: Arc<dyn Clock>) -> Self

An empty backend that stamps trials from clock.

The clock is only ever consulted for the two timestamps the Storage trait has no parameter for: a trial’s creation time and its completion time. Storage::heartbeat’s timestamp always comes from the caller.

pub fn study_count(&self) -> Result<usize>

The number of studies currently stored.

§Errors

Error::Storage if the internal lock is poisoned.

pub fn trial_count(&self) -> Result<usize>

The number of trials currently stored, across all studies.

§Errors

Error::Storage if the internal lock is poisoned.

Trait Implementations§

§

impl AtomicImportStorage for MemStorage

§

fn import_batch(&self, batch: &ImportBatch) -> Result<ImportBatchResult>

Publishes one completely staged batch at one backend commit point. Read more
§

impl Debug for MemStorage

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
§

impl Default for MemStorage

§

fn default() -> Self

Returns the “default value” for a type. Read more
§

impl Storage for MemStorage

§

fn backing_paths(&self) -> Option<Vec<PathBuf>>

Local files that an exporter must never replace, including fixed sidecars. Read more
§

fn create_study(&self, cfg: StudyConfig) -> Result<StudyId>

Creates a study and returns its identity. Read more
§

fn study_config(&self, study: StudyId) -> Result<StudyConfig>

Reads a study’s configuration back. Read more
§

fn study_user_attrs(&self, study: StudyId) -> Result<UserAttrs>

Returns all user-owned JSON metadata attached to a study. Read more
§

fn set_study_user_attr( &self, study: StudyId, key: &str, value: Value, ) -> Result<()>

Inserts or replaces one study user attribute. Read more
§

fn create_trial( &self, study: StudyId, template: Option<TrialTemplate>, ) -> Result<TrialRecord>

Creates a trial, optionally pre-loaded from a template. Read more
§

fn try_transition( &self, trial: TrialId, from: TrialState, to: TrialState, ) -> Result<bool>

Atomically moves a trial from from to to. Read more
§

fn write_params( &self, trial: TrialId, batch: &[(String, Distribution, ParamValue)], ) -> Result<()>

Records sampled parameters together with the distributions they came from. Read more
§

fn report(&self, trial: TrialId, step: u64, values: &[f64]) -> Result<()>

Appends an intermediate report. Read more
§

fn set_values(&self, trial: TrialId, values: &[f64]) -> Result<()>

Records a trial’s final objective values. Read more
§

fn set_error(&self, trial: TrialId, message: &str) -> Result<()>

Records why a trial failed. Read more
§

fn heartbeat(&self, trial: TrialId, now_millis: u64) -> Result<()>

Records that the trial’s owner is still alive at now_millis. Read more
§

fn set_trial_user_attr( &self, trial: TrialId, key: &str, value: Value, ) -> Result<()>

Inserts or replaces one user-owned JSON attribute on an unfinished trial and marks that trial changed for sync. Read more
§

fn put_state(&self, scope: Scope, blob: StateBlob) -> Result<()>

Writes the state blob of scope, replacing any previous one. Read more
§

fn get_state(&self, scope: Scope) -> Result<Option<StateBlob>>

Reads the state blob of scope, if one was ever written. Read more
§

fn read_snapshot(&self, request: &SnapshotRequest) -> Result<StorageSnapshot>

Reads trial deltas, requested side state, and optional finalization records for one observation. Read more
§

fn trial_lifecycle(&self) -> Option<&dyn TrialLifecycleStorage>

Returns the backend’s atomic trial-lifecycle capability, if available. Read more
§

fn atomic_import(&self) -> Option<&dyn AtomicImportStorage>

Returns the backend’s whole-import atomic-publication capability, if available. Read more
§

fn study_catalog(&self) -> Option<&dyn StudyCatalog>

Returns the backend’s study-catalog capability, if available. Read more
§

fn sync( &self, study: StudyId, cursor: Cursor, ) -> Result<(Vec<TrialDelta>, Cursor)>

Returns everything that happened in study after cursor. Read more
§

fn sync_limited( &self, study: StudyId, cursor: Cursor, max_trials: usize, ) -> Result<SyncPage>

sync, bounded to at most max_trials deltas. Read more
§

fn get_trial(&self, trial: TrialId) -> Result<FrozenTrial>

Reads one trial’s snapshot. Read more
§

impl StudyCatalog for MemStorage

§

fn create_if_empty(&self, cfg: StudyConfig) -> Result<StudyCreateOutcome>

Atomically creates cfg only when the catalog has no studies. Read more
§

fn list_studies(&self) -> Result<Vec<StudySummary>>

Lists study identities in deterministic ascending StudyId order. Read more
§

fn find_by_name(&self, name: &str) -> Result<StudyLoadOutcome>

Resolves an exact name without selecting arbitrarily among duplicates. Read more
§

fn list(&self) -> Result<Vec<StudySummary>>

Short alias for list_studies. Read more
§

impl TrialLifecycleStorage for MemStorage

§

fn reserve_and_create_if_budget( &self, request: ReserveAndCreateRequest, ) -> Result<ReservationOutcome>

Reserves and creates a waiting trial if the durable-record budget allows it. Created consumes a trial number; Exhausted consumes nothing. Read more
§

fn abandon(&self, request: AbandonRequest) -> Result<bool>

Conditionally abandons an as-yet-unclaimed reservation. Read more
§

fn observe(&self, trial: TrialId) -> Result<LeaseObservation>

Reads the complete current lease observation for a trial. Read more
§

fn observe_finalization( &self, study: StudyId, ) -> Result<FinalizationObservation>

Reads the study-wide finalization ownership observation. Read more
§

fn acquire_finalization( &self, request: FinalizationAcquireRequest, ) -> Result<FinalizationToken>

Atomically acquires or reclaims the study-wide finalization claim. Read more
§

fn renew_finalization( &self, token: FinalizationToken, ) -> Result<FinalizationObservation>

Atomically renews a held study-wide finalization claim. Read more
§

fn release_finalization(&self, token: FinalizationToken) -> Result<()>

Atomically releases a held study-wide finalization claim. Read more
§

fn claim(&self, request: ClaimRequest) -> Result<TrialOwnerToken>

Atomically claims a reservation or paused trial, writes its initial parameters/state, and starts a new owner epoch. Read more
§

fn renew(&self, request: RenewRequest) -> Result<LeaseObservation>

Renews a running owner and returns the new observation. Read more
§

fn fail_stale(&self, request: FailStaleRequest) -> Result<bool>

Conditionally fails a running trial whose complete observed lease the caller proved unchanged for the request’s grace interval. Backends must compare the complete observation atomically, but must not compare the sweeper timestamp to the owner’s heartbeat timestamp: those clocks may belong to different nodes. Returns true for the sole race winner. The winner atomically commits the failed outcome and an Initial outbox record keyed by the observed trial and epoch, including the request’s finalization intent. A race loss commits neither. Read more
§

fn fenced_mutate(&self, request: FencedMutationRequest) -> Result<()>

Applies one mutation only if the owner/epoch token is still exact. Read more
§

fn mutate_owned( &self, owner: FinalizationToken, request: FencedMutationRequest, ) -> Result<()>

Applies one lifecycle mutation under a study-wide finalization owner. Read more
§

fn terminal(&self, request: TerminalRequest) -> Result<()>

Validates and commits a terminal outcome only if the owner/epoch token is still exact. Read more
§

fn terminal_with_intent( &self, request: TerminalRequest, intent: FinalizationIntent, ) -> Result<OutboxKey>

Commits a terminal outcome together with its durable initial outbox intent. Read more
§

fn terminal_with_intent_owned( &self, owner: FinalizationToken, request: TerminalRequest, intent: FinalizationIntent, ) -> Result<OutboxKey>

Commits a terminal result and initial outbox intent under a study-wide finalization owner. Read more
§

fn advance_outbox(&self, request: OutboxAdvanceRequest) -> Result<OutboxPhase>

Atomically persists callback state and discovered intents while moving one outbox record through its explicit phases. Read more
§

fn advance_outbox_owned( &self, owner: FinalizationToken, request: OutboxAdvanceRequest, _operation: OperationId, ) -> Result<OutboxPhase>

Advances one outbox phase under a study-wide finalization owner. Read more
§

fn get_outbox(&self, key: OutboxKey) -> Result<Option<OutboxRecord>>

Reads one durable outbox record, including its replay cursor and completed effect keys. Read more
§

fn list_outbox(&self) -> Result<Vec<OutboxRecord>>

Lists durable outbox records in key order, including fully-done records. Read more
§

fn list_outbox_page(&self, request: OutboxPageRequest) -> Result<OutboxPage>

Reads one bounded page of study-scoped durable outbox records. Read more
§

fn complete_outbox_effect(&self, request: OutboxEffectCompletion) -> Result<()>

Idempotently acknowledges an externally executed effect. Read more
§

fn create_replacement( &self, effect_key: OutboxEffectKey, ) -> Result<ReplacementOutcome>

Idempotently creates the replacement described by a durable effect. Read more
§

fn put_finalized_state(&self, request: FinalizedStateRequest) -> Result<()>

Replaces one state blob on a terminal lifecycle-managed trial. Read more
§

fn advance_outbox_with_operation( &self, request: OutboxAdvanceRequest, _operation: OperationId, ) -> Result<OutboxPhase>

Advances one outbox phase with the caller’s lifecycle operation correlation. Read more
§

fn complete_outbox_effect_with_operation( &self, request: OutboxEffectCompletion, _operation: OperationId, ) -> Result<()>

Acknowledges one externally executed effect with caller correlation. Read more
§

fn create_replacement_with_operation( &self, effect: OutboxEffectKey, _operation: OperationId, ) -> Result<ReplacementOutcome>

Creates one replacement with caller correlation. Read more
§

fn put_finalized_state_with_operation( &self, request: FinalizedStateRequest, _operation: OperationId, ) -> Result<()>

Replaces finalized state with caller correlation. 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
§

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

§

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

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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.

§

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

Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
§

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

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more