crates/storage-git-gix/parked-gix/.nornir/bench/have-mix.sh
#!/bin/bash
# Derive the REAL hit/miss mix and the REAL round sizes of a negotiation's `have`
# list, by running actual `git fetch`es against the 19 mirrored
# workspace_nordisk repositories and asking the SERVER whether it holds each oid
# the CLIENT offered.
#
# The client is made genuinely behind: reset, drop the remote-tracking ref, expire
# the reflog and `gc --prune=now`, so the newer objects are really gone. Without
# that the client still holds everything, git says "up to date", and the trace
# contains no `have` at all — which is exactly what the first version of this
# script measured.
#
# Two shapes:
# behind-<D> : client D commits behind the server, no local work.
# divergent-<K> : client 10 behind AND holding K local commits of its own.
#
# The haves are taken off the wire (GIT_TRACE_PACKET), not modelled.
#
# LAW 2, added 2026-08-04. Every bail-out below is `|| continue`, which is right
# for one repository that cannot be shaped and catastrophic as a whole-script
# outcome: with the corpus absent the glob stays literal, every iteration
# `continue`s, and the script prints `rows: 0` and exits **0**. Empty output is
# shaped exactly like a legitimate result. Three things now make that impossible:
#
# * the corpus directory and the glob are checked before the loop;
# * `git cat-file`'s answer is checked to have one line per `have` — it is
# `paste`d against them positionally, so a short read does not fail, it
# SHIFTS every later hit onto the wrong oid, and a completely failed read
# reports a 100% miss rate as a measurement;
# * `rows: 0` is a non-zero exit.
set -u -o pipefail
MIRRORS=${HAVE_MIX_MIRRORS:-/home/rickard/scratch/gunnar-bench-fixtures/real-corpus}
WORK=/home/rickard/scratch/have-mix
OUT=/home/rickard/scratch/have-mix.tsv
die() { echo "FATAL: $*" >&2; exit 1; }
[ -d "$MIRRORS" ] || die "no corpus at $MIRRORS. Build it with the real-corpus \
fixture (nornir-bench) or point HAVE_MIX_MIRRORS at one. A missing corpus makes \
every loop below \`continue\` and the script exits 0 having measured nothing."
shopt -s nullglob
MIRROR_DIRS=("$MIRRORS"/*.git)
[ "${#MIRROR_DIRS[@]}" -gt 0 ] || die "$MIRRORS holds no *.git mirror"
rm -rf "$WORK"; mkdir -p "$WORK"
printf 'repo\tshape\tround\thaves\thits\tmisses\n' > "$OUT"
export GIT_LFS_SKIP_SMUDGE=1
for m in "${MIRROR_DIRS[@]}"; do
repo=$(basename "$m" .git)
br=$(git -C "$m" symbolic-ref --short HEAD 2>/dev/null) || continue
n=$(git -C "$m" rev-list --count "$br" 2>/dev/null || echo 0)
[ "$n" -lt 25 ] && continue
for shape in behind-1 behind-10 behind-100 behind-400 divergent-1 divergent-10 divergent-40 divergent-200; do
depth=${shape#*-}
case "$shape" in
behind-*) back=$depth; local_k=0 ;;
divergent-*) back=10; local_k=$depth ;;
esac
[ "$back" -ge "$n" ] && continue
c="$WORK/$repo-$shape"
rm -rf "$c"
git clone --quiet --no-tags --single-branch --branch "$br" "file://$m" "$c" >/dev/null 2>&1 || continue
git -C "$c" reset --quiet --hard "HEAD~$back" 2>/dev/null || { rm -rf "$c"; continue; }
git -C "$c" update-ref -d "refs/remotes/origin/$br" 2>/dev/null
git -C "$c" update-ref -d refs/remotes/origin/HEAD 2>/dev/null
rm -f "$c/.git/FETCH_HEAD"
git -C "$c" reflog expire --expire=now --all >/dev/null 2>&1
git -C "$c" gc --prune=now --quiet >/dev/null 2>&1
i=0
while [ "$i" -lt "$local_k" ]; do
git -C "$c" -c user.name=b -c user.email=b@b commit --quiet --allow-empty -m "local $i" 2>/dev/null
i=$((i+1))
done
trace="$c/trace.txt"
GIT_TRACE_PACKET="$trace" git -C "$c" -c protocol.version=2 fetch --quiet origin "$br" >/dev/null 2>&1
[ -s "$trace" ] || { rm -rf "$c"; continue; }
# One round per `command=fetch` the CLIENT sends.
awk '/fetch> command=fetch/{r++} /fetch> have /{if (r>0) print r"\t"$NF}' "$trace" > "$c/haves.txt"
[ -s "$c/haves.txt" ] || { rm -rf "$c"; continue; }
# Ask the SERVER. `cat-file --batch-check` prints "<oid> missing" for an oid
# the repository does not hold, and "<oid> <type> <size>" for one it does.
cut -f2 "$c/haves.txt" | git -C "$m" cat-file --batch-check 2>/dev/null \
| awk '{print ($NF=="missing") ? 0 : 1}' > "$c/present.txt"
# `paste` joins by POSITION, and pads a short file with empties. A
# `cat-file` that died halfway therefore does not fail — it shifts every
# remaining answer onto the wrong oid, and one that produced nothing at all
# makes `$3` never equal 1, i.e. a 100% miss rate reported as a result. This
# is the whole reason the script's stderr is discarded above and its exit
# status is invisible, so the line count is what has to be checked.
hn=$(wc -l < "$c/haves.txt"); pn=$(wc -l < "$c/present.txt")
[ "$hn" -eq "$pn" ] || die "$repo/$shape: $hn have(s) offered but \`cat-file \
--batch-check\` answered $pn line(s). \`paste\` joins by position, so this would \
have been charted as a hit/miss mix rather than as the broken read it is."
paste "$c/haves.txt" "$c/present.txt" \
| awk -v repo="$repo" -v shape="$shape" '
{r=$1+0; tot[r]++; if ($3==1) hit[r]++}
END {for (k in tot) printf "%s\t%s\t%d\t%d\t%d\t%d\n", repo, shape, k, tot[k], hit[k]+0, tot[k]-(hit[k]+0)}' \
| sort -k3,3n >> "$OUT"
rm -rf "$c"
done
done
rows=$(( $(wc -l < "$OUT") - 1 ))
echo "rows: $rows"
# Non-vacuity. Every bail-out above is a `continue`, so "all 19 repositories were
# unusable" and "the mix is as measured" printed the same thing and exited the
# same way until this line.
[ "$rows" -gt 0 ] || die "have-mix produced NO rows over ${#MIRROR_DIRS[@]} \
mirror(s). Every repository fell through a \`continue\`; nothing was measured."