Skip to content

uv-manager 0.6.0

Choose a tag to compare

@glentner glentner released this 26 Aug 22:57
· 60 commits to main since this release
0.6.0
7f386fd

Hardening for the provisioning lock, which coordinates uv installation across concurrent
invocations on a shared filesystem. One defect in it was reachable at shipped defaults on ordinary
many-rank job launches; the rest needed a long hold or a misconfiguration.

Eighteen commits since 0.5.0, but only one changes anything a site deploys. The other seventeen are
the .agents/ factory and its records.

Fixes

A released lock is no longer misdiagnosed as a broken filesystem. uvm_acquire_lock decided why
mkdir failed by looking at the filesystem again afterwards. That inference is unsound — the lock is
gone either because the mount is unwritable or because a holder released in the interim — and it
killed ranks with check permissions and quota on a healthy filesystem. Contention is now told from
failure by persistence: the waiter retries and reports the fault only after a bounded number of
attempts have each found the lock absent. Measured in 64-way concurrent cold bursts: 0 of 1280
ranks failing, against 21 of 1280 on 0.5.0.
This is the one that affects everybody.

A lock is released only by the process that holds it. Release matched on the path, so a holder
whose lock had been broken as stale removed the breaker's lock instead — leaving two processes
provisioning one tree with no mutual exclusion between them. uvm_acquire_lock now records a
host/pid/nonce line in the lock's owner file and removes the directory only while that line is
still its own.

A live holder's lock is no longer broken as stale. A detached refresher rewrites the owner file
every UVM_LOCK_STALE/10 seconds, so a hold longer than the threshold survives. Age is read from the
owner file rather than the directory, whose mtime does not track writes to files inside it.

No lock survives an exec. exec replaces the process image and the EXIT trap never runs. All
four exec sites now release first.

A stale lock that cannot be removed no longer defeats UVM_LOCK_TIMEOUT. A denied break used to
retry immediately, spinning without bound and re-announcing itself every iteration.

The timeout message names the holder and a recovery command that works. It prints the recorded
owner line, states that the pid belongs to the host recorded beside it rather than the reader's,
and advises rm -f '<lock>/owner' && rmdir '<lock>'. The old advice was a bare rmdir, which
reports Directory not empty for every lock whose holder got as far as claiming it.

Breaking change for a misconfigured site

UVM_LOCK_TIMEOUT must now be less than UVM_LOCK_STALE, and the inversion is refused rather than
acted on.
A waiter that outlives the stale threshold breaks the lock it is waiting for. A site
running an inverted pair today will get a hard failure at provisioning time with a message naming
both variables and the seconds it judged.

Both knobs are now read as decimal seconds. UVM_LOCK_STALE=0600 previously meant 384 seconds,
because bash reads a leading zero as octal; it now means 600. Check any zero-padded values in your
site configuration.

Known issue

A rank that wins the lock and has its directory removed by a losing stale-breaker exits 1 with empty
stdout. It needs a pre-existing abandoned lock plus concurrent contention; measured at 0 of 2304
ranks on the ordinary cold-start path
, and 3–4 of 1280 against a deliberately planted abandoned
lock. 0.5.0 does not fail this way, but loses far more ranks to the defect fixed above. The remedy is
scoped and queued as the next cycle.

Upgrading

Sites tracking a moving main already have this. Sites deploying a pinned tag need to clone 0.6.0
into a new prefix. The Lmod modulefile derives its prefix from myModuleVersion() and needs no edit;
a site that deploys per-version modulefiles has to add one.

git clone and rsync -a preserve the bin/ symlinks that make uv, uvx, uvm and
uv-manager one script. See README.md § For administrators: deployment.

🤖 Generated with Claude Code