This commit was merged in pull request #813.
This commit is contained in:
@@ -381,6 +381,22 @@ function isMissingFile(error: unknown): boolean {
|
||||
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-blocking acquire of the roster mutation lock: an exclusive `wx` create that
|
||||
* throws `concurrent-mutation` (never waits) if the lock is already held. The
|
||||
* on-disk format is an empty private file. CRUD releases in a plain `finally` with
|
||||
* no result-preservation logic, so a release fault here must not override the
|
||||
* mutation result — the release swallows unlink failures by design.
|
||||
*
|
||||
* The recovery-framed `fleet regen` contends on this exact same lock file, but it
|
||||
* does so through the hardened, ownership-proving acquirer in the reconciler
|
||||
* (`acquirePrivateRosterMutationLock`), not this one: whoever wins the `wx` create
|
||||
* owns the file (the loser always gets `concurrent-mutation`), so the reconciler's
|
||||
* ownership token is only ever written and read back by the same regen invocation,
|
||||
* never by this empty-file writer. The two acquirers stay mutually compatible at
|
||||
* the `wx`-contention layer while regen additionally proves ownership before it
|
||||
* unlinks — a guarantee CRUD does not need because it releases unconditionally.
|
||||
*/
|
||||
async function acquireMutationLock(lockPath: string): Promise<() => Promise<void>> {
|
||||
try {
|
||||
const handle = await open(lockPath, 'wx', 0o600);
|
||||
|
||||
Reference in New Issue
Block a user