Class JournalStorage
- Namespace
- OptunaSharp.Storages.Journal
- Assembly
- OptunaSharp.dll
Storage class for Journal storage backend.
Port of optuna/storages/journal/_storage.py: JournalStorage.
Journal storage writes a record of every operation to the database as it is executed and at the same time, keeps a latest snapshot of the database in-memory. If the database crashes for any reason, the storage can re-establish the contents in memory by replaying the operations stored from the beginning.
public class JournalStorage : BaseStorage
- Inheritance
-
JournalStorage
- Inherited Members
Examples
var storage = new JournalStorage(new JournalFileBackend("./optuna_journal_storage.log"));
var study = Optuna.CreateStudy(storage: storage);
study.Optimize(objective);
On Windows, prefer the open lock:
var filePath = "./optuna_journal_storage.log";
var lockObj = new JournalFileOpenLock(filePath);
var storage = new JournalStorage(new JournalFileBackend(filePath, lockObj: lockObj));
Constructors
JournalStorage(BaseJournalBackend, int?)
Restores an optional snapshot and replays the journal to initialize a synchronized storage view.
public JournalStorage(BaseJournalBackend logStorage, int? snapshotInterval = null)
Parameters
logStorageBaseJournalBackendShared process-safe journal backend; its lifetime belongs to the caller.
snapshotIntervalint?For a backend that stores snapshots (IBaseJournalSnapshot: the Redis backends), how many study or trial ids apart this storage saves one: the worker that creates a study or trial whose id is a multiple of this value saves the whole replay state.
null(the default) lets the backend choose through IJournalSnapshotInterval (the Redis backends: Optuna's 100 in both read modes), and falls back to Optuna's fixedSNAPSHOT_INTERVALof 100. Optuna has no such parameter. See the remarks for the trade-off; SnapshotInterval reports the value this storage uses.
Remarks
A storage opened over a journal first restores the latest snapshot and then replays only the records
written after it, so its cold start reads at most about one interval of records. Each snapshot serializes
every trial of the journal under this storage's lock, so a snapshot costs more the longer the journal grows,
and a smaller interval saves one more often. Workers that open and close storages often (the
optunasharp CLI opens one per command) gain from a snapshot when replaying records is expensive;
long-lived workers sync incrementally and never read one.
Measured on 2026-11-07 at 20,000 two-parameter trials on a standalone Redis server (Release build, with the binary snapshot of plan 10, item 2.7), where records are read in batches: a cold start took 109 ms, 170 ms and 927 ms at an interval of 100, 1000 and no snapshot, and the writer 9.76 ms per trial at 100 against 10.74 with no snapshot. In cluster mode, where every record costs a round trip, the same cold start took 0.43 s, 3.3 s and 70.8 s. A snapshot of that study saves in about 20 ms and restores in about 40 ms.
OptunaSharp's snapshots are its own (a binary format, under their own Redis key): Python workers on the same journal neither read nor write them, whatever interval either side uses.
Exceptions
- ArgumentOutOfRangeException
snapshotIntervalis below 1.- ArgumentException
snapshotIntervalisnulland the backend's DefaultSnapshotInterval is below 1.- Exception
The backend cannot load a snapshot, read records, or replay their contents.
Properties
SnapshotInterval
How many study or trial ids apart this storage saves a replay snapshot, resolved once by the constructor: its
snapshotInterval argument, else the backend's DefaultSnapshotInterval,
else Optuna's 100. Unused when the backend stores no snapshots (it does not implement
IBaseJournalSnapshot).
public int SnapshotInterval { get; }
Property Value
Methods
CreateNewStudy(IReadOnlyList<StudyDirection>, string?)
Create a new study from a name. If no name is specified, the storage class generates a name. The returned study ID is unique among all current and deleted studies.
public override int CreateNewStudy(IReadOnlyList<StudyDirection> directions, string? studyName = null)
Parameters
directionsIReadOnlyList<StudyDirection>Objective directions in the same order as the objective values.
studyNamestringName identifying the study in the selected storage.
Returns
- int
Unique storage identifier assigned to the created study.
Exceptions
- DuplicatedStudyError
If a study with the same name already exists.
CreateNewTrial(int, FrozenTrial?)
Create and add a new trial to a study. The returned trial ID is unique among all current and deleted trials.
public override int CreateNewTrial(int studyId, FrozenTrial? templateTrial = null)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
templateTrialFrozenTrialTemplate FrozenTrial with default user-attributes, system-attributes, intermediate-values, and a state.
Returns
- int
Unique storage identifier of the created trial.
Exceptions
- KeyError
If no study with the matching ID exists.
DeleteStudy(int)
Delete a study.
public override void DeleteStudy(int studyId)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
Exceptions
- KeyError
If no study with the matching ID exists.
GetAllStudies()
Read a list of FrozenStudy objects, sorted by study ID.
public override List<FrozenStudy> GetAllStudies()
Returns
- List<FrozenStudy>
Study metadata records ordered by storage identifier.
GetAllTrials(int, bool, IReadOnlyCollection<TrialState>?)
Read all trials in a study, sorted by trial ID.
public override List<FrozenTrial> GetAllTrials(int studyId, bool deepcopy = true, IReadOnlyCollection<TrialState>? states = null)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
deepcopyboolWhether to copy trial records; treat records returned with false as read-only.
statesIReadOnlyCollection<TrialState>States to include; null includes every state.
Returns
- List<FrozenTrial>
Trials in identifier order, optionally filtered by state and copied.
Exceptions
- KeyError
If no study with the matching ID exists.
GetStudyDirections(int)
Read whether a study maximizes or minimizes an objective.
public override List<StudyDirection> GetStudyDirections(int studyId)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
Returns
- List<StudyDirection>
Objective directions in objective-value order; callers must not mutate shared storage records.
Exceptions
- KeyError
If no study with the matching ID exists.
GetStudyIdFromName(string)
Read the ID of a study.
public override int GetStudyIdFromName(string studyName)
Parameters
studyNamestringName identifying the study in the selected storage.
Returns
- int
Storage identifier of the named study.
Exceptions
- KeyError
If no study with the matching name exists.
GetStudyNameFromId(int)
Read the study name of a study.
public override string GetStudyNameFromId(int studyId)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
Returns
- string
Registered study name.
Exceptions
- KeyError
If no study with the matching ID exists.
GetStudySystemAttrs(int)
Read the optuna-internal attributes of a study.
public override OrderedDict<string, object?> GetStudySystemAttrs(int studyId)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
Returns
- OrderedDict<string, object>
Internal metadata snapshot; callers must not mutate shared storage records.
Exceptions
- KeyError
If no study with the matching ID exists.
GetStudyUserAttrs(int)
Read the user-defined attributes of a study.
public override OrderedDict<string, object?> GetStudyUserAttrs(int studyId)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
Returns
- OrderedDict<string, object>
User metadata snapshot; callers must not mutate shared storage records.
Exceptions
- KeyError
If no study with the matching ID exists.
GetTrial(int)
Read a trial.
public override FrozenTrial GetTrial(int trialId)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
Returns
- FrozenTrial
Stored trial record; treat it as read-only unless copied.
Exceptions
- KeyError
If no trial with the matching ID exists.
GetTrialIdFromStudyIdTrialNumber(int, int)
Read the trial ID of a trial.
public override int GetTrialIdFromStudyIdTrialNumber(int studyId, int trialNumber)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
trialNumberintZero-based trial number within the study, not a storage identifier.
Returns
- int
Storage identifier corresponding to the per-study trial number.
Exceptions
- KeyError
If no trial with the matching study ID and trial number exists.
- ArgumentOutOfRangeException
The trial number is negative.
RestoreReplayResult(byte[])
Restore the in-memory replay state from a snapshot produced by
OptunaSharp.Storages.Journal.JournalStorageReplayResult.Serialize().
[Misaligned] Python snapshots are pickle bytes; OptunaSharp uses its own binary format (v2 since plan 10,
item 2.7; the older v1 JSON still restores) under its own key (the Redis backends'
{prefix}:snapshot:optunasharp) — snapshots are a same-language acceleration, never a cross-language
artifact (the file backend has no snapshot support on either side).
public void RestoreReplayResult(byte[] snapshot)
Parameters
snapshotbyte[]OptunaSharp snapshot bytes, v2 or v1; anything else is ignored with a warning.
SetStudySystemAttr(int, string, object?)
Register an optuna-internal attribute to a study, overwriting any existing value.
public override void SetStudySystemAttr(int studyId, string key, object? value)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
keystringAttribute name; a later write replaces its stored value.
valueobjectAttribute value; persistent backends require JSON-serializable data.
Exceptions
- KeyError
If no study with the matching ID exists.
SetStudySystemAttrs(int, IReadOnlyDictionary<string, object?>)
Register several optuna-internal attributes to a study at once (Rustuna's set_study_system_attrs;
plan 13, item S8): the result of SetStudySystemAttr(int, string, object?) once per entry, in order.
public override void SetStudySystemAttrs(int studyId, IReadOnlyDictionary<string, object?> attrs)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
attrsIReadOnlyDictionary<string, object>The attributes, written in enumeration order.
Remarks
The default writes one entry per call; see SetStudyUserAttrs(int, IReadOnlyDictionary<string, object?>) for what the overrides do.
Exceptions
- ArgumentNullException
attrsis null.- KeyError
If no study with the matching ID exists.
SetStudyUserAttr(int, string, object?)
Register a user-defined attribute to a study, overwriting any existing value.
public override void SetStudyUserAttr(int studyId, string key, object? value)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
keystringAttribute name; a later write replaces its stored value.
valueobjectAttribute value; persistent backends require JSON-serializable data.
Exceptions
- KeyError
If no study with the matching ID exists.
SetStudyUserAttrs(int, IReadOnlyDictionary<string, object?>)
Register several user-defined attributes to a study at once, overwriting existing values (Rustuna's
set_study_user_attrs; Rustuna plan 13, item S8). Optuna has no such call: the result is what calling
SetStudyUserAttr(int, string, object?) once per entry, in the dictionary's order, leaves.
public override void SetStudyUserAttrs(int studyId, IReadOnlyDictionary<string, object?> attrs)
Parameters
studyIdintStorage identifier of the study; distinct from its name.
attrsIReadOnlyDictionary<string, object>The attributes, written in enumeration order.
Remarks
This default writes one entry per call, exactly as a caller looping over SetStudyUserAttr(int, string, object?) would, so any storage supports it; it is atomic only as far as each single call is. The built-in storages override it to write in one step: one lock in memory, one appended batch in a journal, one transaction in a database. An empty dictionary writes nothing and checks nothing.
Exceptions
- ArgumentNullException
attrsis null.- KeyError
If no study with the matching ID exists.
SetTrialIntermediateValue(int, long, double)
Report an intermediate value of an objective function, overwriting any existing value associated with the step.
public override void SetTrialIntermediateValue(int trialId, long step, double intermediateValue)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
steplongReporting step whose intermediate objective observation is stored; written as a JSON integer, 64-bit like Python's.
intermediateValuedoubleIntermediate objective observation to store at the reporting step.
Exceptions
- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.
SetTrialParam(int, string, double, BaseDistribution)
Set a parameter to a trial.
public override void SetTrialParam(int trialId, string paramName, double paramValueInternal, BaseDistribution distribution)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
paramNamestringParameter name used as the storage and distribution lookup key.
paramValueInternaldoubleParameter value in the distribution's internal numeric representation.
distributionBaseDistributionDistribution defining the parameter representation and allowed values.
Exceptions
- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.
- ValueError
The distribution is incompatible with an existing parameter distribution.
SetTrialStateValues(int, TrialState, IReadOnlyList<double>?)
Update the state and values of a trial. If values is not
null, this method overwrites any existing trial values.
public override bool SetTrialStateValues(int trialId, TrialState state, IReadOnlyList<double>? values = null)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
stateTrialStateTrial state to record or inspect.
valuesIReadOnlyList<double>Objective values in study direction order, or null when no objective values are recorded.
Returns
- bool
trueif the state is successfully updated;falseif the state is kept the same (which happens when updating a RUNNING trial to RUNNING).
Exceptions
- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.
SetTrialSystemAttr(int, string, object?)
Set an optuna-internal attribute to a trial, overwriting any existing value.
public override void SetTrialSystemAttr(int trialId, string key, object? value)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
keystringAttribute name; a later write replaces its stored value.
valueobjectAttribute value; persistent backends require JSON-serializable data.
Exceptions
- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.
SetTrialSystemAttrs(int, IReadOnlyDictionary<string, object?>)
Set several optuna-internal attributes of a trial at once (Rustuna's set_trial_system_attrs; plan 13,
item S8): the result of SetTrialSystemAttr(int, string, object?) once per entry, in order.
public override void SetTrialSystemAttrs(int trialId, IReadOnlyDictionary<string, object?> attrs)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
attrsIReadOnlyDictionary<string, object>The attributes, written in enumeration order.
Remarks
The default writes one entry per call; see SetTrialUserAttrs(int, IReadOnlyDictionary<string, object?>) for what the overrides do.
Exceptions
- ArgumentNullException
attrsis null.- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.
SetTrialUserAttr(int, string, object?)
Set a user-defined attribute to a trial, overwriting any existing value.
public override void SetTrialUserAttr(int trialId, string key, object? value)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
keystringAttribute name; a later write replaces its stored value.
valueobjectAttribute value; persistent backends require JSON-serializable data.
Exceptions
- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.
SetTrialUserAttrs(int, IReadOnlyDictionary<string, object?>)
Set several user-defined attributes of a trial at once, overwriting existing values (Rustuna's
set_trial_user_attrs; Rustuna plan 13, item S8). Optuna has no such call: the result is what calling
SetTrialUserAttr(int, string, object?) once per entry, in the dictionary's order, leaves.
public override void SetTrialUserAttrs(int trialId, IReadOnlyDictionary<string, object?> attrs)
Parameters
trialIdintStorage identifier of the trial; distinct from its per-study trial number.
attrsIReadOnlyDictionary<string, object>The attributes, written in enumeration order.
Remarks
This default writes one entry per call, as a caller's own loop would, so any storage supports it; a failure part-way leaves the entries before it written. The built-in storages override it to write in one step and check the trial once, so a finished or unknown trial gets nothing written: one lock in memory, one appended batch of ordinary single-attribute records in a journal (what Python's journal reader expects), one transaction in a database. An empty dictionary writes nothing and checks nothing.
Exceptions
- ArgumentNullException
attrsis null.- KeyError
If no trial with the matching ID exists.
- UpdateFinishedTrialError
If the trial is already finished.