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
|
/// EOF-clamping arithmetic of the cursor contract. Crate-internal: the
|
||||||
/// engine cursor bodies behind [`Backend::Cursor`] compose this, so every
|
/// engine cursor bodies behind [`Backend::Cursor`] compose this, so every
|
||||||
/// engine's materializing and staging bodies clamp identically.
|
/// 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) {
|
pub(crate) fn clamped(offset: u64, len: u64, total: usize) -> (usize, usize) {
|
||||||
let start = (offset as usize).min(total);
|
let total = total as u64;
|
||||||
let end = start.saturating_add(len as usize).min(total);
|
let start = offset.min(total);
|
||||||
(start, end)
|
let end = start.saturating_add(len).min(total);
|
||||||
|
(start as usize, end as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -333,6 +339,16 @@ mod tests {
|
|||||||
Vec::<u8>::new(),
|
Vec::<u8>::new(),
|
||||||
"read at EOF is empty, never an error"
|
"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!(
|
assert_eq!(
|
||||||
cursor.read_at(0, 0).await.unwrap(),
|
cursor.read_at(0, 0).await.unwrap(),
|
||||||
Vec::<u8>::new(),
|
Vec::<u8>::new(),
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
//! Size-threshold dispatch between the kv and large tiers (ADR-003):
|
//! Size-threshold dispatch between the kv and large tiers (ADR-003):
|
||||||
//! routing as a pure function of content length.
|
//! 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
|
//! pure function — `route(len, threshold) → Tier`, **at-or-below the
|
||||||
//! threshold stays on the kv tier** (the boundary's pinned reading:
|
//! threshold stays on the kv tier** (the boundary's pinned reading:
|
||||||
//! store-put-paths' "≤ threshold → kv; > threshold → large") — and
|
//! 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
|
//! **One enum, both altitudes.** This is a *single* enum serving both
|
||||||
//! altitudes of the crate's surface. The [`Backend`][crate::backend]
|
//! altitudes of the crate's surface. The [`Backend`][crate::backend]
|
||||||
//! trait's methods return this family but its *effective* members are
|
//! trait's methods return this family but its *effective* members are
|
||||||
//! [`Missing`], [`Verification`], [`Io`], and [`KeyInvalid`] — at the
|
//! `Error::Missing`, `Error::Verification`, `Error::Io`, and
|
||||||
//! trait boundary, keys arrive opaque (so `KeyInvalid` never fires
|
//! `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
|
//! there) and GC delete-arbitration answers flow up as data, not as
|
||||||
//! errors (so `GcRefuse` never fires below the facade). The facade's
|
//! errors (so `Error::GcRefuse` never fires below the facade). The facade's
|
||||||
//! public surface re-exposes this same family with [`GcRefuse`] added:
|
//! public surface re-exposes this same family with `Error::GcRefuse` added:
|
||||||
//! the facade decides and owns the refusal. The altitude discipline is
|
//! the facade decides and owns the refusal. The altitude discipline is
|
||||||
//! carried by doc comments and construction discipline, not by two
|
//! carried by doc comments and construction discipline, not by two
|
||||||
//! separate types (named design point audited at the review gate;
|
//! 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
|
//! (`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
|
//! incomplete one (ADR-003), and it is silent until a sweep deletes
|
||||||
//! the wrong things. Only the engine's own staging directory
|
//! 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.
|
//! entry.
|
||||||
//!
|
//!
|
||||||
//! **Concurrency posture:** every file operation — constructor,
|
//! **Concurrency posture:** every file operation — constructor,
|
||||||
@@ -32,9 +32,10 @@
|
|||||||
//! **Stage hygiene (store-api.md invariant 3):** publish is the
|
//! **Stage hygiene (store-api.md invariant 3):** publish is the
|
||||||
//! commit-rename; every failure path converges on discard with zero
|
//! commit-rename; every failure path converges on discard with zero
|
||||||
//! residue — a failed commit removes the stage file itself (there is
|
//! residue — a failed commit removes the stage file itself (there is
|
||||||
//! no post-failure discard to drive), an explicit [`StagingCursor::discard`]
|
//! no post-failure discard to drive), an explicit
|
||||||
//! removes it, and a staging cursor dropped without either is
|
//! `StagingCursor::discard` removes it, and a staging cursor dropped
|
||||||
//! best-effort-cleaned by [`Drop`] (the engine's own cancellation
|
//! without either is best-effort-cleaned by [`Drop`] (the engine's own
|
||||||
|
//! cancellation
|
||||||
//! story, per the wave-1 review's recorded observation; the hygiene
|
//! story, per the wave-1 review's recorded observation; the hygiene
|
||||||
//! tests below cover all three forms exactly). CAS is first-writer-wins
|
//! tests below cover all three forms exactly). CAS is first-writer-wins
|
||||||
//! everywhere a publish meets an existing entry: the committed file for
|
//! 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:
|
//! The `#![allow(dead_code)]` below marks the narrow remaining scope:
|
||||||
//! in default builds (no `mem`) nothing constructs the engine, so
|
//! 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.
|
//! wave 3's facade constructors and `store-put-paths` name them.
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
//!
|
//!
|
||||||
//! **Schema (POC #5 finding B5's row shape adapted to sqlite):**
|
//! **Schema (POC #5 finding B5's row shape adapted to sqlite):**
|
||||||
//! `blobs (key BLOB PRIMARY KEY, value BLOB, size INTEGER NOT NULL)`.
|
//! `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
|
//! metadata-only — `SELECT size … WHERE key = ?` rides the key's index
|
||||||
//! and never loads the value blob (ADR-008's size discipline;
|
//! and never loads the value blob (ADR-008's size discipline;
|
||||||
//! plan-tested below). `has` is an EXISTS probe, never a value load.
|
//! 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
|
//! would leak engine types through the public surface, force consumers
|
||||||
//! to name engines they must never see (the facade is **engine-blind**,
|
//! 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
|
//! ADR-007/008/010), or push `dyn` onto the surface. The concrete type
|
||||||
//! holds two crate-internal engine-holding enums ([`KvEngine`],
|
//! holds two crate-internal engine-holding enums (`KvEngine`,
|
||||||
//! [`LargeEngine`]) dispatching over the closed five-engine set; the
|
//! `LargeEngine`) dispatching over the closed five-engine set; the
|
||||||
//! conformance factory's binding note anticipated exactly this collapse
|
//! conformance factory's binding note anticipated exactly this collapse
|
||||||
//! (tests/conformance/factory.rs — "most plausibly the associated type
|
//! (tests/conformance/factory.rs — "most plausibly the associated type
|
||||||
//! collapsing to the concrete facade type across all factories"). The
|
//! collapsing to the concrete facade type across all factories"). The
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
//! **Constructor modes** (ADR-011 §4; ADR-012 §6.3):
|
//! **Constructor modes** (ADR-011 §4; ADR-012 §6.3):
|
||||||
//!
|
//!
|
||||||
//! - **dual-tier** (the default): kv + large, size-threshold dispatch
|
//! - **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
|
//! `kv = mem` + `large = local` — the dispatch-coverage test shape
|
||||||
//! ADR-012 §6.3 names (both tiers load-bearing); the wave-3
|
//! ADR-012 §6.3 names (both tiers load-bearing); the wave-3
|
||||||
//! constructible shape is `kv = sqlite` + `large = local` — the
|
//! constructible shape is `kv = sqlite` + `large = local` — the
|
||||||
@@ -61,9 +61,9 @@
|
|||||||
//! **Read-path design points (recorded for the review gate):**
|
//! **Read-path design points (recorded for the review gate):**
|
||||||
//!
|
//!
|
||||||
//! - **The fall-through general rule (ADR-012 §6.1; POC #1 finding
|
//! - **The fall-through general rule (ADR-012 §6.1; POC #1 finding
|
||||||
//! 6).** Every key-addressed op consults [`KvEngine`] first, then
|
//! 6).** Every key-addressed op consults `KvEngine` first, then
|
||||||
//! [`LargeEngine`] — there is no length routing on the read side and
|
//! `LargeEngine` — there is no length routing on the read side and
|
||||||
//! [`Store::tier_for`] is never consulted by it (the dispatch seam's
|
//! `Store::tier_for` is never consulted by it (the dispatch seam's
|
||||||
//! write-half routing is the put path's; `route` feeds nothing on
|
//! 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)`
|
//! reads). A miss on both tiers resolves per op's shape: `Ok(None)`
|
||||||
//! on get/stat, `false` on has, `Err(Missing)` on read_range.
|
//! on get/stat, `false` on has, `Err(Missing)` on read_range.
|
||||||
@@ -71,14 +71,14 @@
|
|||||||
//! returns the pinned `(len, stream)` shape as
|
//! returns the pinned `(len, stream)` shape as
|
||||||
//! `Option<(u64, Blob)>` (store-api.md §Read path) — [`Blob`] is a
|
//! `Option<(u64, Blob)>` (store-api.md §Read path) — [`Blob`] is a
|
||||||
//! bounded, re-entrant windowed reader over the crate-internal
|
//! 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
|
//! (mem's materializing body for kv, `local`'s pread body for
|
||||||
//! large). Windowed reads are the uniform stream shape across
|
//! large). Windowed reads are the uniform stream shape across
|
||||||
//! tiers; no chunk-iterator machinery was adopted — the cursor
|
//! tiers; no chunk-iterator machinery was adopted — the cursor
|
||||||
//! bodies *are* the streaming abstraction, and per-chunk `Stream`-
|
//! bodies *are* the streaming abstraction, and per-chunk `Stream`-
|
||||||
//! wrapping would re-shape them without changing the underlying
|
//! wrapping would re-shape them without changing the underlying
|
||||||
//! reads. Engine cursors never leak onto the public surface:
|
//! 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).
|
//! (constructed only by the store core, ADR-010 §1).
|
||||||
//! - **Verification-on-get (named design point, pinned against
|
//! - **Verification-on-get (named design point, pinned against
|
||||||
//! ADR-006's text).** The whole-blob hash-check fires where the
|
//! ADR-006's text).** The whole-blob hash-check fires where the
|
||||||
@@ -190,11 +190,12 @@
|
|||||||
//! machinery.
|
//! machinery.
|
||||||
//!
|
//!
|
||||||
//! **The dispatch seam the ops tasks program through:** tier selection
|
//! **The dispatch seam the ops tasks program through:** tier selection
|
||||||
//! for a given length ([`Store::tier_for`] composing
|
//! for a given length (`Store::tier_for` composing
|
||||||
//! [`crate::dispatch::route`] per mode), the fall-through consult
|
//! `crate::dispatch::route` per mode), the fall-through consult
|
||||||
//! order — **kv first, then large** — that every key-addressed op
|
//! order — **kv first, then large** — that every key-addressed op
|
||||||
//! consumes (ADR-012 §6.1's general rule; [`Store::kv`] then
|
//! consumes (ADR-012 §6.1's general rule; `Store::kv` then
|
||||||
//! [`Store::large`]), and the GC state home ([`crate::gc::GcHome`])
|
//! `Store::large`), and the GC state home (`GcHome`,
|
||||||
|
//! crate-internal)
|
||||||
//! the gc-protocol task fills.
|
//! the gc-protocol task fills.
|
||||||
//!
|
//!
|
||||||
//! **The durable delete window hosts on the kv engine when it is
|
//! **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
|
//! 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
|
//! executor is the next sweep) stages its candidates on the kv engine
|
||||||
//! the constructor built. The form branch keys off the 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
|
//! 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
|
//! 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
|
//! 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
|
/// Engine-blind by construction: the engines are held in crate-internal
|
||||||
/// enums dispatched statically (see the module's engine-representation
|
/// enums dispatched statically (see the module's engine-representation
|
||||||
/// design point); consumers name modes only. The GC state home
|
/// 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.
|
/// all GC state (ADR-010 §2), which the gc-protocol task fills.
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
/// The kv-tier engine — the first consult in every fall-through.
|
/// The kv-tier engine — the first consult in every fall-through.
|
||||||
|
|||||||
Reference in new issue
Block a user