pub struct ExplodedCache { /* private fields */ }Expand description
The two pools, one door. Everything that used to call an
ExplodedArchive calls this instead; the eager pool is an
ExplodedArchive and behaves exactly as it did.
Implementations§
Source§impl ExplodedCache
impl ExplodedCache
Sourcepub fn open(base: &Path, policy: ExplodePolicy, budget: u64) -> Result<Self>
pub fn open(base: &Path, policy: ExplodePolicy, budget: u64) -> Result<Self>
Open both pools at base (…/objects.exploded), adopting whatever
lazy segments a previous process left beside it.
Sourcepub fn registered(self: Arc<Self>) -> Arc<Self> ⓘ
pub fn registered(self: Arc<Self>) -> Arc<Self> ⓘ
Register this cache so a dashboard tick can read every open store’s
band without holding a store lock — the same Weak registry
crate::progress keeps, for the same reason and with the same sweep.
pub fn root(&self) -> &str
Sourcepub fn set_budget(&self, bytes: u64)
pub fn set_budget(&self, bytes: u64)
The quota, changed live — what the control plane sets when an account’s plan changes. Takes effect at the next rotation; it never refuses a write and never deletes on the caller’s thread.
Sourcepub fn set_global_line(&self, bytes: u64)
pub fn set_global_line(&self, bytes: u64)
The process-wide line this cache holds itself to its fair share of.
0 turns the global check off. Tests set it small; production takes
default_global_line at open.
Sourcepub fn set_disk_line_percent(&self, percent: u64)
pub fn set_disk_line_percent(&self, percent: u64)
The disk line, changed live. 0 turns it off. Takes effect at the next
rotation, like the budget.
Sourcepub fn pressure_refused_write_backs(&self) -> u64
pub fn pressure_refused_write_backs(&self) -> u64
Write-backs refused while the disk line was latched.
pub fn budget(&self) -> u64
pub fn policy(&self) -> ExplodePolicy
pub fn path(&self) -> &Path
Sourcepub fn explode(
&self,
oid: &[u8],
kind: GitObjectKind,
payload: &[u8],
) -> Result<()>
pub fn explode( &self, oid: &[u8], kind: GitObjectKind, payload: &[u8], ) -> Result<()>
The eager write — the indexer’s sink, at push time. Unchanged behaviour: the policy decides, and what it declines is counted as skipped rather than silently dropped.
pub fn explode_at( &self, oid: &[u8], kind: GitObjectKind, mode: Option<u32>, path: Option<&str>, payload: &[u8], ) -> Result<()>
Sourcepub fn write_back(
&self,
oid: &[u8],
kind: GitObjectKind,
payload: &[u8],
cost: ReadCost,
) -> Result<bool>
pub fn write_back( &self, oid: &[u8], kind: GitObjectKind, payload: &[u8], cost: ReadCost, ) -> Result<bool>
The lazy write-back — one object a reader has just inflated from the pack, kept for the next reader.
Buffers only: it appends to the newest segment’s in-memory rows and
returns. Nothing is written, nothing is fsynced, no eviction runs. The
reader that called it has its bytes already and is not made to wait for
anybody — Self::maintain does the I/O on the store’s own thread.
Two readers racing on one oid is benign: the same bytes are buffered
twice and the newest row wins, which is what
ExplodedArchive::explode_at already promises.
Sourcepub fn maintain(&self) -> Result<u64>
pub fn maintain(&self) -> Result<u64>
Write down what is buffered, rotate if the newest segment is full, and evict until the pools fit the budget. The whole of the tier’s I/O, on one thread that is nobody’s reader.
Returns the bytes reclaimed, so a caller can log applied output rather than an intention.
Sourcepub fn content(&self, oid: &[u8]) -> Result<Option<(GitObjectKind, Vec<u8>)>>
pub fn content(&self, oid: &[u8]) -> Result<Option<(GitObjectKind, Vec<u8>)>>
The object’s kind and bytes from either pool, or None — fall back and
re-derive, never wrong.
Eager first: it is the smaller table, its index is the one already warm, and under the shipped policy it holds exactly the objects a graph walk asks for. Then the lazy segments newest first, so a re-entered object is found before the stale copy an older segment may still hold.
pub fn has(&self, oid: &[u8]) -> Result<bool>
pub fn name(&self, oid: &[u8]) -> Result<Option<(Option<u32>, Option<String>)>>
Sourcepub fn of_kind(&self, kind: GitObjectKind) -> Result<Vec<(Vec<u8>, Vec<u8>)>>
pub fn of_kind(&self, kind: GitObjectKind) -> Result<Vec<(Vec<u8>, Vec<u8>)>>
Every oid of one kind, across both pools, newest spelling winning.
The graph fold’s input. Under the shipped policy every commit is in the eager pool, so this is one table’s scan and the lazy segments add nothing — but it unions rather than assuming that, because a store opened under a different policy must still fold a whole graph.
Sourcepub fn retain(&self, live: &dyn Fn(&[u8]) -> bool) -> Result<u64>
pub fn retain(&self, live: &dyn Fn(&[u8]) -> bool) -> Result<u64>
Retire every oid live rejects — in both pools.
Both, and that is not defensive: a tombstone written only into the eager
pool would leave the lazy pool’s row live, content would fall through
to it, and a gc’d object would come back by the second door. That is
the same defect
a_wholly_dead_pack_does_not_come_back_when_the_store_is_reopened found
the first time, one pool along.
Sourcepub fn drop_cache(&self) -> Result<u64>
pub fn drop_cache(&self) -> Result<u64>
repo gc reclaims the cache. Every lazy segment is unlinked; the
eager pool keeps its rows, because they are the graph. Returns the bytes
that left the filesystem.
pub fn flush(&self) -> Result<()>
Sourcepub fn drop_caches(&self)
pub fn drop_caches(&self)
What the memory watchdog reaches for: every derived, rebuildable structure in every pool.
pub fn rows(&self) -> Result<u64>
Sourcepub fn eager_rows(&self) -> Result<u64>
pub fn eager_rows(&self) -> Result<u64>
Rows in the EAGER pool only — what adopt_journal compares against the
index, because the lazy pool’s size is a function of what has been read
and says nothing about whether a pack was absorbed.
pub fn disk_bytes(&self) -> u64
pub fn use_now(&self) -> CacheUse
pub fn note_rederived(&self)
pub fn pread_served(&self) -> u64
pub fn skipped(&self) -> u64
Sourcepub fn engine_stats(&self) -> ExplodedStats
pub fn engine_stats(&self) -> ExplodedStats
The engine-wide counters, summed over both pools, so no caller can tell the two apart by its instruments.
Sourcepub fn kick(self: &Arc<Self>)
pub fn kick(self: &Arc<Self>)
Start the write-back thread if one is not already running — and return to the reader immediately either way.
Rickard’s law, from the design note: nobody waits. The reader already has its bytes; the append, the fsync, the rotation and the eviction all happen here, on a thread that is nobody’s request. A thread per 4 MiB of write-back rather than a parked thread per store, because a box holding 1 200 open repositories (lane V) cannot afford 1 200 idle threads and can easily afford one spawn per few thousand objects read.
The flag is the whole of the mutual exclusion: a second reader finding it set does nothing, and the running thread loops until the buffer is empty before clearing it, so no work is dropped between the two.