Skip to content

test(bench): streaming corpus store builds + opt-in log4j severity - #350

Merged
jensholdgaard merged 7 commits into
mainfrom
bench-streaming-corpus
Jul 4, 2026
Merged

test(bench): streaming corpus store builds + opt-in log4j severity#350
jensholdgaard merged 7 commits into
mainfrom
bench-streaming-corpus

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Unblocks the 10–100 GiB B1/B2 scale run (the RFC 0006 §8 canonical band the thesis targets speak to). Two bench-crate changes, both leaving every recorded §9 number comparable:

1. Streaming corpus path for the query-store builds

corpus::load materializes the whole corpus as a Vec<OtlpLogRecord> (~2–4× raw bytes), which caps the loadable corpus well below the scale targets on the §1 baseline hardware (32 GiB). Mining and Parquet flush were already per-record — the eager load was the only blocker.

  • corpus::stream(dir, severity): a lazy per-line iterator over the same walker (collect_files is now the single traversal both paths consume — ordering, cycle guard, and §3.4.1 byte accounting cannot drift), yielding the same records in the same order with the same timestamps. Equivalence is pinned by stream_replays_load_record_for_record.
  • harness::run_streaming is the real loop; harness::run(&CorpusLoad) delegates (the gate paths hold the corpus anyway; the transient per-record clone is off every measured quantity).
  • build_store (b1/b2) now streams; peak memory is flat at any corpus size. Empty-corpus rejection keeps corpus::load's exact message.
  • --gates (A1/C1/C2) still uses the eager path — untouched behavior.

2. Opt-in log4j severity extraction for plain-text corpora

The §3.3 loader pins every plain-text line to INFO, so B1 skips plain-text corpora outright (distinct_severities == 1) — meaning B1 has no corpus in the ≥10 GiB class (the OTLP captures are ~1 GB). OURIOS_CORPUS_SEVERITY=log4j (never the default; unknown values are a hard error) extracts the first standalone TRACE/DEBUG/INFO/WARN/WARNING/ERROR/FATAL token — what a file-tailing agent would emit as severity_text — giving LogHub HDFS-family corpora a real error band for the B1 predicate. §3.3's pinned-INFO doc-comment explicitly anticipated this divergence ("a documented baseline to diverge from"); the default stays that baseline, so A1/C1/C2 template keying and all recorded numbers are unchanged.

build_query_store / build_b1_store gain the TxtSeverity parameter (bench-lib API); both benches resolve it from the env.

Tests

  • stream_replays_load_record_for_record — record-for-record stream≡load equivalence incl. file/byte accounting.
  • log4j_severity_extraction — token mapping, no-token INFO fallback, substring non-match, Fixed never extracts.
  • b1_store_over_log4j_text_gets_error_band_selectivity — the B1 predicate materializes under the opt-in mode; the existing Fixed selectivity-skip test is unchanged.

Invariants / hazards

  • Tests are specifications: all existing tests pass unchanged (call sites gained the explicit Fixed default only).
  • Bench methodology (RFC 0006): default behavior byte-identical; the severity knob is opt-in and will be named explicitly in any §9 entry that uses it.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for selecting corpus severity when running benchmarks, with consistent handling across benchmark setups.
  • Bug Fixes

    • Improved corpus loading and streaming so they process files in a consistent order and produce matching results.
    • Reduced memory usage during benchmark setup by streaming records instead of loading everything at once.
    • Benchmarks now handle empty corpora more reliably and apply severity-based filtering more consistently.

The B1/B2 query-store builds streamed everything except the corpus
load itself: corpus::load materializes ~2-4x the raw bytes as a
Vec<OtlpLogRecord>, capping the loadable corpus far below the 10-100
GiB the scale targets speak to. corpus::stream is a lazy per-line
iterator over the same single walker (collect_files) — same records,
same order, same accounting, pinned record-for-record by test — and
build_store consumes it via harness::run_streaming, so peak memory is
flat at any corpus size. The --gates path keeps the eager load.

