fix(state): tolerate closed WAL scan descriptors

(cherry picked from commit 299f91bb0c235cd002510034f77c2e627b3985e6)
This commit is contained in:
KoNit-K
2026-09-14 04:04:30 +08:00
committed by kshitij
parent f9ea3a5328
commit 106bf99a0e
2 changed files with 20 additions and 0 deletions
+4
View File
@@ -165,6 +165,10 @@ def _fd_is_truly_unlinked(fd_path: str, watched_path: str) -> bool:
names — the guard keeps failing closed.""" names — the guard keeps failing closed."""
try: try:
fd_stat = os.stat(fd_path) fd_stat = os.stat(fd_path)
except FileNotFoundError:
# The descriptor was closed after /proc was read. It cannot keep a
# retired generation alive, so do not turn this scan race into a halt.
return False
except OSError: except OSError:
return True return True
return _identity_is_truly_unlinked((fd_stat.st_dev, fd_stat.st_ino), watched_path) return _identity_is_truly_unlinked((fd_stat.st_dev, fd_stat.st_ino), watched_path)
@@ -160,6 +160,22 @@ def test_iter_holders_ignores_live_unhashed_dentry(tmp_path, force_wal, monkeypa
db.close() db.close()
def test_iter_holders_ignores_descriptor_closed_during_scan(tmp_path, monkeypatch):
"""A descriptor gone after ``readlink`` cannot hold a retired generation."""
path = tmp_path / "state.db"
wal = Path(str(path) + "-wal")
wal.write_bytes(b"current generation")
vanished_fd = tmp_path / "closed-writable-opener-fd"
monkeypatch.setattr(hermes_state_dbfile.sys, "platform", "linux")
monkeypatch.setattr(
hermes_state_dbfile,
"_iter_proc_fd_targets",
lambda: iter([(os.getpid(), str(wal) + " (deleted)", str(vanished_fd))]),
)
assert iter_deleted_sqlite_sidecar_holders(path) == []
@pytest.mark.skipif( @pytest.mark.skipif(
not sys.platform.startswith("linux"), not sys.platform.startswith("linux"),
reason="deleted-WAL write halt uses Linux unlink semantics", reason="deleted-WAL write halt uses Linux unlink semantics",