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.
Introduce src/server/ as a streaming-first git/lfs server surface. All
request and response bodies cross the API as
Box<dyn AsyncRead + Unpin + Send + Sync> (alias BoxedAsyncRead) — no
Vec<u8> bodies, no read_to_end convenience, no http crate.
What's in the box:
- src/server/mod.rs: re-exports + pipe re-export of
command::cmd::DEFAULT_OUTPUT_CAP_BYTES as server::DEFAULT_OUTPUT_CAP_BYTES
- src/server/backend.rs: ServerBackend async-trait (authorize,
list_refs_stream, produce_pack_stream, ingest_pack_stream,
lfs_get_stream, lfs_put_stream). Every method currently returns
ServerError::Unimplemented("...") placeholders — the wiring is
real, the bodies are intentionally empty.
- src/server/request.rs: ServerRequest (not Clone, body is a boxed
reader), HeaderMap = HashMap<String, String>, RefUpdateBatch
(oid strings, no gix::ObjectId), BoxedAsyncRead alias
- src/server/stream.rs: StreamGuard (Clone + Send + Sync) carrying
cancel() / handle() so spawned workers can race the request
- src/server/endpoint.rs, error.rs, limits.rs: EndpointKind enum,
ServerError, DEFAULT_LFS_OBJECT_CAP_BYTES (5 GiB cap, separate from
the 64 MiB output cap)
- tests/server.rs: PlaceholderBackend skeleton + ENV_LOCK +
200 ms cancel convention reused from tests/env.rs and tests/pipe.rs
Public API impact on GitBaby:
- Drop pipe from GitBaby::new — the server owns its own stream
lifecycle, so the Pipe parameter is no longer required at
construction time. Existing callers must be updated:
- before: GitBaby::new(facade, pipe)
- after: GitBaby::new(facade)
Documentation:
- AGENTS.md gains a "Planned but unimplemented (streaming-first
server)" section documenting the deliberately-empty contracts so
future contributors don't "fill them in" without a concrete
git/lfs protocol task.
CI: cargo build + cargo test (61 total, 23 new from server suite)
green.