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
+1
View File
@@ -108,6 +108,7 @@ jobs:
tests/test_dependency_errors.py \
tests/test_production_logging.py \
tests/test_delivery.py \
tests/test_delivery_io.py \
tests/test_operator_imports.py \
tests/test_health.py \
tests/test_identity.py \
+113
View File
@@ -6,7 +6,9 @@ import importlib
import json
import os
import sys
import threading
import time
from collections.abc import Sequence
from pathlib import Path
import pytest
@@ -200,3 +202,114 @@ def test_fixed_regular_transfer_preserves_exact_bytes_and_offsets(
file_copy.transfer(incoming, outgoing, length, deadline=time.monotonic() + 30)
assert target.read_bytes() == content
assert policy.digest(target) == policy.digest(source)
def test_copy_inventory_prefetch_is_bounded_and_results_keep_input_order():
# Trusted callbacks only: ordinary concurrency control, no VM/Root acceptance.
release, saturated, second = (threading.Event() for _ in range(3))
lock = threading.Lock()
consumed, results, errors = [], [], []
active = maximum = 0
class Inventory(Sequence):
def __len__(self):
return 32
def __getitem__(self, index):
if not 0 <= index < len(self):
raise IndexError
with lock:
consumed.append(index)
return index
def copy(index):
nonlocal active, maximum
with lock:
active += 1
maximum = max(active, maximum)
if active == 4:
saturated.set()
try:
assert release.wait(5)
if index == 0:
assert second.wait(5)
if index == 1:
second.set()
return index * 3
finally:
with lock:
active -= 1
def collect():
try:
results.extend(file_copy.bounded_copies(Inventory(), copy))
except BaseException as error:
errors.append(error)
collector = threading.Thread(target=collect)
collector.start()
try:
assert saturated.wait(5)
with lock:
assert consumed == [0, 1, 2, 3]
assert maximum == 4
finally:
release.set()
collector.join(10)
assert not collector.is_alive() and not errors
assert results == [index * 3 for index in range(32)]
assert active == 0 and maximum == 4
def test_copy_failure_joins_dispatched_calls_before_propagating():
# No files/privileges: observe failure quiescence of trusted callbacks.
together = threading.Barrier(4)
release, failing, returned = (threading.Event() for _ in range(3))
lock = threading.Lock()
active = 0
errors, active_when_returned = [], []
def copy(index):
nonlocal active
with lock:
active += 1
try:
if index < 4:
together.wait(timeout=5)
if index == 0:
failing.set()
raise policy.DeliveryError("ordinary callback refusal model")
assert release.wait(5)
return index
finally:
with lock:
active -= 1
def collect():
try:
file_copy.bounded_copies(list(range(32)), copy)
except BaseException as error:
errors.append(error)
finally:
with lock:
active_when_returned.append(active)
returned.set()
collector = threading.Thread(target=collect)
collector.start()
try:
assert failing.wait(5)
assert not returned.wait(0.05)
finally:
release.set()
collector.join(10)
assert not collector.is_alive() and active_when_returned == [0]
assert len(errors) == 1 and isinstance(errors[0], policy.DeliveryError)
assert str(errors[0]) == "ordinary callback refusal model"
def test_expired_copy_deadline_refuses_before_dispatch():
calls = []
with pytest.raises(policy.DeliveryError, match="copy deadline exceeded"):
file_copy.bounded_copies(list(range(8)), calls.append, deadline=time.monotonic() - 1)
assert calls == []
+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
):