feat(filestore): configurable capacity threshold alert (S05.09)#240
Conversation
…uence Slice 1 of S05.09. Adds SolidSyslogStoreThresholdFunction and SolidSyslogStoreThresholdCallback typedefs plus the three new SolidSyslogFileStoreConfig fields (getCapacityThreshold, onThresholdCrossed, thresholdContext), and threads them through BlockSequenceConfig/BlockSequence. Minimal firing path: any record-write invokes onThresholdCrossed when non-NULL — edge detection and threshold comparison land in subsequent slices.
Slice 2 of S05.09. Adds thresholdCrossed bool to BlockSequence and gates NotifyThresholdCrossed on it being false, so consecutive writes that keep usage above threshold do not refire the callback. The bit is set on first fire and (for now) never cleared — re-arm after a drop lands in slice 3.
…reshold Slice 3 of S05.09. NotifyThresholdCrossed now reads the threshold and compares against BlockSequence_UsedBytes. On a falling edge (used < threshold) it clears thresholdCrossed so the callback re-arms; on a rising edge it fires once and latches the bit. Verifies re-arm under DISCARD_OLDEST when the threshold sits inside the active block.
…abled Slice 4 of S05.09. Adds ThresholdEnabled helper that gates the firing path on both callbacks being non-NULL, and treats threshold == 0 as disabled (clears any latched edge state). Spec calls these out as distinct ways to disable the feature without nulling onThresholdCrossed.
…backs Slice 5 of S05.09. Pure regression guard — the plumbing already wires thresholdContext through (added in slice 1), but the test pins down that contract: both getCapacityThreshold and onThresholdCrossed receive the configured context, mirroring storeFullContext's role.
…ty exhaustion Slice 6 of S05.09. When PrepareForWrite hits the file-full + store-full branch, engage the sticky 100% bit, then run the threshold check so it sees usage = total, then fall through to NotifyStoreFull. Spec defines this ordering at the 100% case so the 'approaching capacity' alert fires before the terminal 'at capacity' callback. Sticky-bit assignment moves out of NotifyStoreFull into the call site to make the sequencing explicit.
Slice 7 of S05.09. Pure regression guard. Once a failed Write has latched thresholdCrossed and engaged the sticky bit, subsequent failed Writes find the bit still set and skip firing — exactly the spec's 'sticky 100% does not re-fire' requirement. Comes free from slice 2's edge-state latch and slice 6's sticky-first ordering.
…ge is above Slice 8 of S05.09. After ScanForExistingFiles + write-position recovery, BlockSequence_Open now runs NotifyThresholdCrossed so the callback fires once on Create when the integrator restarts above an existing threshold.
…ext Write Slice 9 of S05.09. Pure regression guard. Because NotifyThresholdCrossed fetches the threshold via getCapacityThreshold on every Write, a runtime change to a value below current usage naturally fires on the next Write without needing a setter or notification path.
Slice 10 of S05.09. CLAUDE.md "Public header audiences" row for SolidSyslogFileStore.h now lists the threshold typedefs and config fields (with NullBuffer recursion pointer to the header). iec62443.md CR 2.9 / CR 2.10 rows replace the gap-flag wording with the implemented behaviour, including the at-100% ordering with HALT. The header doc-comment for the typedefs (with the NullBuffer recursion gotcha) landed in slice 1.
Slice 11 of S05.09. Threaded example now wires getCapacityThreshold + onThresholdCrossed when --capacity-threshold N is supplied; the callback appends a line to /tmp/solidsyslog_threshold_marker.log so BDD steps can detect invocation. Two scenarios cover the rising-edge fire and the no-fire-while-below-threshold case; environment.py cleans the marker between scenarios.
📝 WalkthroughWalkthroughThis PR implements a configurable capacity threshold alert mechanism for the SolidSyslog file store. It adds edge-triggered threshold callbacks ( ChangesCapacity Threshold Alert Feature
Sequence DiagramsequenceDiagram
actor App as Application
participant CLI as ExampleCommandLine
participant Store as FileStore
participant BS as BlockSequence
participant CB as Callback
App->>CLI: Parse --capacity-threshold 5000
CLI->>CLI: Store threshold in options
App->>Store: Create with threshold config
Store->>BS: Initialize with getCapacityThreshold,<br/>onThresholdCrossed
Note over BS: Resume stored data<br/>Check if usage ≥ threshold
alt Usage already above threshold
BS->>CB: Fire onThresholdCrossed
end
App->>Store: Write message
Store->>BS: Prepare and write
Note over BS: On each Write:
BS->>BS: Query getCapacityThreshold()
BS->>BS: Compare current usage<br/>vs threshold
alt Usage crosses threshold upward
BS->>BS: Set thresholdCrossed=true
BS->>CB: Invoke onThresholdCrossed
end
alt Store becomes full
BS->>CB: Later: Invoke onStoreFull<br/>(after threshold)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
☀️ Quality Summary 🚦 build-linux-gcc: 100% successful (✔️ 972 passed, 🙈 3 skipped) Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
Core/Interface/SolidSyslogFileStore.h (1)
26-30: ⚡ Quick winAdd re-arm behavior to the typedef comment.
The current doc says "fires once when used-bytes transitions from below threshold to at-or-above" but omits that the callback re-arms when usage subsequently falls back below the threshold. An integrator could reasonably read "fires once" as a lifetime guarantee rather than a per-rising-edge guarantee.
✏️ Proposed wording addition
/* Edge-triggered: fires once when used-bytes transitions from below threshold to at-or-above. + * Re-arms automatically when usage falls back below the threshold, so the callback can fire + * again on the next rising-edge transition. * NullBuffer note: SolidSyslog_Log is synchronous under SolidSyslogNullBuffer, so calling * SolidSyslog_Log from this callback will recurse into Store_Write. Either gate the Log, * or use SolidSyslogPosixMessageQueueBuffer (which returns immediately). */🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Core/Interface/SolidSyslogFileStore.h` around lines 26 - 30, Update the typedef comment for SolidSyslogStoreThresholdCallback to clarify that the callback is edge-triggered on rising transitions of used-bytes (fires each time usage goes from below threshold to at-or-above) and that it is re-armed when usage later falls back below the threshold (i.e., it will fire again on subsequent rising edges); keep the existing NullBuffer note and gating advice intact but adjust wording to avoid implying a single lifetime invocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/iec62443.md`:
- Line 35: Tiny wording fix: update the description for
SolidSyslogStoreThresholdFunction + SolidSyslogStoreThresholdCallback to read
"re-arms when usage falls back below the threshold" (i.e., insert "the
threshold" after "falls back below") so the behavior sentence is explicit and
unambiguous for readers.
---
Nitpick comments:
In `@Core/Interface/SolidSyslogFileStore.h`:
- Around line 26-30: Update the typedef comment for
SolidSyslogStoreThresholdCallback to clarify that the callback is edge-triggered
on rising transitions of used-bytes (fires each time usage goes from below
threshold to at-or-above) and that it is re-armed when usage later falls back
below the threshold (i.e., it will fire again on subsequent rising edges); keep
the existing NullBuffer note and gating advice intact but adjust wording to
avoid implying a single lifetime invocation.
🪄 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
Run ID: 16694224-0a08-4add-9223-1e918dee0992
📒 Files selected for processing (14)
Bdd/features/capacity_threshold.featureBdd/features/environment.pyBdd/features/steps/syslog_steps.pyCLAUDE.mdCore/Interface/SolidSyslogFileStore.hCore/Source/BlockSequence.cCore/Source/BlockSequence.hCore/Source/SolidSyslogFileStore.cDEVLOG.mdExample/Common/ExampleCommandLine.cExample/Common/ExampleCommandLine.hExample/Threaded/main.cTests/SolidSyslogFileStoreTest.cppdocs/iec62443.md
Summary
SolidSyslogStoreThresholdFunction/SolidSyslogStoreThresholdCallbacktypedefs and three paired config fields (getCapacityThreshold,onThresholdCrossed,thresholdContext) toSolidSyslogFileStoreConfig.BlockSequence: rises once whenUsedBytes >= threshold, latches via athresholdCrossedbool, clears on falling edge so DISCARD_OLDEST scenarios re-arm naturally.PrepareForWrite's file-full + store-full branch sets the sticky 100% bit, runs the threshold check, then dispatchesonStoreFullso the warning fires before the terminal callback.Createwhen persisted usage is already at-or-above threshold (BlockSequence_Openruns the check after recovering write position).Bdd/Features/capacity_threshold.featurecovers happy-path fire and below-threshold no-fire.Core/Interface/SolidSyslogFileStore.htypedef comments include the NullBuffer recursion gotcha;CLAUDE.md"Public header audiences" row updated;docs/iec62443.mdCR 2.9 / CR 2.10 rows replace the gap-flag wording.Test plan
cmake --build --preset debug+./build/debug/Tests/SolidSyslogTests(967 tests, 100% pass)cmake --build --preset clang-debug(gcc + clang both green)cmake --build --preset sanitizeASan/UBSancmake --build --preset coverage— 100% line + function (1667/1667lines,367/367functions)cmake --build --preset tidy— clang-tidy cleancmake --build --preset cppcheck— cleanclang-format --dry-run --Werroron all touched filesbehave Bdd/Features/capacity_threshold.feature(2 scenarios, both pass)Sliced 11 ways with strict TDD per
feedback_slice_by_slice_review— every production change driven by a failing test, refactor under green following SOLID/DRY. DEVLOG entry recorded.Closes #111
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
--capacity-thresholdcommand-line option to configure the alert threshold.Documentation