OURIOS_CORPUS_SEVERITY=log4j (opt-in, unknown values a hard error)
extracts the first standalone level token from plain-text lines so
LogHub HDFS-family corpora get a real error band for B1's predicate;
the default stays §3.3's pinned INFO, so recorded template-keyed
numbers (A1/C1/C2) are untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard requested a review from Copilot July 4, 2026 04:41
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 10 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e152c1f3-f1b4-4a81-b652-98f8cd87da3f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c590d4 and 1ffe444.

📒 Files selected for processing (5)
  • crates/ourios-bench/benches/b1.rs
  • crates/ourios-bench/benches/b2.rs
  • crates/ourios-bench/src/corpus.rs
  • crates/ourios-bench/src/harness.rs
  • crates/ourios-bench/src/store.rs
📝 Walkthrough

Walkthrough

Corpus loading in ourios-bench is refactored to separate file discovery (CorpusFiles/collect_files) from record ingestion, with shared txt_record and jsonl_line_records helpers reused by eager and streaming paths. Harness streaming now uses Result-typed input. TxtSeverity is threaded through store builders and benchmarks, with tests updated accordingly.

Changes

Corpus Streaming and Severity Wiring

Layer / File(s) Summary
Public TxtSeverity export
crates/ourios-bench/src/lib.rs
Re-exports TxtSeverity from the corpus module as a public API item.
Corpus file discovery and accounting
crates/ourios-bench/src/corpus.rs
Adds CorpusFiles struct and collect_files helper for recursive directory traversal, decoupling discovery from ingestion; walk now only records file metadata, and plain-text ingestion uses a shared txt_record helper.
Shared JSONL record parsing
crates/ourios-bench/src/corpus.rs
Extracts jsonl_line_records to parse a LogsData JSON line, reused by both eager loading and the streaming iterator's pending queue; adds tests for streaming/eager parity and Log4j severity extraction.
Harness streaming input contract
crates/ourios-bench/src/harness.rs
Changes run_streaming to accept Result<OtlpLogRecord, BenchError> items with early termination via ?; run now delegates to run_streaming via a mapped iterator, and the callback passes owned records by reference.
Store builders adopt streaming and TxtSeverity
crates/ourios-bench/src/store.rs
Adds txt_severity parameter to build_query_store, build_b1_store, and build_store; switches ingestion to corpus::stream/harness::run_streaming; moves B1 bookkeeping into the streaming callback and rejects empty corpora after streaming.
Store test updates
crates/ourios-bench/src/store.rs
Updates existing tests to supply TxtSeverity::Fixed and adds a Log4j-specific B1 test.
Benchmark severity wiring
crates/ourios-bench/benches/b1.rs, crates/ourios-bench/benches/b2.rs
Imports TxtSeverity, derives severity from OURIOS_CORPUS_SEVERITY via TxtSeverity::from_env(), and passes it into build_b1_store/build_query_store.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Benchmark as b1.rs / b2.rs
  participant Store as store.rs
  participant Corpus as corpus.rs
  participant Harness as harness.rs

  Benchmark->>Store: build_b1_store/build_query_store(corpus_dir, txt_severity)
  Store->>Corpus: stream(corpus_dir, txt_severity)
  Corpus-->>Store: CorpusStream + file metadata
  Store->>Harness: run_streaming(stream, callback)
  Harness->>Corpus: pull next Result<OtlpLogRecord>
  Corpus-->>Harness: OtlpLogRecord (via jsonl_line_records/txt_record)
  Harness->>Store: callback(&record)
  Store-->>Benchmark: BuiltStore/B1Store or no_lines_error
Loading

Possibly related PRs

  • jensholdgaard/ourios#51: Modifies the same harness/corpus streaming architecture with per-line callback-driven ingestion.
  • jensholdgaard/ourios#58: Touches the same corpus.rs OTLP/JSONL ingestion logic that this PR refactors into jsonl_line_records.
  • jensholdgaard/ourios#171: Also modifies build_b1_store in store.rs and the b1.rs benchmark setup wired to it.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: streaming benchmark builds with opt-in log4j severity.
