Swap/recovery: second-pass fixes from the follow-up review
- Recovery works when another named buffer is current. On that path
OpenFile's NotifyFilenameChanged deleted the journal (old path ==
new path) that was about to be replayed; the swap was lost and the
file opened without the edits (pre-existing).
- After recovering from a journal with a torn final record, the torn
bytes are truncated before the session appends to it (ReplayFile now
reports the valid prefix length). A journal that recovers nothing is
removed instead of appended to.
- Reload restarts the journal; recovery used to replay the edits the
reload discarded.
- Opening a file that is already open switches to its buffer (in
OpenFile and before the recovery check). Two buffers for one file
interleaved records in one journal, and closing either unlinked it.
- Swap file names escape '!' and '%', so distinct paths no longer
share a journal ('/x/a!b' vs '/x/a/b'). Swap files for paths that
contain those characters get new names.
- The gap flag is cleared when the journal restarts, and a gap that
cannot be closed (buffer too large to checkpoint) is reported once.
- crc32's table is initialised thread-safely; writer-thread error
reports identify the buffer by journal path instead of racing on
Buffer::Filename(); Close() no longer retries on EINTR (the fd is
already released and may have been reused).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
@@ -111,7 +111,13 @@ public:
|
||||
// On failure (corrupt/truncated/invalid), the buffer is left in whatever
|
||||
// state results from applying records up to the failure point; callers should
|
||||
// treat this as a recovery failure and surface `err`.
|
||||
static bool ReplayFile(Buffer &buf, const std::string &swap_path, std::string &err);
|
||||
//
|
||||
// A record cut short at end of file (a crash mid-append) ends the replay
|
||||
// successfully; err then describes the incomplete record. If valid_bytes
|
||||
// is given, it receives the length of the journal's valid prefix, so a
|
||||
// caller that keeps using the journal can truncate the torn tail first.
|
||||
static bool ReplayFile(Buffer &buf, const std::string &swap_path, std::string &err,
|
||||
std::uint64_t *valid_bytes = nullptr);
|
||||
|
||||
// Compute the swap path for a file-backed buffer by filename.
|
||||
// Returns empty string if filename is empty.
|
||||
@@ -197,6 +203,7 @@ private:
|
||||
// drop them until a checkpoint re-establishes the full content.
|
||||
bool gap{false};
|
||||
std::uint64_t gap_chkpt_request_ns{0};
|
||||
bool gap_unfixable_reported{false}; // gap on a buffer too large to checkpoint
|
||||
};
|
||||
|
||||
struct Pending {
|
||||
|
||||
Reference in New Issue
Block a user