pub struct StateDirectory {
dir: CheckedDir,
}
state-dir
only.Expand description
The whole program’s state directory
Representation of [storage] state_dir
and permissions
from the Arti configuration.
This type does not embody any subpaths relating to any particular facility within Arti.
Constructing a StateDirectory
may involve filesystem permissions checks,
so ideally it would be created once per process for performance reasons.
Existence of a StateDirectory
also does not imply exclusive access.
This type is passed to each facility’s constructor;
the facility implements InstanceIdentity
and calls acquire_instance
.
§Use for caches
In principle this type and the methods and subtypes available would be suitable for cache data as well as state data.
However the locking scheme does not tolerate random removal of files. And cache directories are sometimes configured to point to locations with OS-supplied automatic file cleaning. That would not be correct, since the automatic file cleaner might remove an in-use lockfile, effectively unlocking the instance state even while a process exists that thinks it still has the lock.
Fields§
§dir: CheckedDir
The actual directory, including mistrust config
Implementations§
Source§impl StateDirectory
impl StateDirectory
Sourcepub fn new(state_dir: impl AsRef<Path>, mistrust: &Mistrust) -> Result<Self>
pub fn new(state_dir: impl AsRef<Path>, mistrust: &Mistrust) -> Result<Self>
Create a new StateDirectory
from a directory and mistrust configuration
Sourcepub fn acquire_instance<I: InstanceIdentity>(
&self,
identity: &I,
) -> Result<InstanceStateHandle>
pub fn acquire_instance<I: InstanceIdentity>( &self, identity: &I, ) -> Result<InstanceStateHandle>
Acquires (creates and locks) a storage for an instance
Ensures the existence and suitability of a subdirectory named kind/identity
,
and locks it for exclusive access.
Sourcefn with_instance_path_pieces<T>(
self: &StateDirectory,
kind_str: &'static str,
id_writer: &'_ dyn Fn(&mut Formatter<'_>) -> Result,
call: impl FnOnce(&SlugRef, &SlugRef, &dyn Fn() -> Resource) -> Result<T>,
) -> Result<T>
fn with_instance_path_pieces<T>( self: &StateDirectory, kind_str: &'static str, id_writer: &'_ dyn Fn(&mut Formatter<'_>) -> Result, call: impl FnOnce(&SlugRef, &SlugRef, &dyn Fn() -> Resource) -> Result<T>, ) -> Result<T>
Given a kind and id, obtain pieces of its path and call a “doing work” callback
This function factors out common functionality needed by
StateDirectory::acquire_instance
and StateDirectory::instance_peek_storage
,
particularly relating to instance kind and id, and errors.
kind
and id
are from an InstanceIdentity
.
Sourcepub fn list_instances<I: InstanceIdentity>(
&self,
) -> impl Iterator<Item = Result<Slug>>
pub fn list_instances<I: InstanceIdentity>( &self, ) -> impl Iterator<Item = Result<Slug>>
List the instances of a particular kind
Returns the instance identities.
(The implementation lists subdirectories named kind_*
.)
Concurrency:
An instance which is not being removed or created will be
listed (or not) according to whether it’s present.
But, in the presence of concurrent calls to acquire_instance
and delete
on different instances,
is not guaranteed to provide a snapshot:
serialisation is not guaranteed across different instances.
It is guaranteed to list each instance only once.
Sourcefn list_instances_inner(
&self,
kind: &'static str,
) -> impl Iterator<Item = Result<Slug>>
fn list_instances_inner( &self, kind: &'static str, ) -> impl Iterator<Item = Result<Slug>>
List the instances of a kind, where the kind is supplied as a value
Used by list_instances
and purge_instances
.
Includes instances that exists only as a stale lockfile.
Sourcepub fn purge_instances(
&self,
now: SystemTime,
filter: &mut (dyn InstancePurgeHandler + '_),
) -> Result<()>
pub fn purge_instances( &self, now: SystemTime, filter: &mut (dyn InstancePurgeHandler + '_), ) -> Result<()>
Delete instances according to selections made by the caller
Each instance is considered in three stages.
Firstly, it is passed to name_filter
.
If name_filter
returns Live
,
further consideration is skipped and the instance is retained.
Secondly, the last time the instance was written to is determined,
and passed to
age_filter
.
Again, this might mean ensure the instance is retained.
Thirdly, the resulting InstanceStateHandle
is passed to
dispose
.
dispose
may choose to call handle.delete()
,
or simply drop the handle.
Concurrency:
In the presence of multiple concurrent calls to acquire_instance
and delete
:
filter
may be called for an instance which is being created or deleted
by another task.
dispose
will be properly serialised with other activities on the same instance,
as implied by it receiving an InstanceStateHandle
.
The expiry time is reset by calls to acquire_instance
,
StorageHandle::store
and InstanceStateHandle::raw_subdir
;
it may be reset by calls to StorageHandle::delete
.
Instances that are currently locked by another task will not be purged,
but the expiry time is not reset by unlocking an instance
(dropping the last clone of an InstanceStateHandle
).
§Sequencing of InstancePurgeHandler
callbacks
Each instance will be processed (and callbacks made for it) at most once; and calls for different instances will not be interleaved.
During the processing of a particular instance
The callbacks will be made in order,
progressing monotonically through the methods in the order listed.
But name_filter
and age_filter
might each be called
more than once for the same instance.
Between each stage,
the purge implementation may discover that the instance
ought not to be processed further.
So returning Liveness::PossiblyUnused
from a filter does not
guarantee that the next callback will be made.
Sourcefn maybe_purge_instance(
&self,
now: SystemTime,
kind: &SlugRef,
id: &SlugRef,
resource: &dyn Fn() -> Resource,
filter: &mut (dyn InstancePurgeHandler + '_),
) -> Result<()>
fn maybe_purge_instance( &self, now: SystemTime, kind: &SlugRef, id: &SlugRef, resource: &dyn Fn() -> Resource, filter: &mut (dyn InstancePurgeHandler + '_), ) -> Result<()>
Consider whether to purge an instance
Performs all the necessary steps, including liveness checks, passing an InstanceStateHandle to filter.dispose, and deleting stale lockfiles without associated state.
Sourcepub fn instance_peek_storage<I: InstanceIdentity, T: DeserializeOwned>(
&self,
identity: &I,
key: &(impl TryIntoSlug + ?Sized),
) -> Result<Option<T>>
pub fn instance_peek_storage<I: InstanceIdentity, T: DeserializeOwned>( &self, identity: &I, key: &(impl TryIntoSlug + ?Sized), ) -> Result<Option<T>>
Tries to peek at something written by StorageHandle::store
It is guaranteed that this will return either the T
that was stored,
or None
if store
was never called,
or StorageHandle::delete
was called
So the operation is atomic, but there is no further synchronisation.
Trait Implementations§
Source§impl Clone for StateDirectory
impl Clone for StateDirectory
Source§fn clone(&self) -> StateDirectory
fn clone(&self) -> StateDirectory
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreAuto Trait Implementations§
impl Freeze for StateDirectory
impl RefUnwindSafe for StateDirectory
impl Send for StateDirectory
impl Sync for StateDirectory
impl Unpin for StateDirectory
impl UnwindSafe for StateDirectory
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more