fix(wake): #908 unify observed_seq on a single store-side allocator (dissolve detector-private-counter seam) (#915)
Co-authored-by: jason.woltje <jason@diversecanvas.com> Co-committed-by: jason.woltje <jason@diversecanvas.com>
This commit was merged in pull request #915.
This commit is contained in:
@@ -65,6 +65,51 @@ _atomic_write() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Enqueue serialization (single store-side observed_seq allocator, #908).
|
||||
#
|
||||
# store.sh is the SOLE allocator of observed_seq: it reads the observed_seq
|
||||
# cursor, computes next = observed_seq + 1, and writes the pending record +
|
||||
# observed.set + the cursor as ONE transaction. That read-modify-write MUST be
|
||||
# serialized so two concurrent enqueues cannot read the same cursor and collide
|
||||
# on a seq. These helpers take an exclusive lock for the duration of the
|
||||
# transaction. flock (Linux/CI) is the load-bearing mechanism; where flock is
|
||||
# absent the open still succeeds so a single-threaded enqueue is unaffected (the
|
||||
# concurrency guarantee then degrades — the concurrency test SKIPs without flock,
|
||||
# exactly as the detector's single-instance test already does).
|
||||
#
|
||||
# The lock uses a FIXED fd (8) within one store.sh process. Each store.sh
|
||||
# invocation is its own process (the detector/reconciler call it as a
|
||||
# subprocess), so fd 8 is always free here and never clashes with the detector
|
||||
# run-loop lock (fd 9, a DIFFERENT process).
|
||||
# ---------------------------------------------------------------------------
|
||||
_wake_lock_acquire() {
|
||||
# _wake_lock_acquire LOCKFILE — open fd 8 on LOCKFILE and take an exclusive
|
||||
# (blocking) lock. Returns non-zero if the lock cannot be taken.
|
||||
local lf="$1" dir
|
||||
dir="$(dirname "$lf")"
|
||||
[ -d "$dir" ] || mkdir -p "$dir" 2>/dev/null || true
|
||||
# Open the lock fd. If the file does not yet exist and the dir is writable it
|
||||
# is created; if the dir is read-only but the file exists, opening it O_WRONLY
|
||||
# still succeeds (write perm on the file, not the dir).
|
||||
# NB: a command-less `exec` redirection persists for the WHOLE shell, so we must
|
||||
# NOT append `2>/dev/null` here (it would permanently silence the caller's
|
||||
# stderr and swallow every later fail-loud diagnostic). Redirect only fd 8.
|
||||
exec 8>"$lf" || return 1
|
||||
if command -v flock >/dev/null 2>&1; then
|
||||
flock 8 || return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_wake_lock_release() {
|
||||
# _wake_lock_release — drop the enqueue lock (closing fd 8 releases the flock).
|
||||
# The `2>/dev/null` is SCOPED to the brace group (suppressing a "bad fd" close
|
||||
# error) — it must NOT sit on a bare `exec`, where the redirection would persist
|
||||
# for the whole shell and silence every later fail-loud diagnostic.
|
||||
{ exec 8>&-; } 2>/dev/null || true
|
||||
}
|
||||
|
||||
# _wake_clean_stale_tmp DIR — remove leftover atomic-write temp files (e.g. from
|
||||
# a crash mid-write). Safe: these are never the live store.
|
||||
_wake_clean_stale_tmp() {
|
||||
|
||||
Reference in New Issue
Block a user