pub struct DoubletsStorage<T: LinkReference, S: Doublets<T>> { /* private fields */ }Expand description
A LinksStorage over any doublets store.
Implementations§
Source§impl<T: LinkReference> DoubletsStorage<T, FileMappedUnitStore<T>>
impl<T: LinkReference> DoubletsStorage<T, FileMappedUnitStore<T>>
Sourcepub fn open<P: AsRef<Path>>(path: P) -> Result<Self, LinkError>
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, LinkError>
Opens (or creates) a file-mapped doublets database at path
without taking an advisory lock.
Opens the database and holds a shared advisory lock for the lifetime of the returned storage, excluding concurrent writers.
Sourcepub fn open_exclusive<P: AsRef<Path>>(path: P) -> Result<Self, LinkError>
pub fn open_exclusive<P: AsRef<Path>>(path: P) -> Result<Self, LinkError>
Opens the database and holds an exclusive advisory lock for the lifetime of the returned storage, excluding every other reader and writer that honours the same protocol.
Sourcepub fn try_open_exclusive<P: AsRef<Path>>(
path: P,
) -> Result<Option<Self>, LinkError>
pub fn try_open_exclusive<P: AsRef<Path>>( path: P, ) -> Result<Option<Self>, LinkError>
Like Self::open_exclusive but returns Ok(None) instead of
blocking when another holder owns a conflicting lock.
Source§impl<T: LinkReference, S: Doublets<T>> DoubletsStorage<T, S>
impl<T: LinkReference, S: Doublets<T>> DoubletsStorage<T, S>
Sourcepub fn wrap(store: S) -> Self
pub fn wrap(store: S) -> Self
Adopts a doublets store the caller already owns.
Nothing about the store is assumed: no path, no locking and no
external-change detection. This is the entry point for embedding
applications that open their own unit::Store<usize, _> and only
want the transactions layer on top of it.
Sourcepub fn wrap_at<P: AsRef<Path>>(store: S, path: P) -> Result<Self, LinkError>
pub fn wrap_at<P: AsRef<Path>>(store: S, path: P) -> Result<Self, LinkError>
Adopts a store the caller already owns while recording the path
it is backed by, enabling LinksStorage::flush,
LinksStorage::has_external_changes and the lock helpers.
Sourcepub fn map_store<S2, F>(self, map: F) -> DoubletsStorage<T, S2>
pub fn map_store<S2, F>(self, map: F) -> DoubletsStorage<T, S2>
Replaces the underlying store with map(store), keeping the path,
advisory lock and change-detection fingerprint of this storage.
This is the extension point for stacking any doublets decorator
(or a custom one) under the transactions and version control
layers:
use doublets::decorators::DecoratorsExt;
use link_cli::storage::DoubletsStorage;
let storage = DoubletsStorage::<u32, _>::open("links.data")?
.map_store(|store| store.with_inner_reference_existence_validation());Sourcepub fn with_automatic_uniqueness_and_usages_resolution(
self,
) -> DoubletsStorage<T, AutomaticUniquenessAndUsagesResolution<T, S>>
pub fn with_automatic_uniqueness_and_usages_resolution( self, ) -> DoubletsStorage<T, AutomaticUniquenessAndUsagesResolution<T, S>>
Wraps the underlying store in the same decorator stack C# applies
through ILinksExtensions.DecorateWithAutomaticUniquenessAndUsagesResolution.
After this call (source, target) pairs are unique: creating or
updating a link into a pair that already exists resolves to the
existing link, re-points every usage of the redundant link at the
survivor and deletes the redundant link. Deleting a link cascades
to its usages and resets its contents first.
use link_cli::storage::{DoubletsStorage, LinksStorage};
let mut storage = DoubletsStorage::<u32, _>::open("links.data")?
.with_automatic_uniqueness_and_usages_resolution();
let first = storage.create_link(1, 1)?;
let second = storage.create_link(1, 1)?;
assert_eq!(first, second);Sourcepub fn into_store(self) -> S
pub fn into_store(self) -> S
Returns the underlying doublets store, dropping any held lock.
Acquires a shared advisory lock on this database’s sidecar lock file.
Sourcepub fn lock_exclusive(&self) -> Result<FileLock, LinkError>
pub fn lock_exclusive(&self) -> Result<FileLock, LinkError>
Acquires an exclusive advisory lock on this database’s sidecar lock file.
Trait Implementations§
Source§impl<T: LinkReference, S: Doublets<T>> LinksStorage<T> for DoubletsStorage<T, S>
impl<T: LinkReference, S: Doublets<T>> LinksStorage<T> for DoubletsStorage<T, S>
Source§fn flush(&mut self) -> Result<(), LinkError>
fn flush(&mut self) -> Result<(), LinkError>
fsyncs the backing file so the mapped writes survive a machine
crash, and publishes them to other processes by advancing the
file’s modification time. A no-op for stores adopted without a
known path.
Bumping the timestamp is deliberate: the kernel only refreshes
mtime when a clean page of a shared mapping is first written
to, so a long-lived writer that keeps touching already-dirty
pages would otherwise stay invisible to
LinksStorage::has_external_changes.
Source§fn has_external_changes(&self) -> Result<bool, LinkError>
fn has_external_changes(&self) -> Result<bool, LinkError>
Compares the database file’s size and mtime against the values observed when this storage was opened, reloaded or flushed.
The granularity is a published write: writers publish by
calling LinksStorage::flush, which fsyncs and advances the
file’s modification time. Writes that a peer has made but not yet
flushed are already visible through the shared mapping, but are
not reported here — take DoubletsStorage::lock_shared when an
exact answer is required.
Source§fn reload(&mut self) -> Result<(), LinkError>
fn reload(&mut self) -> Result<(), LinkError>
Memory-mapped stores always read through to the mapping, so this only refreshes the change-detection fingerprint.
Source§fn create_link(&mut self, source: T, target: T) -> Result<T, LinkError>
fn create_link(&mut self, source: T, target: T) -> Result<T, LinkError>
Source§fn ensure_link_created(&mut self, index: T) -> Result<T, LinkError>
fn ensure_link_created(&mut self, index: T) -> Result<T, LinkError>
index, creating placeholders as needed.Source§fn get_link(&self, index: T) -> Option<GenericLink<T>>
fn get_link(&self, index: T) -> Option<GenericLink<T>>
index, if any.Source§fn link_exists(&self, index: T) -> bool
fn link_exists(&self, index: T) -> bool
true when a link exists at index.Source§fn update_link(
&mut self,
index: T,
source: T,
target: T,
) -> Result<GenericLink<T>, LinkError>
fn update_link( &mut self, index: T, source: T, target: T, ) -> Result<GenericLink<T>, LinkError>
index at source/target, returning the previous state.Source§fn delete_link(&mut self, index: T) -> Result<GenericLink<T>, LinkError>
fn delete_link(&mut self, index: T) -> Result<GenericLink<T>, LinkError>
index, returning the link that was removed.Source§fn all_links(&self) -> Vec<GenericLink<T>>
fn all_links(&self) -> Vec<GenericLink<T>>
Source§fn query_links(
&self,
index: Option<T>,
source: Option<T>,
target: Option<T>,
) -> Vec<GenericLink<T>>
fn query_links( &self, index: Option<T>, source: Option<T>, target: Option<T>, ) -> Vec<GenericLink<T>>
Source§fn search_link(&self, source: T, target: T) -> Option<T>
fn search_link(&self, source: T, target: T) -> Option<T>
Source§fn get_or_create_link(&mut self, source: T, target: T) -> Result<T, LinkError>
fn get_or_create_link(&mut self, source: T, target: T) -> Result<T, LinkError>
(source, target) link,
creating it when it does not exist yet.