- 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
51 lines
1.7 KiB
C++
51 lines
1.7 KiB
C++
// SyscallWrappers.h - EINTR-safe syscall wrappers for kte
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <cstddef>
|
|
#include <sys/stat.h>
|
|
|
|
namespace kte {
|
|
namespace syscall {
|
|
// EINTR-safe wrapper for open(2).
|
|
// Returns file descriptor on success, -1 on failure (errno set).
|
|
// Automatically retries on EINTR.
|
|
int Open(const char *path, int flags, mode_t mode = 0);
|
|
|
|
// Wrapper for close(2).
|
|
// Returns 0 on success, -1 on failure (errno set).
|
|
// EINTR is treated as success and never retried: the descriptor has already
|
|
// been released on Linux, and retrying could close an unrelated, reused fd.
|
|
int Close(int fd);
|
|
|
|
// EINTR-safe wrapper for fsync(2).
|
|
// Returns 0 on success, -1 on failure (errno set).
|
|
// Automatically retries on EINTR.
|
|
int Fsync(int fd);
|
|
|
|
// EINTR-safe wrapper for fstat(2).
|
|
// Returns 0 on success, -1 on failure (errno set).
|
|
// Automatically retries on EINTR.
|
|
int Fstat(int fd, struct stat *buf);
|
|
|
|
// EINTR-safe wrapper for fchmod(2).
|
|
// Returns 0 on success, -1 on failure (errno set).
|
|
// Automatically retries on EINTR.
|
|
int Fchmod(int fd, mode_t mode);
|
|
|
|
// EINTR-safe wrapper for ftruncate(2).
|
|
// Returns 0 on success, -1 on failure (errno set).
|
|
// Automatically retries on EINTR.
|
|
int Ftruncate(int fd, off_t length);
|
|
|
|
// EINTR-safe wrapper for mkstemp(3).
|
|
// Returns file descriptor on success, -1 on failure (errno set).
|
|
// Automatically retries on EINTR.
|
|
// Note: template_str must be a mutable buffer ending in "XXXXXX".
|
|
int Mkstemp(char *template_str);
|
|
|
|
// Note: rename(2) and unlink(2) are not wrapped because they operate on
|
|
// filesystem metadata and typically complete atomically without EINTR.
|
|
// If interrupted, they either succeed or fail without partial state.
|
|
} // namespace syscall
|
|
} // namespace kte
|