Skip to main content

FsLayoutStore

Struct FsLayoutStore 

Source
pub struct FsLayoutStore { /* private fields */ }
Expand description

A NamespaceStore holding the ref class (r 00 <repo> 00 <name>) of one repo, in one partition, as files under the served root. Its capabilities are StoreCapabilities::refs_only: one key per batch, no layout-version row (the .mkit on-disk format is layout version 1).

A ref (a refs/ name) is exactly FileTransport’s ref file: reads are FileTransport’s strict reads, and every write is its CAS (Missing for an Absent guard, Match for an Equals guard, Any otherwise) and its atomic write, under its ref lock (<root>/.mkit/refs/.lock), so mkit+file:// remotes and this store see the same files and serialize on the same lock. Local mkit commands use their own per-ref refs-<digest>.lock and are not coordinated with it (SPEC-CONCURRENCY §3.1). A ref’s value is its 32-byte id. A ref file that does not decode is StoreError::Corrupt on a read or a precondition, never absent; a scan skips it with a warning, like a ref file whose name is over refs::MAX_REF_NAME_BYTES (written before SPEC-REFS §3 capped names), as FileTransport::list_refs skips both. A ref whose file would clash with another ref’s directory, or the reverse, is StoreError::Invalid; a delete removes the directories it leaves empty.

The ref class also allows names that are not refs/ ref names, with any value. The pipeline never writes one (it serves only refs/ names, R-86); they live in row files under .mkit/server/rows/, written under the same lock and invisible to the CLI and FileTransport (so a name like packs/<hex> can never overwrite a pack). Ref files an older mkit serve wrote outside refs/ (<root>/main) are not served.

apply takes the ref lock, reads the store clock (for a Precondition::NotAfter), checks every precondition and writes, all in one synchronous step (normative rules 4 and 8). Reads take no lock: every write is one atomic rename. A full disk or quota is StoreError::Full, except for a delete-only batch (rule 7).

A process that crashes mid-write leaves its temp file (.<file>.tmp.<pid>.<seq>, next to the ref or row file) behind. It is at most a ref wire or a row long; scans skip it, and nothing sweeps it (the pack temp files a crashed upload leaves are swept, see FsBlobStore::sweep_stale_uploads).

It is the permanent metadata store of the server-free ssh path (reconciliation R-13), with SinglePartition routing.

Implementations§

Source§

impl FsLayoutStore

Source

pub fn new(root: impl Into<PathBuf>, repo: &RepoId) -> Self

repo’s refs, served from root, in the partition SinglePartition routes them to (Partition::Namespace(repo.namespace)).

Source

pub fn open(root: impl Into<PathBuf>, repo: &RepoId) -> Result<Self, StoreError>

Self::new, refusing a root whose refs live in SQLite (R-81): one carrying the META_MARKER a SQLite-metadata server deployment writes. Serving its ref files too would keep a second, diverging copy of the refs. Every server of a .mkit root opens its ref store through here.

§Errors

StoreError::Unsupported naming both ways out when the root is marked; StoreError::Unavailable when the marker cannot be checked.

Source

pub fn in_partition( root: impl Into<PathBuf>, partition: Partition, repo: RepoName, ) -> Self

repo’s refs in partition, served from root: for a deployment that maps each partition to its own directory. Any other partition or repo is StoreError::Unsupported.

Source

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

Use clock for Precondition::NotAfter instead of the host clock.

Source

pub fn root(&self) -> &Path

The served root.

Trait Implementations§

Source§

impl Debug for FsLayoutStore

Source§

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

Formats the value using the given formatter. Read more
Source§

impl NamespaceStore for FsLayoutStore

Source§

fn capabilities(&self) -> StoreCapabilities

What this store supports.
Source§

async fn get( &self, p: &Partition, key: &Key, ) -> Result<Option<Value>, StoreError>

The value at key, if any.
Source§

async fn scan( &self, p: &Partition, start: &Key, end: &Key, after: Option<&Cursor>, limit: u32, ) -> Result<ScanPage, StoreError>

Up to limit (at least 1) entries in [start, end), ascending by key bytes. after resumes strictly after the cursor’s position; a cursor outside [start, end) (forged, or from another range) is StoreError::Invalid. A page may hold fewer than limit entries and still return next: callers page until next is None.
Source§

async fn apply( &self, p: &Partition, batch: Batch, ) -> Result<BatchOutcome, StoreError>

One atomic, all-or-nothing batch: validate it, read the backend clock once, check every precondition in order against committed state (NotAfter against that reading); on the first failure return BatchOutcome::PreconditionFailed or BatchOutcome::DeadlinePassed and write nothing, otherwise apply every write and return BatchOutcome::Committed.
Source§

async fn stats(&self, p: &Partition) -> Result<PartitionStats, StoreError>

Storage used by one partition; may be approximate or up to 60 s stale.
Source§

async fn probe(&self) -> Result<(), StoreError>

A cheap health check.
Source§

fn has( &self, p: &Partition, key: &Key, ) -> impl Future<Output = Result<bool, StoreError>> + MaybeSend

Whether key holds a value.
Source§

fn get_many( &self, p: &Partition, keys: &[Key], ) -> impl Future<Output = Result<Vec<Option<Value>>, StoreError>> + MaybeSend

Several keys in one round trip; results in input order. The default issues sequential Self::get calls.
Source§

fn scan_many( &self, p: &Partition, ranges: &[RangeScan], ) -> impl Future<Output = Result<Vec<ScanPage>, StoreError>> + MaybeSend

Scan a served prefix of ranges in order. A nonempty request returns at least its first page and at most one page per range; callers re-request any unserved suffix. Every returned page obeys Self::scan. The default serves every range sequentially.

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

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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.

Source§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> MaybeSync for T
where T: Sync + ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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

impl<T> WithSubscriber for T

Source§

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

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

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