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
impl MemStorage
pub fn new() -> Self
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
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>
pub fn study_count(&self) -> Result<usize>
pub fn trial_count(&self) -> Result<usize>
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
impl AtomicImportStorage for MemStorage
§fn import_batch(&self, batch: &ImportBatch) -> Result<ImportBatchResult>
fn import_batch(&self, batch: &ImportBatch) -> Result<ImportBatchResult>
§impl Debug for MemStorage
impl Debug for MemStorage
§impl Storage for MemStorage
impl Storage for MemStorage
§fn backing_paths(&self) -> Option<Vec<PathBuf>>
fn backing_paths(&self) -> Option<Vec<PathBuf>>
§fn create_study(&self, cfg: StudyConfig) -> Result<StudyId>
fn create_study(&self, cfg: StudyConfig) -> Result<StudyId>
§fn study_config(&self, study: StudyId) -> Result<StudyConfig>
fn study_config(&self, study: StudyId) -> Result<StudyConfig>
§fn study_user_attrs(&self, study: StudyId) -> Result<UserAttrs>
fn study_user_attrs(&self, study: StudyId) -> Result<UserAttrs>
§fn set_study_user_attr(
&self,
study: StudyId,
key: &str,
value: Value,
) -> Result<()>
fn set_study_user_attr( &self, study: StudyId, key: &str, value: Value, ) -> Result<()>
§fn create_trial(
&self,
study: StudyId,
template: Option<TrialTemplate>,
) -> Result<TrialRecord>
fn create_trial( &self, study: StudyId, template: Option<TrialTemplate>, ) -> Result<TrialRecord>
§fn try_transition(
&self,
trial: TrialId,
from: TrialState,
to: TrialState,
) -> Result<bool>
fn try_transition( &self, trial: TrialId, from: TrialState, to: TrialState, ) -> Result<bool>
§fn write_params(
&self,
trial: TrialId,
batch: &[(String, Distribution, ParamValue)],
) -> Result<()>
fn write_params( &self, trial: TrialId, batch: &[(String, Distribution, ParamValue)], ) -> Result<()>
§fn report(&self, trial: TrialId, step: u64, values: &[f64]) -> Result<()>
fn report(&self, trial: TrialId, step: u64, values: &[f64]) -> Result<()>
§fn set_values(&self, trial: TrialId, values: &[f64]) -> Result<()>
fn set_values(&self, trial: TrialId, values: &[f64]) -> Result<()>
§fn set_error(&self, trial: TrialId, message: &str) -> Result<()>
fn set_error(&self, trial: TrialId, message: &str) -> Result<()>
§fn heartbeat(&self, trial: TrialId, now_millis: u64) -> Result<()>
fn heartbeat(&self, trial: TrialId, now_millis: u64) -> Result<()>
now_millis. Read more§fn put_state(&self, scope: Scope, blob: StateBlob) -> Result<()>
fn put_state(&self, scope: Scope, blob: StateBlob) -> Result<()>
scope, replacing any previous one. Read more§fn get_state(&self, scope: Scope) -> Result<Option<StateBlob>>
fn get_state(&self, scope: Scope) -> Result<Option<StateBlob>>
scope, if one was ever written. Read more§fn read_snapshot(&self, request: &SnapshotRequest) -> Result<StorageSnapshot>
fn read_snapshot(&self, request: &SnapshotRequest) -> Result<StorageSnapshot>
§fn trial_lifecycle(&self) -> Option<&dyn TrialLifecycleStorage>
fn trial_lifecycle(&self) -> Option<&dyn TrialLifecycleStorage>
§fn atomic_import(&self) -> Option<&dyn AtomicImportStorage>
fn atomic_import(&self) -> Option<&dyn AtomicImportStorage>
§fn study_catalog(&self) -> Option<&dyn StudyCatalog>
fn study_catalog(&self) -> Option<&dyn StudyCatalog>
§impl StudyCatalog for MemStorage
impl StudyCatalog for MemStorage
§fn create_if_empty(&self, cfg: StudyConfig) -> Result<StudyCreateOutcome>
fn create_if_empty(&self, cfg: StudyConfig) -> Result<StudyCreateOutcome>
cfg only when the catalog has no studies. Read more§fn list_studies(&self) -> Result<Vec<StudySummary>>
fn list_studies(&self) -> Result<Vec<StudySummary>>
§fn find_by_name(&self, name: &str) -> Result<StudyLoadOutcome>
fn find_by_name(&self, name: &str) -> Result<StudyLoadOutcome>
§fn list(&self) -> Result<Vec<StudySummary>>
fn list(&self) -> Result<Vec<StudySummary>>
list_studies. Read more§impl TrialLifecycleStorage for MemStorage
impl TrialLifecycleStorage for MemStorage
§fn reserve_and_create_if_budget(
&self,
request: ReserveAndCreateRequest,
) -> Result<ReservationOutcome>
fn reserve_and_create_if_budget( &self, request: ReserveAndCreateRequest, ) -> Result<ReservationOutcome>
Created consumes a trial number; Exhausted consumes nothing. Read more