mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-13 03:48:06 +01:00
train S4: merge #3932 at 7444f6a4ce v1.94.19.0
This commit is contained in:
commit
d36ba8a704
11 files changed
+154
-27
No files matched your search
+55
-8
@@ -8,8 +8,11 @@
|
||||
# shares them.
|
||||
#
|
||||
# Usage:
|
||||
# gstack-lease touch [--root <checkout>] [--pid <p> | --from <pid>]
|
||||
# write <git dir>/gstack-leases/<pid> holding the pid's start identity;
|
||||
# gstack-lease touch [--root <checkout>] [--pid <p> | --from <pid>] [--run <id>]
|
||||
# write <git dir>/gstack-leases/<pid> holding the pid's start identity
|
||||
# and the open run <id> (gstack-skill-start's SESSION_ID); without --run
|
||||
# it records a hold no release closes; a run counts 120 min from its
|
||||
# start and a hold 120 min from its last renewal;
|
||||
# pid defaults to the harness pid behind this call
|
||||
# (bin/gstack-harness-pid.sh, the same derivation the session marker
|
||||
# uses), or behind --from (a caller whose own parent is short-lived
|
||||
@@ -24,8 +27,11 @@
|
||||
# --count-shared-harness (bin/gstack-upgrade only) still prints an
|
||||
# ancestor that is a shared harness (capy-server: every session on the
|
||||
# machine runs under it) while its lease is under 120 minutes old
|
||||
# gstack-lease release --pid <p> --run <id> [--root <checkout>]
|
||||
# close run <id> on <pid>'s lease (gstack-skill-end); once every run it
|
||||
# recorded is closed the lease is idle and live skips it (GST-1205)
|
||||
# gstack-lease list [--root <checkout>]
|
||||
# print `<pid> <age>m alive|dead|stale` for every lease
|
||||
# print `<pid> <age>m alive|idle|dead|stale` for every lease
|
||||
# A pid alone is not a holder: pids are reused after a reboot or a machine
|
||||
# wake. A lease records its process's start identity (Linux: boot id and
|
||||
# /proc start time; elsewhere `ps -o lstart`), and a lease whose pid now
|
||||
@@ -47,12 +53,13 @@ BIN="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
}
|
||||
|
||||
VERB="${1:-}"; [ $# -gt 0 ] && shift
|
||||
ROOT="" PID="" EXCLUDE="" FROM="" SHARED=0
|
||||
ROOT="" PID="" EXCLUDE="" FROM="" SHARED=0 RUN=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--root) ROOT="${2:-}"; shift ;;
|
||||
--pid) PID="${2:-}"; shift ;;
|
||||
--from) FROM="${2:-}"; shift ;;
|
||||
--run) RUN="${2:-}"; shift ;;
|
||||
--exclude-ancestry-of) EXCLUDE="${2:-}"; shift ;;
|
||||
--count-shared-harness) SHARED=1 ;;
|
||||
*) echo "gstack-lease: unknown argument '$1'" >&2; exit 2 ;;
|
||||
@@ -60,8 +67,8 @@ while [ $# -gt 0 ]; do
|
||||
shift
|
||||
done
|
||||
case "$VERB" in
|
||||
touch|live|list) ;;
|
||||
-h|--help|'') sed -n '2,28p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
touch|live|list|release) ;;
|
||||
-h|--help|'') sed -n '2,34p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "gstack-lease: unknown verb '$VERB'" >&2; exit 2 ;;
|
||||
esac
|
||||
[ -n "$ROOT" ] || ROOT=$(gstack_source_root "$BIN")
|
||||
@@ -248,6 +255,15 @@ reclaim() {
|
||||
unlock
|
||||
return 1
|
||||
}
|
||||
# Run entries (GST-1205), lines after the identity: `run <id> <epoch>` per
|
||||
# open run, `hold <epoch>` for a holder that opened none, `idle` once every
|
||||
# run closed. An entry older than 120 minutes no longer counts.
|
||||
# fresh FILE [DROP] — the entries under 120 minutes old, minus the line whose
|
||||
# first two fields are DROP ("run <id>" or "hold").
|
||||
fresh() { sed -n '2,$p' "$1" 2>/dev/null | awk -v now="$(date +%s)" -v drop="${2:-}" '($1 == "run" && NF == 3 && now - $3 < 7200 && $1 " " $2 != drop) || ($1 == "hold" && NF == 2 && now - $2 < 7200 && $1 != drop)'; }
|
||||
# idle FILE — the lease records entries and none of them still counts. A lease
|
||||
# with no entries (written without --run, or by an older gstack) is never idle.
|
||||
idle() { [ -n "$(sed -n '2,$p' "$1" 2>/dev/null | grep -v '^$')" ] && [ -z "$(fresh "$1")" ]; }
|
||||
age_min() { # FILE — minutes since its mtime
|
||||
_m=$(stat -c %Y "$1" 2>/dev/null || stat -f %m "$1" 2>/dev/null || echo 0)
|
||||
echo $(( ( $(date +%s) - _m ) / 60 ))
|
||||
@@ -264,7 +280,20 @@ case "$VERB" in
|
||||
exit 3
|
||||
}
|
||||
_tmp="$DIR/.$PID.$$"
|
||||
identity "$PID" > "$_tmp" && mv -f "$_tmp" "$DIR/$PID" || { rm -f "$_tmp"; unlock; exit 2; }
|
||||
_id=$(identity "$PID") _keep="" _held=0 _now=$(date +%s)
|
||||
if [ -f "$DIR/$PID" ] && [ "$(head -1 "$DIR/$PID" 2>/dev/null)" = "$_id" ]; then
|
||||
if [ -n "$RUN" ]; then _keep=$(fresh "$DIR/$PID" "run $RUN"); else _keep=$(fresh "$DIR/$PID" hold); fi
|
||||
[ -z "$(sed -n '2,$p' "$DIR/$PID" 2>/dev/null | grep -v '^$')" ] && _held=1
|
||||
fi
|
||||
{
|
||||
printf '%s\n' "$_id"
|
||||
[ -z "$_keep" ] || printf '%s\n' "$_keep"
|
||||
if [ -n "$RUN" ]; then
|
||||
[ "$_held" -eq 1 ] && echo "hold $(stat -c %Y "$DIR/$PID" 2>/dev/null || stat -f %m "$DIR/$PID" 2>/dev/null || echo "$_now")"
|
||||
echo "run $RUN $_now"
|
||||
elif [ -n "$_keep" ]; then echo "hold $_now"
|
||||
fi
|
||||
} > "$_tmp" && mv -f "$_tmp" "$DIR/$PID" || { rm -f "$_tmp"; unlock; exit 2; }
|
||||
find "$DIR" -maxdepth 1 -mmin +120 -type f ! -name '.lock*' -exec rm -f {} + 2>/dev/null
|
||||
for _c in "$DIR"/.lock*.claim.*; do
|
||||
[ -f "$_c" ] || continue
|
||||
@@ -274,12 +303,29 @@ case "$VERB" in
|
||||
rm -rf "$DIR"/.lock*.gone.* 2>/dev/null
|
||||
unlock
|
||||
exit 0 ;;
|
||||
release)
|
||||
case "$PID" in ''|*[!0-9]*) echo "gstack-lease: release needs --pid <number> and --run <id>" >&2; exit 2 ;; esac
|
||||
[ -n "$RUN" ] && [ "$RUN" != - ] || { echo "gstack-lease: release needs --pid <number> and --run <id>" >&2; exit 2; }
|
||||
[ -f "$DIR/$PID" ] || exit 0
|
||||
lock || exit 3
|
||||
f="$DIR/$PID" _tmp="$DIR/.$PID.$$"
|
||||
if sed -n '2,$p' "$f" | awk -v id="$RUN" '$1 == "run" && $2 == id { found = 1 } END { exit !found }'; then
|
||||
_keep=$(fresh "$f" "run $RUN")
|
||||
{
|
||||
head -1 "$f"
|
||||
if [ -n "$_keep" ]; then printf '%s\n' "$_keep"; else echo idle; fi
|
||||
} > "$_tmp" && touch -r "$f" "$_tmp" && mv -f "$_tmp" "$f" || { rm -f "$_tmp"; unlock; exit 2; }
|
||||
fi
|
||||
unlock
|
||||
exit 0 ;;
|
||||
list)
|
||||
for f in "$DIR"/*; do
|
||||
[ -f "$f" ] || continue
|
||||
p=${f##*/}
|
||||
_age=$(age_min "$f")
|
||||
echo "$p ${_age}m $(state "$p" "$(head -1 "$f" 2>/dev/null)" "$_age")"
|
||||
_st=$(state "$p" "$(head -1 "$f" 2>/dev/null)" "$_age")
|
||||
[ "$_st" = alive ] && idle "$f" && _st=idle
|
||||
echo "$p ${_age}m $_st"
|
||||
done
|
||||
exit 0 ;;
|
||||
esac
|
||||
@@ -296,6 +342,7 @@ done
|
||||
FOUND=1
|
||||
for f in "$DIR"/*; do
|
||||
[ -f "$f" ] || continue
|
||||
idle "$f" && continue
|
||||
p=${f##*/}
|
||||
_age=$(age_min "$f")
|
||||
case "$ANCESTRY" in *" $p "*) [ "$SHARED" -eq 1 ] && [ "$_age" -lt 120 ] && gstack_shared_harness "$p" || continue ;; esac
|
||||
|
||||
@@ -57,6 +57,9 @@ _TEL_END=$(date +%s)
|
||||
case "$TEL_START" in ''|*[!0-9]*) TEL_START="$_TEL_END" ;; esac
|
||||
_TEL_DUR=$(( _TEL_END - TEL_START ))
|
||||
[ -n "$SESSION_ID" ] && rm -f "$_GH/analytics/.pending-$SESSION_ID" 2>/dev/null || true
|
||||
# Release the workflow lease run gstack-skill-start opened (SESSION_ID starts
|
||||
# with its harness pid), so a finished run stops blocking gstack-upgrade (GST-1205).
|
||||
[ -n "$SESSION_ID" ] && "$_BIN/gstack-lease" release --pid "${SESSION_ID%%-*}" --run "$SESSION_ID" >/dev/null 2>&1 || true
|
||||
|
||||
# Record completion before the final drain, including its durable enqueue.
|
||||
# The normal sync gates still decide publication: full may sync timelines,
|
||||
|
||||
+11
-9
@@ -127,13 +127,6 @@ fi
|
||||
mkdir -p "$_GH/sessions" 2>/dev/null || true
|
||||
touch "$_GH/sessions/$PARENT_PID" 2>/dev/null || true
|
||||
find "$_GH/sessions" -mmin +120 -type f -exec rm {} + 2>/dev/null || true
|
||||
# The install-scoped twin (bin/gstack-lease): what bin/gstack-upgrade reads
|
||||
# before moving a checkout other sessions share. Fail-open, but a lease the
|
||||
# held lock kept from being written is reported.
|
||||
"$_BIN/gstack-lease" touch --pid "$PARENT_PID" >/dev/null 2>&1 || {
|
||||
[ $? -eq 3 ] && echo "gstack-lease: the lease directory stayed locked by a live process; this session holds no workflow lease, so bin/gstack-upgrade cannot see it" >&2
|
||||
true
|
||||
}
|
||||
_SESSIONS=$(find "$_GH/sessions" -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
|
||||
|
||||
_PROACTIVE=$("$_BIN/gstack-config" get proactive 2>/dev/null || echo "core")
|
||||
@@ -241,9 +234,18 @@ _TEL_PROMPTED=$([ -f "$_GH/.telemetry-prompted" ] && echo "yes" || echo "no")
|
||||
_TEL_START=$(date +%s)
|
||||
# PID+epoch alone is guessable; a random suffix makes the block-binding token
|
||||
# unforgeable by content reflected into the same tool result. Falls back to
|
||||
# the plain form when urandom is unavailable.
|
||||
# this process's pid when urandom is unavailable, so two same-second starts
|
||||
# never share a SESSION_ID (it also keys their lease runs, GST-1205).
|
||||
_SID_RAND=$(od -An -N4 -tx4 /dev/urandom 2>/dev/null | tr -d ' \n' || true)
|
||||
_SESSION_ID="$PARENT_PID-$_TEL_START${_SID_RAND:+-$_SID_RAND}"
|
||||
_SESSION_ID="$PARENT_PID-$_TEL_START-${_SID_RAND:-$$}"
|
||||
# The install-scoped twin (bin/gstack-lease): what bin/gstack-upgrade reads
|
||||
# before moving a checkout other sessions share. This run holds it until
|
||||
# gstack-skill-end releases its SESSION_ID (GST-1205). Fail-open, but a lease
|
||||
# the held lock kept from being written is reported.
|
||||
"$_BIN/gstack-lease" touch --pid "$PARENT_PID" --run "$_SESSION_ID" >/dev/null 2>&1 || {
|
||||
[ $? -eq 3 ] && echo "gstack-lease: the lease directory stayed locked by a live process; this session holds no workflow lease, so bin/gstack-upgrade cannot see it" >&2
|
||||
true
|
||||
}
|
||||
echo "TELEMETRY: ${_TEL:-off}"
|
||||
echo "TEL_PROMPTED: $_TEL_PROMPTED"
|
||||
echo "SESSION_ID: $_SESSION_ID"
|
||||
|
||||
Reference in new issue
Block a user