some changes and log fix
This commit is contained in:
@@ -105,7 +105,10 @@ def _read_log_tail(path: Path, max_bytes: int = 16384) -> str:
|
||||
data = handle.read()
|
||||
except OSError:
|
||||
return ""
|
||||
return data.decode("utf-8", errors="replace").strip()
|
||||
# Drop NULs: logs written by an older supervisor can carry a sparse hole from
|
||||
# the pre-O_APPEND truncate bug, and a tail landing in it would otherwise turn
|
||||
# an exit report (or a rolled `.prev`) into megabytes of NUL padding.
|
||||
return data.replace(b"\0", b"").decode("utf-8", errors="replace").strip()
|
||||
|
||||
|
||||
class ProcessSupervisor:
|
||||
@@ -232,8 +235,17 @@ class ProcessSupervisor:
|
||||
self._roll_log_to_prev(stdout_path)
|
||||
self._roll_log_to_prev(stderr_path)
|
||||
|
||||
stdout_file = open(stdout_path, "wb")
|
||||
stderr_file = open(stderr_path, "wb")
|
||||
# O_APPEND ("ab"), not "wb": the child inherits these fds and keeps its own
|
||||
# file offset. Without O_APPEND, the in-place truncate in
|
||||
# `_roll_log_if_oversized` leaves that offset far past the new end of file,
|
||||
# so the next write lands there and the kernel fills everything before it
|
||||
# with a hole of NUL bytes — the log becomes unreadable and the size cap
|
||||
# stops working entirely. O_APPEND makes the kernel seek to EOF atomically
|
||||
# on every write, so a truncate genuinely restarts the file at offset 0.
|
||||
# `_roll_log_to_prev` above already renamed any previous log away, so not
|
||||
# truncating on open costs nothing.
|
||||
stdout_file = open(stdout_path, "ab")
|
||||
stderr_file = open(stderr_path, "ab")
|
||||
try:
|
||||
handle = subprocess.Popen(
|
||||
command,
|
||||
@@ -499,6 +511,11 @@ class ProcessSupervisor:
|
||||
The child holds an open fd to this inode, so a rename would not redirect
|
||||
its writes. Instead keep one rolled generation via copy-to-`.prev` and
|
||||
truncate the live inode in place, freeing the allocated disk blocks.
|
||||
|
||||
This relies on the child's fd being opened with O_APPEND (see `_spawn`):
|
||||
only then does the child resume writing at offset 0 after the truncate.
|
||||
With a plain write fd it would keep writing at its stale offset, punching
|
||||
a multi-hundred-megabyte NUL hole and defeating the cap.
|
||||
"""
|
||||
try:
|
||||
if path.stat().st_size <= _LOG_MAX_BYTES:
|
||||
|
||||
Reference in New Issue
Block a user