pub enum Engine {
Znippy,
}Expand description
A storage engine this binary actually carries.
The variants are #[cfg]-gated on purpose: a value of this type is proof
that the engine it names is linked. There is no “selected but absent” state
to guard against, because it cannot be represented.
Variants§
Znippy
znippy-plugin-git — Arrow-IPC in a znippy archive.
Implementations§
Source§impl Engine
impl Engine
Sourcepub const COMPILED: &'static [Engine]
pub const COMPILED: &'static [Engine]
Every engine compiled into this binary, in preference order.
Sourcepub fn replication_can_read_repositories(self) -> bool
pub fn replication_can_read_repositories(self) -> bool
Can replication read a repository this engine stores?
It reads one by opening it as a filesystem git repository — gix::open
in [crate::mirror], then gunnar-client’s send-pack, which is proven
against the real git receive-pack and must not be twinned. An engine
that writes no .git layout cannot be read that way, and the failure
lands inside the retry loop where nobody sees it: the server accepts
every push and the standby stays empty.
So it is asked at start-up instead, and a server that cannot do what it
was configured to do refuses to come up. Closing the gap means a
server-side send-pack over GitServe — the store already emits packs
for upload-pack — at which point this predicate goes away rather than
gaining an arm.
Sourcepub fn plugin(self) -> &'static str
pub fn plugin(self) -> &'static str
The engine’s crate, as it is named on the Storage page and linked.
Sourcepub fn summary(self) -> &'static str
pub fn summary(self) -> &'static str
What it stores and how, in one line — the Storage page’s tooltip.
Sourcepub fn repo_url(self) -> String
pub fn repo_url(self) -> String
Where the engine’s source lives, off NORDISK_REPOS: znippy’s
own repository; storage-git-gix is a crate of edda’s (built on
gitoxide’s gix-odb / gix-ref).
Sourcepub fn report(self) -> StorageEngine
pub fn report(self) -> StorageEngine
The engine, in parts — name, one-line description, source
repository — for Admin.StorageInfo’s engine (2026-10-02).
Sourcepub fn describe(self) -> String
pub fn describe(self) -> String
What answers, in one line, for an operator reading storage info:
znippy-plugin-git (Arrow-IPC archive; objects + refs), made of the
same parts Self::report sends apart.
Sourcepub fn compiled_list() -> String
pub fn compiled_list() -> String
The engines this binary carries, as a human-readable list.
Sourcepub fn from_name(name: &str) -> Result<Engine>
pub fn from_name(name: &str) -> Result<Engine>
Resolve a name to an engine, or refuse.
Three outcomes, and the middle one is the whole point:
- a name this build carries → that engine;
- a name this build knows but did not compile in → refused, saying so;
- anything else → refused as unknown.
Never a fallback. See the module docs.
Sourcepub fn selected() -> Result<Engine>
pub fn selected() -> Result<Engine>
The engine this process runs, decided once, on the startup path.
ENGINE_ENV if it is set and non-empty, DEFAULT_ENGINE otherwise.
An unset variable is not “no engine”: it is the default, which is
znippy wherever znippy is compiled in.
Sourcepub fn open_repo(self, git_dir: &Path, hash_kind: Kind) -> Result<Arc<OpenRepo>>
pub fn open_repo(self, git_dir: &Path, hash_kind: Kind) -> Result<Arc<OpenRepo>>
Open — creating if absent — the repository at git_dir.
Unconditional. “It holds nothing yet” is the normal state of a repository’s first push, not a reason to answer with something else: gating on what a repository already holds is what refuses every first push, which is a mistake this seam has already made once.
Sourcepub fn cancel_index(self, git_dir: &Path)
pub fn cancel_index(self, git_dir: &Path)
Stop any index work on the repository at git_dir — the engine half
of repo delete. A no-op for an engine without a background indexer.
Sourcepub fn index_progress(self) -> Vec<(PathBuf, IndexSnapshot)>
pub fn index_progress(self) -> Vec<(PathBuf, IndexSnapshot)>
Index work in flight across every open repository, as
(git_dir, snapshot). Empty for an engine without a background indexer.
Sourcepub fn explode_use(self) -> Vec<(PathBuf, ExplodeBand)>
pub fn explode_use(self) -> Vec<(PathBuf, ExplodeBand)>
Every open repository’s explode band, as (git_dir, band).
The exploded tier is a read cache with a byte budget, not storage: a blob is written into it by the first reader that inflates it and unlinked from it when the budget says so. Both numbers are here because an operator asked to see a repository at its limit — an account at its budget still serves every object, only slower, and nothing else on the dashboard would say which repositories those are.
A metadata call per pool, no store lock. Empty for an engine with no
such tier.
Sourcepub fn open_object_counts(self) -> Vec<(PathBuf, u64)>
pub fn open_object_counts(self) -> Vec<(PathBuf, u64)>
Indexed objects of every open store, as (git_dir, count) — the
objects meter of Usage.Read, i.e. what this process is paying RAM
for (~382 B an object, measured). A closed store is absent, not zero.
Empty on the gix engine: it keeps no in-RAM object index per open store (its odb is mmapped pack indexes), so there is no per-object RAM price to report and reporting one would be a made-up bill.
Sourcepub fn set_explode_budget(self, git_dir: &Path, bytes: u64) -> usize
pub fn set_explode_budget(self, git_dir: &Path, bytes: u64) -> usize
Set the explode budget of every open repository under git_dir.
A prefix, so one call moves a whole account. Returns how many stores were changed — applied output, so a control plane that reached nothing (every repository closed) can say so instead of reporting success.
Sourcepub fn hold_no_graph_memo(self)
pub fn hold_no_graph_memo(self)
A twin keeps no derived memo (.nornir/twin-transaction-log.md C2): the znippy
engine’s persisted commit graph (objects.graph) is off for every store this process
opens from now on. Process-wide, because the box’s role is — called when stores open as
a twin and when a fresh box becomes one. The gix engine keeps no such file.
Sourcepub fn hold_twin_memory_bound(self)
pub fn hold_twin_memory_bound(self)
A twin holds no read cache and resolves narrow (twin-memory-bound, and lane T3’s
one-medium run): the znippy engine’s explode policy is off, its explode budget is
TWIN_EXPLODE_BUDGET_BYTES, and the indexer’s resolver runs TWIN_RESOLVE_WORKERS
wide with TWIN_RESOLVE_LOOKAHEAD_BYTES of lookahead, for every store this
process opens from now on. MEASURED: +36 MiB of RssAnon for a 512 MiB snapshot install
against a 64 MiB ceiling, against +149 MiB unbounded — and, with the policy left alone,
five objects.exploded files on a twin’s volume that a twin may not hold.
Process-wide, because the box’s role is. It is a SIBLING of
Engine::hold_no_graph_memo and not folded into it, because the two answer different
files (objects.graph against objects.exploded and the resolver’s heap) and a reader
who assumed the graph door covered the cache is exactly how the twin came to hold five
of them. The gix engine has neither.
Sourcepub fn bound_open_stores_to_twin(self) -> u64
pub fn bound_open_stores_to_twin(self) -> u64
And the stores already open when that happened — their exploded pools unlinked and capped, since a store keeps the policy it opened with. Returns the bytes unlinked.
Sourcepub fn drop_explode_cache(self, git_dir: &Path) -> u64
pub fn drop_explode_cache(self, git_dir: &Path) -> u64
repo gc reclaims the read cache: every lazily-exploded object
unlinked, the commit-and-tree pool kept because that is the graph.
Returns the bytes that left the filesystem.
Sourcepub fn ingest_push(
self,
git_dir: &Path,
hash_kind: Kind,
pack: &mut dyn BufRead,
objects: ObjectSet,
progress: Option<&dyn PackProgress>,
before_store: Option<BeforeStore<'_>>,
) -> Result<PushReceipt>
pub fn ingest_push( self, git_dir: &Path, hash_kind: Kind, pack: &mut dyn BufRead, objects: ObjectSet, progress: Option<&dyn PackProgress>, before_store: Option<BeforeStore<'_>>, ) -> Result<PushReceipt>
Take one pushed packfile straight into storage, off the wire.
The bytes go from the transport into the engine and are durable when this returns. Nothing is staged through a packfile on the way: a seam spelled in paths cannot express a server without them, which is why this one is spelled in bytes.
Everything but want_objects is engine-neutral and lives in
[ingest_common] — the pack header, the trailer and
GitOps::put_pack are the same
three facts whichever engine stored them. Enumerating the ids a push
introduced is not neutral: a pack entry carries no oid, so an engine
answers it out of its own index or not at all.
§progress, and why it is threaded rather than fetched
Some(sink) asks the engine to say how many objects of this pack it has
taken in while it is still taking them in
(GitOps::put_pack_observed).
The count belongs to the code that splits the pack and to nothing else —
deriving it anywhere on the way here means inflating every entry a second
time, which is a second pack decoder (one implementation) — so the only thing this
layer can do is carry the sink down and let the walk publish.
§before_store, and why the pushed pack is framed HERE
Called with exactly the bytes the engine is about to store, before it stores them — the
transaction log’s Pack frame (gunnar_core::txlog, the twin). This path opens the
engine by git_dir and never passes the OpenRepo::logged tee, so without it a pushed
pack was never a frame while its ref update was: MEASURED 2026-09-15 under KVM, the twin
and a restored primary both refused refs/heads/main would point at …, which this repository does not have. An error from the hook refuses the push before a byte lands.
None is not a degraded mode: a push over SSH or smart HTTP has no job
record and nobody polling one, so it asks for nothing and pays for
nothing. The mirror queue is the caller that has a console watching.
Sourcepub fn maintain(
self,
git_dir: &Path,
hash_kind: Kind,
) -> Result<MaintenanceReport>
pub fn maintain( self, git_dir: &Path, hash_kind: Kind, ) -> Result<MaintenanceReport>
gunnar gc for one repository: seal, then reclaim.
The order is the correctness argument rather than a preference. Sealing folds pending index work into the derived tables; reclaiming computes its live set out of those tables. Reclaiming first would judge liveness against a graph missing everything pushed since the last drain, and tombstone objects reachable only from those commits.
Only the znippy arm has a seal. The gix arm’s gc reads the packs and
the ref store directly, so there is no pending index work for a seal to
fold in, and it reports sections_sealed: 0 — which is the truth and not
a stub.
Trait Implementations§
impl Copy for Engine
impl Eq for Engine
impl StructuralPartialEq for Engine
Auto Trait Implementations§
impl Freeze for Engine
impl RefUnwindSafe for Engine
impl Send for Engine
impl Sync for Engine
impl Unpin for Engine
impl UnsafeUnpin for Engine
impl UnwindSafe for Engine
Blanket Implementations§
impl<T> Allocation for T
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request