Skip to content

feat(metrics): add compaction io + H4 file-size telemetry (RFC 0009 §3.6) - #113

Merged
jensholdgaard merged 1 commit into
mainfrom
feat/compaction-io-filesize-metrics
Jun 4, 2026
Merged

feat(metrics): add compaction io + H4 file-size telemetry (RFC 0009 §3.6)#113
jensholdgaard merged 1 commit into
mainfrom
feat/compaction-io-filesize-metrics

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jun 4, 2026

Copy link
Copy Markdown
Owner

What

Completes the compaction metric set (RFC 0009 §3.6) with the two byte-volume instruments the earlier telemetry slice deferred — headlined by the H4 small-file detector.

Metric Instrument Unit Attributes
ourios.storage.parquet.file.size Histogram By ourios.tenant
ourios.compaction.io Counter By ourios.io.direction
  • ourios.storage.parquet.file.size — the H4 detector (hazards.md docs: apply RFC maturity-model amendments #4, small-file problem). A per-tenant distribution of consolidated output-file sizes; the "alert when > 5 % of files < 128 MiB" rule is a derived alert over this distribution, not a base metric.
  • ourios.compaction.io — bytes read from the merged-away inputs vs. written to the consolidated output, split by ourios.io.direction (read / write).

How

  • compact_partition now reports bytes_read / bytes_written on CompactionOutcome. Sizing is best-effort (stat0 on failure) by design: a metric inaccuracy on a file we just read or wrote must never turn a committed compaction into a failure.
  • SweepReport carries the aggregate bytes_read plus one per-tenant CompactedFile { tenant, bytes } per committed output (the per-tenant histogram samples).
  • CompactionMetrics builds the io counter + file_size histogram and records both in record_sweep. Neither is zero-seeded (required attribute / histogram), consistent with sweeps / duration; io surfaces on the first sweep with a 0-byte point.
  • Names/units come from the generated ourios-semconv constants (already present) — no registry / weaver change.

Invariants (CLAUDE.md §4, hazard H4)

This is the H4 ("small file problem") detection metric. It is observe-only — it changes no compaction behaviour, only exposes the per-tenant file-size distribution the H4 alert needs. Row conservation, the audit event, and the atomic manifest swap are untouched.

ourios.compaction.backlog (an UpDownCounter for sealed-but-uncompacted lag — a cross-sweep gauge, not a per-compaction quantity) remains the one §3.6 metric still deferred.

Tests

  • ourios-parquet: compact_partition reports a non-zero read volume and a write volume equal to the consolidated file's on-disk size; a no-op reports zero volumes.
  • ourios-ingester: the in-memory exporter shows all 8 compaction metrics; io carries read (4096) and write (3072 = Σ outputs) direction points; file.size is a per-tenant histogram with one sample per output. (Single test / single global provider — init_in_memory installs the global meter.)

Local: cargo fmt --all --check, cargo clippy --workspace --all-targets --all-features -D warnings, cargo test --workspace --all-features all green.

Part of epic #94.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Enhanced compaction operations with I/O byte-volume metrics and per-file size tracking
    • Improved observability into compaction efficiency through detailed read/write statistics and consolidated file-size reporting

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

More reviews will be available in 39 minutes and 8 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 00578711-e2c6-4b15-a41c-e383db1e112c

📥 Commits

Reviewing files that changed from the base of the PR and between 69952ec and b87299e.

📒 Files selected for processing (3)
  • crates/ourios-ingester/src/compactor.rs
  • crates/ourios-ingester/src/metrics.rs
  • crates/ourios-parquet/src/compaction.rs
📝 Walkthrough

Walkthrough

This PR instruments compaction operations with byte-volume metrics across three layers: CompactionOutcome now reports bytes read from input files and bytes written to the consolidated output; SweepReport aggregates these metrics via a new CompactedFile struct; and CompactionMetrics records I/O counters and output file-size histograms for OpenTelemetry export.

Changes

Compaction I/O and File-Size Metrics

Layer / File(s) Summary
Compaction outcome byte-volume metrics
crates/ourios-parquet/src/compaction.rs
CompactionOutcome gains bytes_read (total input file size) and bytes_written (output file size) fields; compact_partition accumulates input file sizes during streaming and computes output size from file metadata; a file_len helper provides best-effort stat-based sizing; tests validate byte-volume reporting and zero-values for no-op compactions.
Sweep report aggregation and CompactedFile struct
crates/ourios-ingester/src/compactor.rs
SweepReport extends with bytes_read (saturating sum across partitions) and compacted_files list; new CompactedFile struct records tenant and output bytes per consolidated file; run_sweep populates both from committed CompactionOutcome metrics.
Metrics instrumentation for I/O and file sizes
crates/ourios-ingester/src/metrics.rs
CompactionMetrics adds io (Counter) and file_size (Histogram) instruments; new() constructs them with By unit; record_sweep() records io read/write points (with io.direction attribute) and file-size samples per file (with ourios.tenant attribute); tests validate exported metric names, read/write totals, and per-file histogram sample counts and sums.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • jensholdgaard/ourios#94: Main changes directly implement compaction byte-volume and file-size metrics tracked by the background compaction epic.

Possibly related PRs

  • jensholdgaard/ourios#106: Both extend compaction sweep instrumentation in SweepReport and CompactionMetrics to record additional compaction outcome details as metrics.
  • jensholdgaard/ourios#110: Both modify run_sweep handling of successful committed partition compactions to record per-compaction output information.
  • jensholdgaard/ourios#102: Main PR implements the compaction telemetry metrics defined in RFC/semconv, adding ourios.compaction.io and ourios.storage.parquet.file.size instrumentation aligned with the semconv registry spec.

Poem

🐰 Bytes flow through the compactor's hands,
Read and written, tallied up with care,
Files shrink down to measured strands,
Metrics dance in OpenTelemetry's air,
I/O streams now have their tale to share!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically summarizes the main change: adding compaction I/O and file-size telemetry metrics per RFC 0009 §3.6.
Description check ✅ Passed The description covers all template sections with substantial detail: What/How, Related (RFC 0009 §3.6, epic #94), comprehensive Checklist with all items addressed (cargo fmt/clippy clean, tests added, docs updated, RFC linked).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/compaction-io-filesize-metrics

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 and usage tips.

@jensholdgaard
jensholdgaard requested a review from Copilot June 4, 2026 21:44
@jensholdgaard

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/ourios-ingester/src/metrics.rs (1)

130-147: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Record ourios.compaction.io even when a sweep fails.

io datapoints are currently skipped on Err(IngestError), so first-sweep visibility is lost on fatal scan failures and direction series may disappear during outage windows. Emit read=0/write=0 outside the Ok(report) block, then override values from report when present.

🤖 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-ingester/src/metrics.rs` around lines 130 - 147, Currently io
datapoints are only emitted inside the Ok(result) branch, so on Err(IngestError)
the read/write series vanish; move the self.io.add calls so a default
zero-valued pair is emitted unconditionally before matching result (emit
self.io.add(0, &[KeyValue::new(semconv::OURIOS_IO_DIRECTION, "read")]) and
self.io.add(0, &[KeyValue::new(semconv::OURIOS_IO_DIRECTION, "write")]) ), then
in the Ok(report) branch compute bytes_written and call
self.io.add(report.bytes_read, ..) and self.io.add(bytes_written, ..) to
override the zeros; update the code around result handling where bytes_written,
report, and self.io.add are used.
🤖 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.

Inline comments:
In `@crates/ourios-ingester/src/metrics.rs`:
- Line 139: The bytes_written aggregation uses .sum() which can overflow; change
the computation of bytes_written from report.compacted_files.iter().map(|f|
f.bytes).sum() to a saturating fold so it never wraps (e.g., use iter().map(|f|
f.bytes).fold(0u64, |acc, b| acc.saturating_add(b))); update the variable
bytes_written and related logic in metrics.rs to match the saturating
accumulation semantics used by run_sweep in compactor.rs.

---

Outside diff comments:
In `@crates/ourios-ingester/src/metrics.rs`:
- Around line 130-147: Currently io datapoints are only emitted inside the
Ok(result) branch, so on Err(IngestError) the read/write series vanish; move the
self.io.add calls so a default zero-valued pair is emitted unconditionally
before matching result (emit self.io.add(0,
&[KeyValue::new(semconv::OURIOS_IO_DIRECTION, "read")]) and self.io.add(0,
&[KeyValue::new(semconv::OURIOS_IO_DIRECTION, "write")]) ), then in the
Ok(report) branch compute bytes_written and call self.io.add(report.bytes_read,
..) and self.io.add(bytes_written, ..) to override the zeros; update the code
around result handling where bytes_written, report, and self.io.add are used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 07864e9e-4e60-4616-95f6-1e9348688c7e

📥 Commits

Reviewing files that changed from the base of the PR and between 12fc507 and 69952ec.

📒 Files selected for processing (3)
  • crates/ourios-ingester/src/compactor.rs
  • crates/ourios-ingester/src/metrics.rs
  • crates/ourios-parquet/src/compaction.rs

Comment thread crates/ourios-ingester/src/metrics.rs Outdated

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

Adds the remaining RFC 0009 §3.6 compaction telemetry by plumbing byte-volume measurements out of ourios-parquet compaction and emitting new OpenTelemetry instruments in ourios-ingester, including the H4 small-file detector.

Changes:

  • Extend CompactionOutcome with best-effort bytes_read / bytes_written and compute them during compact_partition.
  • Extend sweep reporting to carry aggregate read volume plus per-committed-output (tenant, bytes) samples.
  • Add ourios.compaction.io counter (read/write via ourios.io.direction) and ourios.storage.parquet.file.size per-tenant histogram, with tests validating export.

Reviewed changes

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

File Description
crates/ourios-parquet/src/compaction.rs Computes and returns best-effort compaction read/write byte volumes; adds unit tests for byte-volume reporting.
crates/ourios-ingester/src/compactor.rs Propagates byte-volume data into SweepReport, including per-tenant consolidated file-size samples.
crates/ourios-ingester/src/metrics.rs Defines and records new io counter and file_size histogram instruments; extends in-memory exporter tests.

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

Comment thread crates/ourios-ingester/src/metrics.rs
Comment thread crates/ourios-ingester/src/metrics.rs
Comment thread crates/ourios-ingester/src/metrics.rs Outdated
@jensholdgaard
jensholdgaard force-pushed the feat/compaction-io-filesize-metrics branch from 69952ec to 6e44502 Compare June 4, 2026 21:54
@jensholdgaard
jensholdgaard requested a review from Copilot June 4, 2026 21:56
@jensholdgaard

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread crates/ourios-parquet/src/compaction.rs
…3.6)

Complete the compaction metric set with the two byte-volume instruments
RFC 0009 §3.6 deferred:

- `ourios.storage.parquet.file.size` (Histogram, By, `ourios.tenant`) —
  the H4 small-file detector: a per-tenant distribution of consolidated
  output sizes, so the "alert when > 5 % of files < 128 MiB" rule (the
  small-file hazard) is a derived alert over this distribution.
- `ourios.compaction.io` (Counter, By, `ourios.io.direction`) — bytes
  read from the merged-away inputs and written to the consolidated file.

`compact_partition` now reports `bytes_read` / `bytes_written` on
`CompactionOutcome` (best-effort `stat`: a metric inaccuracy on a file we
just read or wrote never fails a committed compaction), the `SweepReport`
carries them through plus a per-tenant `CompactedFile` per output, and
`CompactionMetrics::record_sweep` records both instruments. Names/units
come from the generated `ourios-semconv` constants — no registry change.

`ourios.compaction.backlog` (an UpDownCounter for sealed-but-uncompacted
lag — a cross-sweep gauge, not a per-compaction quantity) stays the one
§3.6 metric deferred.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard force-pushed the feat/compaction-io-filesize-metrics branch from 6e44502 to b87299e Compare June 4, 2026 22:02
@jensholdgaard
jensholdgaard requested a review from Copilot June 4, 2026 22:03
@jensholdgaard

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 3 out of 3 changed files in this pull request and generated no new comments.

@jensholdgaard
jensholdgaard merged commit f6e6ace into main Jun 4, 2026
11 checks passed
@jensholdgaard
jensholdgaard deleted the feat/compaction-io-filesize-metrics branch June 4, 2026 22:14
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