Repository navigation
fix(wal): track write failures, attempt rotation, fix nil-file panic - #485
Conversation
Previously, w.currentFile.Write() errors were logged but: - Not tracked (no counter for operators to monitor) - Not followed by rotation (same bad file handle kept failing) - Sync errors from w.currentFile.Sync() were silently ignored Changes: - Add FailedWrites atomic counter to Writer struct (exposed in Stats()) - On write failure: increment counter, attempt rotation, retry write - On sync failure: log the error - Wire FailedWrites into the metrics system (IncWALFailedWrites, wal_failed_writes in snapshot, arc_wal_failed_writes_total in Prometheus) Fixes #339
Previously rotate() closed the old file before opening the new one. If os.OpenFile failed (e.g. disk full), w.currentFile was left nil, causing the next writeEntry to panic on nil pointer dereference. Now: open new file + write header first, close old file only after the new file is confirmed ready. On any failure, the old file handle stays valid and the next write succeeds against it.
There was a problem hiding this comment.
Code Review
This pull request introduces write failure tracking and automatic file rotation to the WAL writer. It adds a FailedWrites counter, exposes it via metrics (including Prometheus), and updates the write path to attempt a file rotation and retry the write upon failure. Additionally, the rotate method is refactored to open the new file and write its header before closing the old file, and sync errors are now captured and logged. The review feedback suggests changing the FailedWrites field in the Writer struct from a raw int64 to atomic.Int64 to prevent potential alignment panics on 32-bit architectures and to align with modern Go idioms, along with corresponding updates to use .Add(1) and .Load().
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
Thanks for the review. Addressing the findings:
|
The write-failure retry path can leave a truncated entry at the tail of the old WAL file if the first write failed mid-way. Document that this is safe because Reader.readEntry tolerates a partial trailing entry (clean EOF on a truncated header, skipped-corrupted on a truncated payload / checksum mismatch) and never returns a fatal error for it. No behavior change.
Fixes #339.
Summary
Three fixes for the WAL writer:
Write failures are now tracked. A new
FailedWritescounter (exposed inStats()and asarc_wal_failed_writes_totalin Prometheus) lets operators monitor write failure rates. Previously,w.currentFile.Write()errors were logged but not observable in metrics.Rotation is attempted on write failure. If a write fails (disk full, permission change, file deleted), the writer now tries to rotate to a new WAL file and retry the entry. Previously, the same bad file handle kept being used for all subsequent writes.
rotate() no longer leaves
w.currentFilenil. The rotation function now opens and initializes the new file BEFORE closing the old one. If the new file can't be created (e.g., disk full), the old file handle stays valid — no nil-pointer panic on the next write. This was a pre-existing bug exposed by the new write-error rotation path.Sync errors are now logged.
w.currentFile.Sync()errors were silently ignored; they are now logged at ERROR level.Configuration Matrix
w.currentFilevalid from initrotate();metricsimported;w.muheldTest Plan
go build ./...) cleangofmt/go vetclean