Description check ✅ Passed The description clearly explains the change, motivation, and tests, though it omits the template's Related and Checklist sections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bench-streaming-corpus

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the ourios-bench crate to (1) build B1/B2/query stores from a streaming corpus iterator (removing the need to materialize the entire corpus in memory) and (2) add an opt-in plain-text severity extraction mode (OURIOS_CORPUS_SEVERITY=log4j) to unlock severity selectivity for large text corpora while keeping the default baseline behavior unchanged.

Changes:

  • Introduce a streaming corpus loader (corpus::stream) and route query-store builds through harness::run_streaming to keep peak memory usage low for large corpora.
  • Add TxtSeverity with Fixed (default) and Log4j (opt-in) modes, wired into B1/B2 benches and store builders.
  • Add/extend tests to pin stream≡load equivalence and validate log4j severity extraction behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
crates/ourios-bench/src/store.rs Plumbs TxtSeverity through store builders and switches the build pipeline to stream records instead of eagerly loading them.
crates/ourios-bench/src/lib.rs Re-exports TxtSeverity as part of the bench crate API surface.
crates/ourios-bench/src/harness.rs Adds run_streaming and reworks run to delegate to the streaming loop.
crates/ourios-bench/src/corpus.rs Splits traversal into collect_files, adds streaming iterator (CorpusStream), and implements opt-in log4j severity extraction for plain-text.
crates/ourios-bench/benches/b1.rs Reads TxtSeverity from env and passes it to build_b1_store.
crates/ourios-bench/benches/b2.rs Reads TxtSeverity from env and passes it to build_query_store.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-bench/src/corpus.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/ourios-bench/src/corpus.rs (1)

524-538: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid cloning the corpus file list

store.rs only needs the accounting fields from CorpusFiles, so CorpusFiles.files doesn’t need to stay live alongside CorpusStream. Moving the file list into CorpusStream would avoid keeping two copies resident during the run.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ourios-bench/src/corpus.rs` around lines 524 - 538, The corpus stream
setup currently clones the collected file list, leaving the same files resident
in both CorpusFiles and CorpusStream. Update stream to move the files vector
into CorpusStream instead of cloning it, and adjust CorpusFiles usage so
store.rs still gets only the accounting fields it needs while CorpusStream owns
the iterator source.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/ourios-bench/src/corpus.rs`:
- Around line 524-538: The corpus stream setup currently clones the collected
file list, leaving the same files resident in both CorpusFiles and CorpusStream.
Update stream to move the files vector into CorpusStream instead of cloning it,
and adjust CorpusFiles usage so store.rs still gets only the accounting fields
it needs while CorpusStream owns the iterator source.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cdc29269-774b-4115-ab2a-5328e0a90c18

📥 Commits

Reviewing files that changed from the base of the PR and between d8a9ede and 1c590d4.

📒 Files selected for processing (6)
  • crates/ourios-bench/benches/b1.rs
  • crates/ourios-bench/benches/b2.rs
  • crates/ourios-bench/src/corpus.rs
  • crates/ourios-bench/src/harness.rs
  • crates/ourios-bench/src/lib.rs
  • crates/ourios-bench/src/store.rs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-bench/src/store.rs
Comment thread crates/ourios-bench/src/store.rs Outdated
The callback is now fallible: a Parquet write / observe error stops
the mine at the failing record instead of stashing the error and
CPU-mining the remaining corpus (minutes wasted at the 10-100 GiB
scale this path exists for). Also scopes the memory-flat claim to the
record/raw-byte dimension (the file list is O(files)).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread crates/ourios-bench/src/harness.rs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread crates/ourios-bench/src/corpus.rs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-bench/src/store.rs
Comment thread crates/ourios-bench/src/corpus.rs Outdated
…streaming loop

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Comment thread crates/ourios-bench/src/corpus.rs Outdated
Comment thread crates/ourios-bench/benches/b1.rs
Comment thread crates/ourios-bench/benches/b2.rs
…he band map

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@jensholdgaard
jensholdgaard merged commit 2655bac into main Jul 4, 2026
22 checks 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.

2 participants