diff --git a/labs/12-product-engineering-loop/boatstack-distribution/release-notes/2026-07-26-guard-hydrate-double-check.md b/labs/12-product-engineering-loop/boatstack-distribution/release-notes/2026-07-26-guard-hydrate-double-check.md new file mode 100644 index 000000000..3919f54f3 --- /dev/null +++ b/labs/12-product-engineering-loop/boatstack-distribution/release-notes/2026-07-26-guard-hydrate-double-check.md @@ -0,0 +1,12 @@ +### Concurrent first use hydrates the shared runtime exactly once + +When several tool calls hit an empty shared-runtime slot at the same time, one guard hydrates +the slot and the others wait. A guard tests whether the slot is missing, then takes a +clone-wide lock to hydrate it. A slow guard could reach the lock only after the winner had +already finished and released it. Its test result was stale, so it took the lock and ran the +installer a second time. + +The guard now re-tests the slot after it takes the lock and runs the installer only if the +slot is still missing or incomplete. So exactly one hydration happens under contention. This +also narrows the window where a peer is writing the helper while another guard starts it, +which complements the retry that already handles that case on Linux. diff --git a/labs/12-product-engineering-loop/product-engineering-loop/hooks.go b/labs/12-product-engineering-loop/product-engineering-loop/hooks.go index 4725d5c4e..4e58985ff 100644 --- a/labs/12-product-engineering-loop/product-engineering-loop/hooks.go +++ b/labs/12-product-engineering-loop/product-engineering-loop/hooks.go @@ -170,21 +170,28 @@ if { [[ ! -x "$HELPER" || -L "$HELPER" || ! -f "$MANIFEST" || -L "$MANIFEST" ]]; mkdir -p "$COMMON/boatstack" 2>/dev/null || true HYDRATE_LOCK="$COMMON/boatstack/hydrate-%s.lock" if mkdir "$HYDRATE_LOCK" 2>/dev/null; then - ( - cd "$ROOT" || exit 0 - export BOATSTACK_MODE=hydrate - export BOATSTACK_VERSION="%s" - export BOATSTACK_REPO="$ROOT" - HYDRATE_COMMAND="${BOATSTACK_HYDRATE_COMMAND:-}" - if [[ -z "$HYDRATE_COMMAND" ]]; then - HYDRATE_COMMAND='%s' - fi - if command -v timeout >/dev/null 2>&1; then - timeout 8 /bin/bash -c "$HYDRATE_COMMAND" - else - /bin/bash -c "$HYDRATE_COMMAND" - fi - ) >&2 || true + # Double-checked locking. A slow guard can reach this mkdir only after the + # winner already hydrated and released the lock, so its mkdir succeeds too. + # Re-test the slot now that we hold the lock and run the installer only if it + # is still missing or incomplete, so exactly one hydration happens under + # contention (redundant installer runs also widen the exec-time race window). + if [[ ! -x "$HELPER" || -L "$HELPER" || ! -f "$MANIFEST" || -L "$MANIFEST" ]]; then + ( + cd "$ROOT" || exit 0 + export BOATSTACK_MODE=hydrate + export BOATSTACK_VERSION="%s" + export BOATSTACK_REPO="$ROOT" + HYDRATE_COMMAND="${BOATSTACK_HYDRATE_COMMAND:-}" + if [[ -z "$HYDRATE_COMMAND" ]]; then + HYDRATE_COMMAND='%s' + fi + if command -v timeout >/dev/null 2>&1; then + timeout 8 /bin/bash -c "$HYDRATE_COMMAND" + else + /bin/bash -c "$HYDRATE_COMMAND" + fi + ) >&2 || true + fi rmdir "$HYDRATE_LOCK" 2>/dev/null || true else # A peer holds the hydrate lock. Wait for the peer to finish — it removes the