perf(delivery): bound copy I/O and streamline metadata scans

This commit is contained in:
2026-10-20 03:51:01 +08:00
parent 02c1dadf67
commit ee9ebd6d24
7 changed files with 235 additions and 42 deletions
+6
View File
@@ -408,6 +408,12 @@ failure. Further bundles receive full verification; separate commands start fres
Fixed-size regular-file copies can use Linux kernel transfer with bounded chunks.
Unsupported transfer falls back at the same offsets. Source size/EOF, file fsync
and independent destination byte verification remain required.
Verified installer and stopped-node recovery inventories can keep at most four
file operations in flight. Each file retains its durability and byte checks;
directory finalization and success receipts wait for all dispatched work. On
failure, queued work is cancelled and running calls are joined before the error
returns. Private partial data is retained for inspection. The original operator
CPU, memory, PID and deadline limits still apply.
Old configuration and maintenance receipts go into inactive
`recovery/ID/history/`. The new boot's Sandbox preparation owns cgroup recreation.
Unknown/nonempty targets and differing existing files are refused; partial restores
+52 -1
View File
@@ -4,12 +4,63 @@ import errno
import os
import stat
import time
from typing import BinaryIO
from collections.abc import Callable, Sequence
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
from itertools import islice
from typing import BinaryIO, cast
from .policy import MAX_FILE_BYTES, DeliveryError
CHUNK = 1024 * 1024
UNSUPPORTED = {errno.ENOSYS, errno.EINVAL, errno.EOPNOTSUPP, errno.EXDEV}
IN_FLIGHT = 4
def bounded_copies[Item, Result](
rows: Sequence[Item],
operation: Callable[[Item], Result],
*,
deadline: float | None = None,
) -> list[Result]:
"""Join a finite verified inventory, with at most four operations in flight."""
def remaining() -> float | None:
if deadline is None:
return None
value = deadline - time.monotonic()
if value <= 0:
raise DeliveryError("copy deadline exceeded; private partial target retained")
return value
remaining()
if len(rows) < 2:
return [operation(row) for row in rows]
results: list[Result | None] = [None] * len(rows)
source = iter(enumerate(rows))
with ThreadPoolExecutor(max_workers=min(IN_FLIGHT, len(rows))) as executor:
pending = {
executor.submit(operation, row): index for index, row in islice(source, IN_FLIGHT)
}
try:
while pending:
ready, _ = wait(pending, timeout=remaining(), return_when=FIRST_COMPLETED)
if not ready:
raise DeliveryError("copy deadline exceeded; private partial target retained")
# Observe every completed failure before dispatching more work.
completed = [(pending.pop(future), future.result()) for future in ready]
for index, result in completed:
results[index] = result
following = next(source, None)
if following is not None:
index, row = following
remaining()
pending[executor.submit(operation, row)] = index
finally:
for future in pending:
future.cancel()
# The executor joins running calls before this function can return
# or propagate an error. No success receipt can outrun file I/O.
return cast(list[Result], results)
def _identity(info: os.stat_result) -> tuple[int, ...]:
+4 -1
View File
@@ -235,7 +235,8 @@ def frozen_copy(
target.mkdir(mode=0o700)
for name in sorted(directories, key=lambda name: (name.count("/"), name)):
(target / name).mkdir(mode=0o700)
for record in records:
def copy(record: dict) -> None:
# The complete sealed tree is read back immediately below. Avoid
# hashing each destination both here and again in that inventory.
_copy_verified(
@@ -246,6 +247,8 @@ def frozen_copy(
readback=False,
expected_bytes=record["bytes"],
)
file_copy.bounded_copies(records, copy)
for name in sorted(directories, key=lambda name: name.count("/"), reverse=True):
(target / name).chmod(0o555)
sync_directory(target / name)
+47 -30
View File
@@ -45,24 +45,24 @@ _MAX_SCOPED_METADATA = 2 * MAX_METADATA_BYTES
def _bundle_signature(bundle: Path) -> dict[str, tuple[int, ...]]:
"""Observe topology and all metadata that can invalidate a prior byte read."""
if not bundle.is_dir() or bundle.is_symlink():
raise DeliveryError("bundle directory required")
members = set()
for path in bundle.iterdir():
members.add(path.name)
if len(members) > 2:
raise DeliveryError("unexpected bundle member")
if members != {"manifest.json", "payload"}:
flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW | os.O_CLOEXEC
descriptor = os.open(bundle, flags)
members = {}
try:
root = os.fstat(descriptor)
with os.scandir(descriptor) as entries:
for entry in entries:
members[entry.name] = entry.stat(follow_symlinks=False)
if len(members) > 2:
raise DeliveryError("unexpected bundle member")
finally:
os.close(descriptor)
if set(members) != {"manifest.json", "payload"}:
raise DeliveryError("unexpected bundle member")
result = {}
def add(path: Path, *, directory: bool) -> None:
info = path.lstat()
if not (stat.S_ISDIR(info.st_mode) if directory else stat.S_ISREG(info.st_mode)):
raise DeliveryError("bundle proof requires ordinary directories and files")
if not directory and info.st_nlink != 1:
raise DeliveryError("bundle proof requires single-link files")
result[path.relative_to(bundle).as_posix()] = (
def identity(info: os.stat_result) -> tuple[int, ...]:
return (
info.st_dev,
info.st_ino,
info.st_mode,
@@ -73,25 +73,42 @@ def _bundle_signature(bundle: Path) -> dict[str, tuple[int, ...]]:
info.st_mtime_ns,
info.st_ctime_ns,
)
def add(name: str, info: os.stat_result, *, directory: bool) -> None:
if not (stat.S_ISDIR(info.st_mode) if directory else stat.S_ISREG(info.st_mode)):
raise DeliveryError("bundle proof requires ordinary directories and files")
if not directory and info.st_nlink != 1:
raise DeliveryError("bundle proof requires single-link files")
result[name] = identity(info)
if len(result) > MAX_FILES + 3:
raise DeliveryError("bundle proof entry count limit")
def failed(error: OSError) -> None:
raise error
add(bundle, directory=True)
add(bundle / "manifest.json", directory=False)
add(".", root, directory=True)
add("manifest.json", members["manifest.json"], directory=False)
payload = bundle / "payload"
add(payload, directory=True)
for directory, names, files in os.walk(payload, followlinks=False, onerror=failed):
for name in names:
path = Path(directory) / name
relative_name(path.relative_to(payload).as_posix() + "/.__directory__")
add(path, directory=True)
for name in files:
path = Path(directory) / name
relative_name(path.relative_to(payload).as_posix())
add(path, directory=False)
add("payload", members["payload"], directory=True)
pending = [(str(payload), "", result["payload"])]
while pending:
directory, prefix, expected = pending.pop()
# Close each iterator before visiting another directory. Wide or deep
# verified inventories never require one open descriptor per directory.
descriptor = os.open(directory, flags)
try:
if identity(os.fstat(descriptor)) != expected:
raise DeliveryError("verified bundle changed during the operator operation")
with os.scandir(descriptor) as entries:
for entry in entries:
name = prefix + entry.name
info = entry.stat(follow_symlinks=False)
is_directory = stat.S_ISDIR(info.st_mode)
relative_name(name + "/.__directory__" if is_directory else name)
add("payload/" + name, info, directory=is_directory)
if is_directory:
pending.append(
(os.path.join(directory, entry.name), name + "/", identity(info))
)
finally:
os.close(descriptor)
return result
+12 -10
View File
@@ -121,7 +121,7 @@ def target(record: dict, recovery: Path) -> tuple[Path, int, int, int]:
return path, 0, 0, 0o700 if "bytes" not in record else 0o600
def member(path: Path, uid: int, gid: int, mode: int, *, directory: bool) -> None:
def member(path: Path, uid: int, gid: int, mode: int, *, directory: bool) -> os.stat_result:
info = path.lstat()
if (
(info.st_uid, info.st_gid, stat.S_IMODE(info.st_mode)) != (uid, gid, mode)
@@ -129,6 +129,7 @@ def member(path: Path, uid: int, gid: int, mode: int, *, directory: bool) -> Non
or (not directory and info.st_nlink != 1)
):
raise DeliveryError("existing recovery destination differs; no overwrite")
return info
def file_witness(info: os.stat_result) -> tuple[int, ...]:
@@ -148,8 +149,7 @@ def file_witness(info: os.stat_result) -> tuple[int, ...]:
def readback(
path: Path, item: dict, uid: int, gid: int, mode: int, deadline: float
) -> tuple[int, ...]:
member(path, uid, gid, mode, directory=False)
before = file_witness(path.lstat())
before = file_witness(member(path, uid, gid, mode, directory=False))
descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_CLOEXEC)
with os.fdopen(descriptor, "rb") as stream:
if file_witness(os.fstat(stream.fileno())) != before:
@@ -169,8 +169,7 @@ def readback(
def unchanged_file(path: Path, witness: tuple[int, ...], uid: int, gid: int, mode: int) -> None:
member(path, uid, gid, mode, directory=False)
if file_witness(path.lstat()) != witness:
if file_witness(member(path, uid, gid, mode, directory=False)) != witness:
raise DeliveryError("verified recovery file changed before completion")
@@ -290,12 +289,15 @@ def restore(recovery_id: str, backup_id: str, expected: str) -> dict:
free = os.statvfs(Path("/var/lib/kf-onlinejudge"))
if free.f_frsize * free.f_bavail < value["payload_bytes"] + 128 * 1024**2:
raise DeliveryError("cold recovery destination reserve insufficient")
verified = {}
for item in value["files"]:
def copy(item: dict) -> tuple[int, ...]:
path, uid, gid, mode = target(item, recovery)
verified[item["path"]] = write_file(
root / "payload" / item["path"], path, item, uid, gid, mode, deadline
)
return write_file(root / "payload" / item["path"], path, item, uid, gid, mode, deadline)
witnesses = file_copy.bounded_copies(value["files"], copy, deadline=deadline)
verified = {
item["path"]: witness for item, witness in zip(value["files"], witnesses, strict=True)
}
for item in sorted(
value["directories"], key=lambda row: row["path"].count("/"), reverse=True
):