docs(arch): A-2 + A-6 — async-trait trait family, pinned execution model
Resolves review 001 findings A-2 (critical) and A-6 (major) — the same signature surface: - ADR-012 §1: registry traits amended to #[async_trait] (bare async fn in traits is not dyn-compatible, E0038; ops sit behind Arc<dyn GitRegistryStore>). Desugared boxed Future form pinned in OQ-03's freeze inventory. async-trait = "0.1" added to the manifest. - backend.md concurrency model: the five-trait family is #[async_trait] Send + Sync dyn-compatible; the wire layer enforces ADR-009's pipeline-concurrency budget itself (permit acquired around each GitPackGen/GitPackIngest call — the concrete admission point); impls must not block the async executor and own their internal threading (gix impls run spawn_blocking inside the impl — POC-2's shape restated at its true layer). - transport.md §fetch: spawn_blocking sentence rephrased to the trait-contract version (the wire spec stops speaking gix). - ADR-009: enforcement point of the blocking-pool budget made concrete. - ADR-013 §6: ingestion spawn_blocking line aligned. - review 001: A-2, A-6 marked resolved. Verification: cargo test, clippy -D warnings, fmt --check, doc --no-deps, check --no-default-features, check --all-features — all clean.
This commit is contained in:
1 parent
c4b9c53674
commit
d067cf558a
7 files changed
+55
-15
No files matched your search
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-09-25
|
||||
last_updated: 2026-09-29
|
||||
---
|
||||
|
||||
# Backend traits: the storage seam
|
||||
@@ -52,7 +52,8 @@ gix types:
|
||||
validated ref updates; the transaction itself is applied by `GitRefs`
|
||||
(single CAS home — ingest validates, refs commits; one transaction per
|
||||
push is what makes `atomic` correct — ADR-013 §7). Budgeted (ADR-009
|
||||
max pack size); blocking-thread friendly.
|
||||
max pack size); the impl runs its blocking work off the async
|
||||
executor (concurrency model below).
|
||||
|
||||
Minimal-vs-full was the open sub-question; resolved as **full family** —
|
||||
each trait is one or two methods plus types, and collapsing them (e.g.
|
||||
@@ -96,13 +97,31 @@ Two independent seams, two default-on features:
|
||||
## Concurrency model
|
||||
|
||||
- `gix` structures: `parking_lot` short-held locks; per-session handles
|
||||
moved into `spawn_blocking` tasks (POC-2's shape: store shared, handle
|
||||
per session, generation on blocking threads).
|
||||
and `spawn_blocking` live inside the gix impls (POC-2's shape: store
|
||||
shared, handle per session, generation on blocking threads).
|
||||
- Poisoned locks: `unwrap_or_else(|e| e.into_inner())` (convention 2).
|
||||
- The traits are `Send + Sync` object-safe; impls run under the
|
||||
adapter's tokio context. `GitRegistry::resolve` is async (one call per
|
||||
session/request, before the first protocol byte — ADR-011 §6); no
|
||||
sync-hot-path constraint exists here, unlike alkcall's accept loop.
|
||||
- **Trait execution model** (review 001 A-6): all five traits are
|
||||
`#[async_trait]` — `Send + Sync`, dyn-compatible (E0038 forbids bare
|
||||
`async fn`), signatures per ADR-012 §1. `GitRegistry::resolve` is
|
||||
async (one call per session/request, before the first protocol byte —
|
||||
ADR-011 §6); no sync-hot-path constraint exists here, unlike alkcall's
|
||||
accept loop. The execution model the signatures imply:
|
||||
- **The wire layer enforces the pipeline-concurrency budget itself**
|
||||
(ADR-009's "max concurrent blocking pipeline tasks" — a permit
|
||||
acquired in the wire layer around each `GitPackGen`/`GitPackIngest`
|
||||
call; the admission point of "enforced at assembly/acceptance
|
||||
time"). The wire layer is backend-trait-only (ADR-010) and knows
|
||||
nothing of stores, handles, or threads — so the permit, not
|
||||
`spawn_blocking`, is its entire concurrency contract.
|
||||
- **Implementations must not block the async executor** and own their
|
||||
internal threading: the gix impls run pack generation/ingestion on
|
||||
`spawn_blocking` with the owned handle moved in *inside the trait
|
||||
impl* (POC-2's shape, restated at its true layer — it is the impl's
|
||||
internal structure, invisible from the wire layer).
|
||||
- The traits are async so an embedder whose storage is async (DB
|
||||
registries, network object stores) implements them natively; the
|
||||
gix impl's blocking work is an internal detail, not part of the
|
||||
seam.
|
||||
|
||||
## Public API surface
|
||||
|
||||
|
||||
Reference in new issue
Block a user