feat(cargo-cache): hardlink-clone a per-ref Cargo cache from a published snapshot
Replaces the phase-0 resolution probe with the real actions, merging the two independent per-branch Cargo cache implementations on this forge into the design neither of them had. ## The merge - zemyna seeds a PR branch by `cp -al` hardlink clone (near-free: cost scales with inode count, not bytes) from the base branch's LIVE target dir — a torn read waiting for a second job slot (its own #911). - emowheel seeds from a PUBLISHED IMMUTABLE SNAPSHOT (no race by construction) but with `cp -a`, duplicating ~35 GB per branch. This ships hardlink-clone FROM a published snapshot: zemyna's cost profile, emowheel's soundness, and #911 closed structurally rather than by the runner happening to have one execution slot. ## The bug both implementations have A build inside a `cp -al` clone DOES mutate the directory it was cloned from. Cargo replaces real artifacts, but writes its metadata — and build scripts write their OUT_DIR — with a plain truncating write, straight through the shared inode. Measured set: `.fingerprint/<unit>/dep-<target>` (under CARGO_UNSTABLE_CHECKSUM_FRESHNESS), `build/<pkg>/{output,root-output,out/**}`, `deps/*.d` and `<profile>/*.d`. The checksum-freshness case is a wrong answer, not a slow build: a PR clone rewrites the base's dep-info to describe the PR's sources while the base's cache still holds the artifact built from the base's; once the PR merges, the base's next run finds the checksums match, reports `Fresh`, and links a binary built from the pre-merge code. Reproduced end to end. Fix: hardlink the artifacts (the GB), real-copy the metadata (the MB) — about 3.7% of a 6.9 GB Bevy target dir, against 100% for a full copy. ## Contents - `cargo-cache/action.yml` — consume: resolve keys, seed from the base's snapshot via staging + one atomic rename, strip Cargo lock files, unshare the mutable paths, restore mtimes from git history, lock, prune. - `cargo-cache-publish/action.yml` — publish: record the build watermark, atomically republish the snapshot on a protected branch, release the lock (`mode: release-lock` for the `if: always()` step). - `scripts/` — all logic, so it is testable standalone; the YAML is wiring. - `scripts/*selftest.sh` + `selftest.sh` — five suites, 63 assertions, every fix paired with a control that reproduces the bug. All green locally. Eviction merges emowheel's liveness pass (dead branches pruned unconditionally, not gated on disk pressure) with LRU-under-pressure, but inverts the order within the pressure pass: `target-*` before `snapshot-*`, because a snapshot is hardlinked to everything cloned from it, so evicting one frees almost no real bytes while costing every future PR its warm start. restore-mtimes.sh is ported from emowheel (the watermark variant, which closes the merge hazard zemyna's copy still has) with its provenance de-projectised. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sqh2vscfzisk83VuPVQX9L
This commit is contained in:
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Runs every selftest in this directory and reports a single verdict.
|
||||
#
|
||||
# bash scripts/selftest.sh # everything
|
||||
# bash scripts/selftest.sh --fast # skip the ones that invoke a compiler
|
||||
#
|
||||
# The compiler-backed tests (hardlink-clone, restore-mtimes) are the ones that
|
||||
# verify behaviour against real Cargo rather than against a fixture, so
|
||||
# --fast is for iterating, not for signing off a change.
|
||||
set -uo pipefail
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
FAST=0
|
||||
[ "${1:-}" = "--fast" ] && FAST=1
|
||||
|
||||
FIXTURE_TESTS=(seed-target-dir-selftest.sh publish-snapshot-selftest.sh prune-cache-selftest.sh)
|
||||
CARGO_TESTS=(hardlink-clone-selftest.sh restore-mtimes-selftest.sh)
|
||||
|
||||
TESTS=("${FIXTURE_TESTS[@]}")
|
||||
if [ "$FAST" = "0" ]; then TESTS+=("${CARGO_TESTS[@]}"); fi
|
||||
|
||||
failed=()
|
||||
for t in "${TESTS[@]}"; do
|
||||
echo
|
||||
echo "############################################################"
|
||||
echo "# $t"
|
||||
echo "############################################################"
|
||||
if bash "$script_dir/$t"; then
|
||||
echo "--> $t OK"
|
||||
else
|
||||
echo "--> $t FAILED"
|
||||
failed+=("$t")
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
if [ "${#failed[@]}" -eq 0 ]; then
|
||||
echo "selftest: all ${#TESTS[@]} suites passed"
|
||||
[ "$FAST" = "1" ] && echo "NOTE: --fast skipped ${CARGO_TESTS[*]}"
|
||||
exit 0
|
||||
fi
|
||||
echo "selftest: ${#failed[@]} of ${#TESTS[@]} suites FAILED: ${failed[*]}"
|
||||
exit 1
|
||||
Reference in New Issue
Block a user