#!/bin/bash
# Reproduces BUG #19628: measures how long a VACUUM on a hash index takes
# to honor pg_cancel_backend() while in the "vacuuming indexes" phase.
#
# Usage:
#   PGBIN=/path/to/pg/bin ./test_hash_vacuum_cancel.sh
#
# Expects a built PostgreSQL tree's bin/ dir in PGBIN (initdb, pg_ctl, psql).
# Creates a scratch data dir under $WORKDIR, runs the test, leaves the
# cluster running afterward (stop it yourself when done).

set -euo pipefail

PGBIN="${PGBIN:?set PGBIN to the postgres bin directory}"
PGPORT="${PGPORT:-5455}"
ROWS="${ROWS:-8000000}"
WORKDIR="${WORKDIR:-$(mktemp -d)}"
PGDATA="$WORKDIR/pgdata"
LIBDIR="$(dirname "$PGBIN")/lib"

export LD_LIBRARY_PATH="$LIBDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

echo "workdir: $WORKDIR"
mkdir -p "$WORKDIR"

"$PGBIN/initdb" -D "$PGDATA" --no-sync -U postgres > "$WORKDIR/initdb.log" 2>&1
"$PGBIN/pg_ctl" -D "$PGDATA" -o "-p $PGPORT -c autovacuum=off" -l "$WORKDIR/server.log" -w start

psql() { "$PGBIN/psql" -p "$PGPORT" -U postgres "$@"; }

echo "building dataset ($ROWS rows, ~90% dead)..."
psql <<SQL
CREATE TABLE hvac_test (id bigint, payload text);
INSERT INTO hvac_test SELECT g, repeat('x', 50) FROM generate_series(1, $ROWS) g;
CREATE INDEX hvac_idx ON hvac_test USING hash (id);
DELETE FROM hvac_test WHERE id % 10 <> 0;
SQL

echo "starting VACUUM in background..."
VACOUT="$WORKDIR/vacout.txt"
"$PGBIN/psql" -p "$PGPORT" -U postgres -Atq \
    -c "select pg_backend_pid();" \
    -c "VACUUM (VERBOSE) hvac_test;" > "$VACOUT" 2>&1 &
VAC_JOB=$!

for _ in $(seq 1 200); do
    grep -qE '^[0-9]+$' "$VACOUT" 2>/dev/null && break
    sleep 0.02
done
BEPID=$(grep -E '^[0-9]+$' "$VACOUT" | head -1)
echo "vacuum backend pid: $BEPID"

echo "waiting for 'vacuuming indexes' phase..."
for _ in $(seq 1 2000); do
    phase=$(psql -Atc "select phase from pg_stat_progress_vacuum where pid=$BEPID;")
    [ "$phase" = "vacuuming indexes" ] && break
    sleep 0.01
done
echo "phase at cancel time: ${phase:-<never reached>}"

t1=$(date +%s.%N)
psql -Atc "select pg_cancel_backend($BEPID);" > /dev/null
wait "$VAC_JOB" || true
t2=$(date +%s.%N)

echo "--- vacuum output ---"
cat "$VACOUT"
echo "--- result ---"
python3 -c "print(f'seconds from cancel to backend exit: {$t2 - $t1:.3f}')"
