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
impl FsLayoutStore
Sourcepub fn new(root: impl Into<PathBuf>, repo: &RepoId) -> Self
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)).
Sourcepub fn open(root: impl Into<PathBuf>, repo: &RepoId) -> Result<Self, StoreError>
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.
Sourcepub fn in_partition(
root: impl Into<PathBuf>,
partition: Partition,
repo: RepoName,
) -> Self
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.
Sourcepub fn with_clock(self, clock: Arc<dyn Clock>) -> Self
pub fn with_clock(self, clock: Arc<dyn Clock>) -> Self
Use clock for Precondition::NotAfter instead of the host
clock.
Trait Implementations§
Source§impl Debug for FsLayoutStore
impl Debug for FsLayoutStore
Source§impl NamespaceStore for FsLayoutStore
impl NamespaceStore for FsLayoutStore
Source§fn capabilities(&self) -> StoreCapabilities
fn capabilities(&self) -> StoreCapabilities
Source§async fn get(
&self,
p: &Partition,
key: &Key,
) -> Result<Option<Value>, StoreError>
async fn get( &self, p: &Partition, key: &Key, ) -> Result<Option<Value>, StoreError>
key, if any.Source§async fn scan(
&self,
p: &Partition,
start: &Key,
end: &Key,
after: Option<&Cursor>,
limit: u32,
) -> Result<ScanPage, StoreError>
async fn scan( &self, p: &Partition, start: &Key, end: &Key, after: Option<&Cursor>, limit: u32, ) -> Result<ScanPage, StoreError>
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>
async fn apply( &self, p: &Partition, batch: Batch, ) -> Result<BatchOutcome, StoreError>
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>
async fn stats(&self, p: &Partition) -> Result<PartitionStats, StoreError>
Source§fn has(
&self,
p: &Partition,
key: &Key,
) -> impl Future<Output = Result<bool, StoreError>> + MaybeSend
fn has( &self, p: &Partition, key: &Key, ) -> impl Future<Output = Result<bool, StoreError>> + MaybeSend
key holds a value.Source§fn get_many(
&self,
p: &Partition,
keys: &[Key],
) -> impl Future<Output = Result<Vec<Option<Value>>, StoreError>> + MaybeSend
fn get_many( &self, p: &Partition, keys: &[Key], ) -> impl Future<Output = Result<Vec<Option<Value>>, StoreError>> + MaybeSend
Self::get calls.Source§fn scan_many(
&self,
p: &Partition,
ranges: &[RangeScan],
) -> impl Future<Output = Result<Vec<ScanPage>, StoreError>> + MaybeSend
fn scan_many( &self, p: &Partition, ranges: &[RangeScan], ) -> impl Future<Output = Result<Vec<ScanPage>, StoreError>> + MaybeSend
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.