feat(tests): the conformance suite's sqlite column — the durable-schedule SQL-backed column green (wave 3)
- The first SQL-backed column: the default-build production shape (kv = sqlite + large = local, feature sqlite default-on) runs the form-independent reference rows verbatim (INV-1, INV-6, the NoLivenessSources/ProtectFailed abort shapes, the kv-only rejection row against kv-only(sqlite)) and grows the durable-schedule sweep rows — exact counts asserted relative to the staged schedule (ADR-012 §6.7): two-sweep counts over the full protection set, the race across the window delay (a re-put landing during the window survives the executing sweep), the holder-stages-only lease shape, INV-5 through durable-schedule outcomes, and the schedule-relative INV-2/INV-3 readings - Dispatch rows mirror the local column's family with the placement oracle adapted by medium: the sqlite file's pool/window rows vs the root's committed files; virgin-store reads as no-ops on a fresh file (the no-tables-yet tolerance engine-instrumented, this row its facade form) - Factories: dual-tier sqlite+local and kv-only(sqlite), instance- tracked temp sites (fresh sqlite file + private root per open; idempotent panicking-row-safe teardown), the column-tuned threshold and the test window-delay tuning (Duration::ZERO — execute-on-next- sweep); the module is cfg(feature = "sqlite"), default-on — the column runs in every default cargo test, server-less, never skips - Shared fixtures moved to rows.rs (committed_file_count, staging_file_count, slice_digest, LatchProtect pub(crate)) so the columns share them without the mem gate - README: the schedule-relative reading for SQL-backed columns recorded (citing ADR-012 §6.7), the sqlite rows table inventory, Current state (three columns) Verification: cargo test (default) green — 69 lib + 19 conformance + 3 git-interop; cargo test --features mem green (124 lib + 54 conformance); cargo check --all-features --tests green; cargo clippy --all-targets -- -D warnings green; cargo fmt --check green.
This commit is contained in:
1 parent
fb8326c4d5
commit
3f8e8158a7
6 files changed
+2049
-67
No files matched your search
@@ -32,12 +32,14 @@
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::io::Cursor;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin as StdPin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use sha2::{Digest as _, Sha256};
|
||||
use tokio::io::{AsyncRead, ReadBuf};
|
||||
|
||||
use crate::factory::StoreFactory;
|
||||
@@ -111,9 +113,10 @@ impl ProtectCallback for SetProtect {
|
||||
/// A protect callback that blocks mid-consult — the fixture for the
|
||||
/// sweep-lease contended window: it announces its entry on a channel,
|
||||
/// waits on a second, then answers with an empty protection set.
|
||||
struct LatchProtect {
|
||||
entered: std::sync::mpsc::Sender<()>,
|
||||
release: Mutex<Option<std::sync::mpsc::Receiver<()>>>,
|
||||
/// `pub(crate)`: the suite's other columns reuse it.
|
||||
pub(crate) struct LatchProtect {
|
||||
pub(crate) entered: std::sync::mpsc::Sender<()>,
|
||||
pub(crate) release: Mutex<Option<std::sync::mpsc::Receiver<()>>>,
|
||||
}
|
||||
|
||||
impl ProtectCallback for LatchProtect {
|
||||
@@ -267,6 +270,57 @@ pub(crate) fn assert_exact_counts(report: &alkblobs::SweepReport) {
|
||||
);
|
||||
}
|
||||
|
||||
/// Every regular file under `root` outside any `staging` directory —
|
||||
/// the committed-tree counter of the medium-backed columns' on-disk
|
||||
/// placement oracle. With a kv tier that never touches this disk it is
|
||||
/// exactly one per committed large-tier entry; a SQL-backed kv tier
|
||||
/// distinguishes by medium instead (its entries live in the database
|
||||
/// file, so this count is still exactly the large tier's residency).
|
||||
/// `pub(crate)`: the suite's other columns reuse it.
|
||||
pub(crate) fn committed_file_count(root: &Path) -> usize {
|
||||
fn walk(dir: &Path, out: &mut Vec<PathBuf>) {
|
||||
let Ok(entries) = std::fs::read_dir(dir) else {
|
||||
return;
|
||||
};
|
||||
for entry in entries.flatten() {
|
||||
let Ok(kind) = entry.file_type() else {
|
||||
continue;
|
||||
};
|
||||
let path = entry.path();
|
||||
if kind.is_dir() {
|
||||
if path.file_name().and_then(|n| n.to_str()) == Some("staging") {
|
||||
continue;
|
||||
}
|
||||
walk(&path, out);
|
||||
} else if kind.is_file() {
|
||||
out.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut files = Vec::new();
|
||||
walk(root, &mut files);
|
||||
files.len()
|
||||
}
|
||||
|
||||
/// Files in the large tier's staging area — the residue counter of the
|
||||
/// on-disk stage-hygiene exact-count form (zero after every failure
|
||||
/// form and every success form; a staged artifact lives there only
|
||||
/// mid-put). `pub(crate)`: the suite's other columns reuse it.
|
||||
pub(crate) fn staging_file_count(root: &Path) -> usize {
|
||||
match std::fs::read_dir(root.join("staging")) {
|
||||
Ok(entries) => entries.count(),
|
||||
Err(_) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// The ADR-006 slice digest, computed independently of the crate —
|
||||
/// SHA-256 over exactly the returned bytes (the out-of-band
|
||||
/// verification the convention requires; callers verify the same way).
|
||||
/// `pub(crate)`: the suite's other columns reuse it.
|
||||
pub(crate) fn slice_digest(bytes: &[u8]) -> [u8; 32] {
|
||||
Sha256::digest(bytes).into()
|
||||
}
|
||||
|
||||
/// INV-1: whole-blob put/get round-trips byte-identical under the
|
||||
/// canonical derivation — the content matrix loops both put paths
|
||||
/// (known-length, unknown-length) in-body; every put's key is the
|
||||
|
||||
Reference in new issue
Block a user