fix(store): rustdoc hygiene + u64-safe cursor clamping
- resolve or unlink 25 preexisting rustdoc warnings: broken intra-doc links (error variants), public-docs-linking-private-items (crate-internal cursor/registry names), and one stale reference to a `Store::window_host` that never existed (the form branch is `sweep_window`'s engine-enum match) - `clamped` runs its arithmetic in u64 and narrows to usize after clamping, so a wide u64 offset can never wrap onto a small slice position on narrow-pointer targets; the cursor contract tests pin the overflowing-offset and overflowing-length forms - zero rustdoc warnings under RUSTDOCFLAGS=-D warnings Verification: cargo test (69+19+3 green), cargo test --all-features (124+54+4 green), cargo clippy --all-targets -- -D warnings green, cargo fmt --check green, RUSTDOCFLAGS=-D warnings cargo doc --no-deps green.
This commit is contained in:
1 parent
97cdf682c4
commit
611d30a3c4
6 files changed
+47
-28
No files matched your search
+19
-3
@@ -242,10 +242,16 @@ pub(crate) trait Backend: Send + Sync {
|
||||
/// EOF-clamping arithmetic of the cursor contract. Crate-internal: the
|
||||
/// engine cursor bodies behind [`Backend::Cursor`] compose this, so every
|
||||
/// engine's materializing and staging bodies clamp identically.
|
||||
///
|
||||
/// The arithmetic runs in `u64` — the offset/len domain — and narrows to
|
||||
/// `usize` only after clamping, so a truncated `as usize` cast can never
|
||||
/// wrap a huge offset back onto a small slice position on narrow-pointer
|
||||
/// targets.
|
||||
pub(crate) fn clamped(offset: u64, len: u64, total: usize) -> (usize, usize) {
|
||||
let start = (offset as usize).min(total);
|
||||
let end = start.saturating_add(len as usize).min(total);
|
||||
(start, end)
|
||||
let total = total as u64;
|
||||
let start = offset.min(total);
|
||||
let end = start.saturating_add(len).min(total);
|
||||
(start as usize, end as usize)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -333,6 +339,16 @@ mod tests {
|
||||
Vec::<u8>::new(),
|
||||
"read at EOF is empty, never an error"
|
||||
);
|
||||
assert_eq!(
|
||||
cursor.read_at(u64::MAX, 5).await.unwrap(),
|
||||
Vec::<u8>::new(),
|
||||
"an overflowing u64 offset clamps to EOF in u64 arithmetic — never wraps"
|
||||
);
|
||||
assert_eq!(
|
||||
cursor.read_at(0, u64::MAX).await.unwrap(),
|
||||
whole,
|
||||
"an overflowing u64 length clamps to the whole body"
|
||||
);
|
||||
assert_eq!(
|
||||
cursor.read_at(0, 0).await.unwrap(),
|
||||
Vec::<u8>::new(),
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
//! Size-threshold dispatch between the kv and large tiers (ADR-003):
|
||||
//! routing as a pure function of content length.
|
||||
//!
|
||||
//! **The routing seam the facade programs through.** [`route`] is the
|
||||
//! **The routing seam the facade programs through.** `route` is the
|
||||
//! pure function — `route(len, threshold) → Tier`, **at-or-below the
|
||||
//! threshold stays on the kv tier** (the boundary's pinned reading:
|
||||
//! store-put-paths' "≤ threshold → kv; > threshold → large") — and
|
||||
|
||||
+5
-4
@@ -3,11 +3,12 @@
|
||||
//! **One enum, both altitudes.** This is a *single* enum serving both
|
||||
//! altitudes of the crate's surface. The [`Backend`][crate::backend]
|
||||
//! trait's methods return this family but its *effective* members are
|
||||
//! [`Missing`], [`Verification`], [`Io`], and [`KeyInvalid`] — at the
|
||||
//! trait boundary, keys arrive opaque (so `KeyInvalid` never fires
|
||||
//! `Error::Missing`, `Error::Verification`, `Error::Io`, and
|
||||
//! `Error::KeyInvalid` — at the
|
||||
//! trait boundary, keys arrive opaque (so `Error::KeyInvalid` never fires
|
||||
//! there) and GC delete-arbitration answers flow up as data, not as
|
||||
//! errors (so `GcRefuse` never fires below the facade). The facade's
|
||||
//! public surface re-exposes this same family with [`GcRefuse`] added:
|
||||
//! errors (so `Error::GcRefuse` never fires below the facade). The facade's
|
||||
//! public surface re-exposes this same family with `Error::GcRefuse` added:
|
||||
//! the facade decides and owns the refusal. The altitude discipline is
|
||||
//! carried by doc comments and construction discipline, not by two
|
||||
//! separate types (named design point audited at the review gate;
|
||||
|
||||
+6
-5
@@ -17,7 +17,7 @@
|
||||
//! (`Error::Io` naming the path): a malformed list is as deadly as an
|
||||
//! incomplete one (ADR-003), and it is silent until a sweep deletes
|
||||
//! the wrong things. Only the engine's own staging directory
|
||||
//! ([`staging_dir`], excluded from the walk) is a known non-shard
|
||||
//! (`staging_dir`, excluded from the walk) is a known non-shard
|
||||
//! entry.
|
||||
//!
|
||||
//! **Concurrency posture:** every file operation — constructor,
|
||||
@@ -32,9 +32,10 @@
|
||||
//! **Stage hygiene (store-api.md invariant 3):** publish is the
|
||||
//! commit-rename; every failure path converges on discard with zero
|
||||
//! residue — a failed commit removes the stage file itself (there is
|
||||
//! no post-failure discard to drive), an explicit [`StagingCursor::discard`]
|
||||
//! removes it, and a staging cursor dropped without either is
|
||||
//! best-effort-cleaned by [`Drop`] (the engine's own cancellation
|
||||
//! no post-failure discard to drive), an explicit
|
||||
//! `StagingCursor::discard` removes it, and a staging cursor dropped
|
||||
//! without either is best-effort-cleaned by [`Drop`] (the engine's own
|
||||
//! cancellation
|
||||
//! story, per the wave-1 review's recorded observation; the hygiene
|
||||
//! tests below cover all three forms exactly). CAS is first-writer-wins
|
||||
//! everywhere a publish meets an existing entry: the committed file for
|
||||
@@ -43,7 +44,7 @@
|
||||
//!
|
||||
//! The `#![allow(dead_code)]` below marks the narrow remaining scope:
|
||||
//! in default builds (no `mem`) nothing constructs the engine, so
|
||||
//! [`LocalBackend::new`]/the staged-put bodies have no caller until
|
||||
//! `LocalBackend::new`/the staged-put bodies have no caller until
|
||||
//! wave 3's facade constructors and `store-put-paths` name them.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! **Schema (POC #5 finding B5's row shape adapted to sqlite):**
|
||||
//! `blobs (key BLOB PRIMARY KEY, value BLOB, size INTEGER NOT NULL)`.
|
||||
//! The dedicated `size` column is what makes [`Backend::size`]
|
||||
//! The dedicated `size` column is what makes `Backend::size`
|
||||
//! metadata-only — `SELECT size … WHERE key = ?` rides the key's index
|
||||
//! and never loads the value blob (ADR-008's size discipline;
|
||||
//! plan-tested below). `has` is an EXISTS probe, never a value load.
|
||||
|
||||
+15
-14
@@ -19,8 +19,8 @@
|
||||
//! would leak engine types through the public surface, force consumers
|
||||
//! to name engines they must never see (the facade is **engine-blind**,
|
||||
//! ADR-007/008/010), or push `dyn` onto the surface. The concrete type
|
||||
//! holds two crate-internal engine-holding enums ([`KvEngine`],
|
||||
//! [`LargeEngine`]) dispatching over the closed five-engine set; the
|
||||
//! holds two crate-internal engine-holding enums (`KvEngine`,
|
||||
//! `LargeEngine`) dispatching over the closed five-engine set; the
|
||||
//! conformance factory's binding note anticipated exactly this collapse
|
||||
//! (tests/conformance/factory.rs — "most plausibly the associated type
|
||||
//! collapsing to the concrete facade type across all factories"). The
|
||||
@@ -34,7 +34,7 @@
|
||||
//! **Constructor modes** (ADR-011 §4; ADR-012 §6.3):
|
||||
//!
|
||||
//! - **dual-tier** (the default): kv + large, size-threshold dispatch
|
||||
//! via [`crate::dispatch::route`]. The wave-2 constructible shape is
|
||||
//! via `crate::dispatch::route`. The wave-2 constructible shape is
|
||||
//! `kv = mem` + `large = local` — the dispatch-coverage test shape
|
||||
//! ADR-012 §6.3 names (both tiers load-bearing); the wave-3
|
||||
//! constructible shape is `kv = sqlite` + `large = local` — the
|
||||
@@ -61,9 +61,9 @@
|
||||
//! **Read-path design points (recorded for the review gate):**
|
||||
//!
|
||||
//! - **The fall-through general rule (ADR-012 §6.1; POC #1 finding
|
||||
//! 6).** Every key-addressed op consults [`KvEngine`] first, then
|
||||
//! [`LargeEngine`] — there is no length routing on the read side and
|
||||
//! [`Store::tier_for`] is never consulted by it (the dispatch seam's
|
||||
//! 6).** Every key-addressed op consults `KvEngine` first, then
|
||||
//! `LargeEngine` — there is no length routing on the read side and
|
||||
//! `Store::tier_for` is never consulted by it (the dispatch seam's
|
||||
//! write-half routing is the put path's; `route` feeds nothing on
|
||||
//! reads). A miss on both tiers resolves per op's shape: `Ok(None)`
|
||||
//! on get/stat, `false` on has, `Err(Missing)` on read_range.
|
||||
@@ -71,14 +71,14 @@
|
||||
//! returns the pinned `(len, stream)` shape as
|
||||
//! `Option<(u64, Blob)>` (store-api.md §Read path) — [`Blob`] is a
|
||||
//! bounded, re-entrant windowed reader over the crate-internal
|
||||
//! [`AnyCursor`], which dispatches the engine cursor bodies by tier
|
||||
//! `AnyCursor`, which dispatches the engine cursor bodies by tier
|
||||
//! (mem's materializing body for kv, `local`'s pread body for
|
||||
//! large). Windowed reads are the uniform stream shape across
|
||||
//! tiers; no chunk-iterator machinery was adopted — the cursor
|
||||
//! bodies *are* the streaming abstraction, and per-chunk `Stream`-
|
||||
//! wrapping would re-shape them without changing the underlying
|
||||
//! reads. Engine cursors never leak onto the public surface:
|
||||
//! [`AnyCursor`] is `pub(crate)`, `Blob` is opaque but drivable
|
||||
//! `AnyCursor` is `pub(crate)`, `Blob` is opaque but drivable
|
||||
//! (constructed only by the store core, ADR-010 §1).
|
||||
//! - **Verification-on-get (named design point, pinned against
|
||||
//! ADR-006's text).** The whole-blob hash-check fires where the
|
||||
@@ -190,11 +190,12 @@
|
||||
//! machinery.
|
||||
//!
|
||||
//! **The dispatch seam the ops tasks program through:** tier selection
|
||||
//! for a given length ([`Store::tier_for`] composing
|
||||
//! [`crate::dispatch::route`] per mode), the fall-through consult
|
||||
//! for a given length (`Store::tier_for` composing
|
||||
//! `crate::dispatch::route` per mode), the fall-through consult
|
||||
//! order — **kv first, then large** — that every key-addressed op
|
||||
//! consumes (ADR-012 §6.1's general rule; [`Store::kv`] then
|
||||
//! [`Store::large`]), and the GC state home ([`crate::gc::GcHome`])
|
||||
//! consumes (ADR-012 §6.1's general rule; `Store::kv` then
|
||||
//! `Store::large`), and the GC state home (`GcHome`,
|
||||
//! crate-internal)
|
||||
//! the gc-protocol task fills.
|
||||
//!
|
||||
//! **The durable delete window hosts on the kv engine when it is
|
||||
@@ -208,7 +209,7 @@
|
||||
//! form**, ADR-008 §2 staged re-arbitrated delete; ADR-012 §6.7 the
|
||||
//! executor is the next sweep) stages its candidates on the kv engine
|
||||
//! the constructor built. The form branch keys off the engine
|
||||
//! representation ([`Store::window_host`] — one kv-engine-enum match
|
||||
//! representation (`sweep_window`'s one kv-engine-enum match
|
||||
//! arm, never a flag): the durable form runs where the host is
|
||||
//! SQL-backed, the inline form verbatim on mem/local, so wave 5's
|
||||
//! pg-lo dormancy (the dual-SQL instance's large-engine window clauses
|
||||
@@ -275,7 +276,7 @@ pub const DEFAULT_DELETE_WINDOW_DELAY: Duration = Duration::from_secs(5 * 60);
|
||||
/// Engine-blind by construction: the engines are held in crate-internal
|
||||
/// enums dispatched statically (see the module's engine-representation
|
||||
/// design point); consumers name modes only. The GC state home
|
||||
/// ([`crate::gc::GcHome`]) rides as a field — the store instance owns
|
||||
/// (`GcHome`, crate-internal) rides as a field — the store instance owns
|
||||
/// all GC state (ADR-010 §2), which the gc-protocol task fills.
|
||||
pub struct Store {
|
||||
/// The kv-tier engine — the first consult in every fall-through.
|
||||
|
||||
Reference in new issue
Block a user