Skip to content

Polish bundle: validation, BufWriter WAL, durability mode, spec-aligned routes - #6

Merged
pbudzik merged 1 commit into
mainfrom
feat/polish-bundle
May 16, 2026
Merged

Polish bundle: validation, BufWriter WAL, durability mode, spec-aligned routes#6
pbudzik merged 1 commit into
mainfrom
feat/polish-bundle

Conversation

@pbudzik

@pbudzik pbudzik commented May 16, 2026

Copy link
Copy Markdown
Owner

Summary

Knocks out the long tail of small review items in a single PR. After this, the codebase is in a clean state where the only remaining moves are performance work (per-column encodings, block metadata) or testing infrastructure (proptest invariants).

What's in

Test plan

  • cargo build --all-targets clean with -D warnings
  • cargo test --all-targets — 37 tests pass (was 32; +5 validation unit tests)
  • CI green

Still on the backlog

  • Per-column dictionary / delta / RLE encodings (the format reserves discriminants)
  • Block-level metadata for in-segment skipping
  • Rollup segment columnar format
  • DurabilityMode::Balanced (group commit)
  • proptest property tests for spec §19 invariants

🤖 Generated with Claude Code

…ed routes

Closes a long tail of small review items in a single PR.

#14 Event validation. handle_ingest now runs each event through
validate_event before WAL append: rejects empty event_id, account_id,
product_id, meter_id; non-positive timestamp_ms; >16 dimensions
(spec §21); Correction/Retraction without correction_ref. Rejected
events never reach the WAL or dedupe. IngestBatchResponse.rejected
is finally a real count, surfacing collector bugs that previously
went silent. 5 unit tests cover the rules.

#17 Buffered WAL. Wal.file becomes BufWriter<File>. writeln!
coalesces in userspace; sync() flushes then fsyncs; rotate flushes
+ fsyncs the sealed file before swapping. Throughput win for
small-batch ingest with no change to durability semantics in Strict
mode.

#18 Durability mode. New Config.durability_mode: DurabilityMode
enum (Strict | Fast). Strict (default) is the previous flush+fsync
behavior. Fast does flush-only — bytes reach the page cache but no
disk round-trip — for at-least-once upstream pipelines that tolerate
losing the tail batch on host crash. Balanced (group commit) is
documented as future work.

#19 Endpoint paths aligned with spec.
- POST /v1/usage/batch (was /v1/ingest)
- GET /v1/accounts/:account_id/usage with query params from/to/group_by/
  product_id/meter_id/model_id/source (§12.2 monthly usage path)
- GET /v1/accounts/:account_id/usage/events for raw audit (§12.3)
- POST /v1/query/json and /v1/query/sql kept for flexible callers

#20 ingested_at_ms consistency. The ingest handler now overwrites
event.ingested_at_ms with server-side now_ms() before hashing and
WAL persistence, so a client with a wrong clock can't poison the
dedupe TTL eviction. Replay still uses the persisted (server-stamped)
value, so live and replayed entries are consistent.

#21 evict_expired simplification. The "Only remove if entry hasn't
been replaced" branch was unreachable since cache entries are never
updated — drop both unconditionally when past the cutoff.

#22 Drop unused parking_lot from Cargo.toml.

#23 Zero clones on the accepted ingest path. wal.append_batch now
takes IntoIterator<Item = &UsageEvent> so the handler can stream
refs from new_events.iter() without building an intermediate Vec
of clones. Memtable insertion moves the event by value.

#16 Manifest fsync portability. Switch from fs::write + reopened-RO
fsync (Linux-only contract) to the standard recipe: open + write +
sync_all on a single fd, drop, rename, parent dir fsync.

README updated. 37/37 tests pass (was 32; +5 validation unit tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pbudzik
pbudzik merged commit 19630c5 into main May 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant