Two-part change:
1) Submodule split of src/cache/ (was a single ~150-line mod.rs)
- src/cache/config.rs: CacheConfig, defaults, default_cache_dir(),
DEFAULT_NAME / DEFAULT_MEMORY_CAPACITY_BYTES /
DEFAULT_DISK_CAPACITY_BYTES constants
- src/cache/key.rs: CacheKey / CacheValue type aliases and key
derivation helpers (rev -> oid, blob-exists negatives)
- src/cache/store.rs: CacheStore — the foyer HybridCache wrapper
(open / close / get / insert / remove / contains), all errors
mapped to BabyError::Cache with op-tagged source
- src/cache/pools.rs: CachePools — multi-store aggregator used by
the global singleton; replaces the old monolithic CacheStore
- src/cache/stats.rs: CacheStats + counter accessors
- src/cache/invalidation.rs: hook_ref_updated / hook_blob_written
(single-process invalidation hooks, fired from usecase impls)
- src/cache/mod.rs: now just submodule re-exports of
(config, global, invalidation, key, pools, stats, store)
- src/cache/global.rs: GITBABY_CACHE singleton + init / try /
shutdown now operate on Arc<CachePools> instead of Arc<CacheStore>
2) Cache integration in usecase modules
- src/blob/usecase.rs: read paths go through cache.get / insert;
invalidation hooks fire on write
- src/commit/usecase.rs: commit-list results cached, invalidated on
commit write
- src/branch/usecase.rs: branch-list results cached, invalidated on
ref update
- src/refs/usecase.rs: lookup-cache + ref-update hook
- src/tags/usecase.rs: tag-info cache + write hook
3) AGENTS.md
- Document that cached serde payloads (CommitInfo, Vec<TreeEntry>,
etc.) follow additive-only compatibility: never rename/remove a
field, every new field gets #[serde(default)] so stale payloads
still deserialize.
- Note that the foyer cache is single-process: fixed on-disk dir
per config + in-process invalidation hooks. Sharing across
processes on the same repo can leave stale metadata; do not do
that.
CI: cargo build + cargo test (61 passed) green.
BREAKING: the public cache surface moved. Anyone reaching into
cache::CacheStore directly should switch to cache::CachePools (or
cache::global::try_global_cache). The high-level helpers in
cache::global keep the same name; only the inner type changed.
55 lines
1.6 KiB
Rust
55 lines
1.6 KiB
Rust
use std::sync::{Arc, LazyLock, Mutex};
|
|
|
|
use crate::cache::{CacheConfig, CachePools};
|
|
use crate::error::BabyError;
|
|
|
|
pub static GITBABY_CACHE: LazyLock<Mutex<Option<Arc<CachePools>>>> =
|
|
LazyLock::new(|| Mutex::new(None));
|
|
|
|
pub fn try_global_cache() -> Option<Arc<CachePools>> {
|
|
let guard = GITBABY_CACHE.lock().ok()?;
|
|
guard.clone()
|
|
}
|
|
|
|
pub fn init_global_cache(cfg: CacheConfig) -> Result<Arc<CachePools>, BabyError> {
|
|
let rt = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.map_err(|source| {
|
|
BabyError::Custom(format!(
|
|
"build one-shot tokio runtime for init_global_cache: {}",
|
|
source
|
|
))
|
|
})?;
|
|
let pools = rt.block_on(CachePools::open(cfg))?;
|
|
install(pools)
|
|
}
|
|
|
|
pub async fn init_global_cache_async(cfg: CacheConfig) -> Result<Arc<CachePools>, BabyError> {
|
|
let pools = CachePools::open(cfg).await?;
|
|
install(pools)
|
|
}
|
|
|
|
fn install(pools: Arc<CachePools>) -> Result<Arc<CachePools>, BabyError> {
|
|
let mut guard = GITBABY_CACHE
|
|
.lock()
|
|
.map_err(|source| BabyError::Custom(format!("global cache mutex poisoned: {}", source)))?;
|
|
*guard = Some(pools.clone());
|
|
Ok(pools)
|
|
}
|
|
|
|
pub async fn shutdown_global_cache() -> Result<(), BabyError> {
|
|
let pools = {
|
|
let mut guard = GITBABY_CACHE.lock().map_err(|source| {
|
|
BabyError::Custom(format!("global cache mutex poisoned: {}", source))
|
|
})?;
|
|
guard.take()
|
|
};
|
|
if let Some(pools) = pools
|
|
&& Arc::strong_count(&pools) == 1
|
|
{
|
|
pools.close().await?;
|
|
}
|
|
Ok(())
|
|
}
|