Repository navigation
fix(hashlogcompare): drop the torn tail of a sealed hash log file - #607
Conversation
A crash can leave a hash log file whose last line has no newline. When
seid restarts, it seals that file and keeps the torn bytes. The reader
waited for that line to finish, so it never moved to the next file and
reported no error. The comparator then stalled with healthy metrics
until a restart.
The reader now drops the incomplete last line of a sealed file, as the
HashLogger's own reader does, and returns errTornRow. The comparator
counts it as source_errors_total{reason="torn_row"} and logs a warning.
Refs: PLT-1398
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR SummaryMedium Risk Overview Reader now treats trailing bytes after the last newline on a sealed file as a torn row—skips them, advances the cursor, and returns Observability: Reviewed by Cursor Bugbot for commit 385a85a. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
On a sealed hash log file, the reader now skips an incomplete last line and reports it as a torn_row source error, so it moves on to the next file instead of waiting forever. This fixes the PLT-1398 stall, and I found nothing blocking: the sidecar returns the whole requested range with no size cap, so the reader only drops bytes that are really torn. codex's reading found nothing and I agree, so it gave me no findings to keep or drop; I could not run the tests because Go is not installed here.
Non-blocking
- The fix covers only a sealed file whose rows are torn. If a sealed file's header line has no newline,
Pollstill hits ther.header == nilbranch and returns no error, and it does that on every poll forever. That is the same silent stall this PR fixes, and only the sei-chain sealing guarantee stops it from happening. Consider returning an error there whenr.sealedis true, so a broken guarantee shows up as a source error rather than a hang.
seidroid review · decision approve · session a2943639c36548e38904a21f40200e01 · turn resp_claude_de25abf82c1c8a44a4e7390e1882afd1 · item 48fb903a1afd520a9a15a7a510780237
Findings: 0 blocking | 1 non-blocking | 0 posted inline
Summary
On atlantic-2, the reserve reader of
canary-hashlog-comparatorstalled for about 30 minutes after a pod restart. It logged no error and counted no source error, and only a restart of the comparator recovered it. The cause was a sealed hash log file whose last line a crash had torn.Reader.Pollwaited for that line to finish, so it never callednextFile. This PR makes the reader drop that line and report it (PLT-1398).Change
Pollmoves the cursor past any bytes after the last newline and returnserrTornRow. The error names the file and the byte count. The next poll reads zero bytes at end of file and follows the existingnextFilepath.run.gomapserrTornRowto a new reason,torn_row. It goes through the existing WARN log andsource_errors_totalincrement.initPairexports the new series at zero.Readerdoc states the sei-chain guarantee that this rests on.ReadHashLogFilediscards a torn last line, andsealHashLogremoves an orphan with no complete row. Together, they mean that a sealed file always has a complete header and at least one row. Only its last line can be incomplete.HashLogSourceErrors, which needs 5 minutes of errors. If the restarted node does not write that height again,HashLogHeightGapsfires.Verification
TestReader_DropsTornTailOfSealedFileandTestPairRunner_TornReserveRowIsSourceError. Both fail without the change, with no error and no progress.gofmt,go vet,go test(asmake testruns it), andgolangci-lintv2.12.1 with no filter on the package.staticcheckis clean on the package.source_heighton the atlantic-2 pair.Refs: PLT-1398
🤖 Generated with Claude Code