#!/usr/bin/env bash
#
# Reproducer for MDEV-32538: crash while loading aria_log
#   "File 'aria_log.NNNNNNN' not found" -> free(): invalid pointer -> signal 6
#
# This version targets an ALREADY RUNNING server via its socket, pulls
# datadir/pid-file/port/aria-log-file-size from it, then:
#   1. loads data to force aria_log rotation
#   2. kills the server uncleanly (kill -9) mid-write
#   3. deletes an early (not-newest) aria_log file
#   4. restarts the SAME binary against the SAME datadir
#   5. checks the resulting error log for the crash signature
#
# WARNING: this kills the running server with kill -9 and deletes a file
# from its datadir. Point it only at a disposable/test instance.
#
# Usage:
#   ./repro_mdev32538_live.sh /path/to/socket /path/to/mariadbd [aria_log_file_size]
#
# aria_log_file_size (optional, default 8388608 = 8MB): if the live server's
# current setting is larger than this, the server is restarted once (same
# datadir/port/socket) with this smaller size so that normal data loading
# rotates logs quickly instead of requiring gigabytes of writes.

set -u

SOCKET="${1:?Usage: $0 /path/to/socket /path/to/mariadbd [aria_log_file_size]}"
MARIADBD="${2:?Usage: $0 /path/to/socket /path/to/mariadbd [aria_log_file_size]}"
DESIRED_LOG_SIZE="${3:-1048576}"
FILL_ROWS=2000000
MAX_WAIT_SECONDS=120
MIN_LOGS_NEEDED=3

# Prefer the mariadb client that ships alongside the target mariadbd binary,
# since a PATH-resolved client (different version/build) can mismatch on
# things like SSL requirements. Fall back to PATH + --ssl=0 if not found.
BINDIR="$(dirname "$MARIADBD")"
if [ -x "$BINDIR/mariadb" ]; then
    MARIADB_CLIENT=("$BINDIR/mariadb")
else
    MARIADB_CLIENT=(mariadb --ssl=0)
fi

pass() { echo "PASS: $*"; }
fail() { echo "FAIL: $*"; }
info() { echo "INFO: $*"; }

get_var() {
    "${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -N -B -e "SHOW VARIABLES LIKE '$1'" | awk '{print $2}'
}

info "Querying live server via socket: $SOCKET"
info "Using client: ${MARIADB_CLIENT[*]}"
"${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -e "SELECT 1" >/dev/null 2>&1
if [ $? -ne 0 ]; then
    fail "Cannot connect via socket $SOCKET. Check the path and that the server is reachable."
    exit 1
fi

DATADIR="$(get_var datadir)"
PIDFILE="$(get_var pid_file)"
PORT="$(get_var port)"
ARIA_LOG_SIZE="$(get_var aria_log_file_size)"

info "datadir           = $DATADIR"
info "pid_file          = $PIDFILE"
info "port              = $PORT"
info "aria_log_file_size = $ARIA_LOG_SIZE"

if [ -z "$DATADIR" ] || [ -z "$PIDFILE" ]; then
    fail "Could not determine datadir or pid_file from the running server. Aborting."
    exit 1
fi

ERRLOG2="$(dirname "$PIDFILE")/mdev32538_error_after_restart.log"
ERRLOG_PREP="$(dirname "$PIDFILE")/mdev32538_error_prep_restart.log"

if [ "$ARIA_LOG_SIZE" -gt "$DESIRED_LOG_SIZE" ]; then
    info "Current aria_log_file_size ($ARIA_LOG_SIZE) is too large to rotate quickly."
    info "Restarting server once with --aria-log-file-size=$DESIRED_LOG_SIZE (same datadir/port/socket)..."

    kill "$(cat "$PIDFILE")" 2>/dev/null
    for i in $(seq 1 30); do
        [ ! -f "$PIDFILE" ] && break
        sleep 1
    done
    sleep 1

    "$MARIADBD" \
        --datadir="$DATADIR" \
        --socket="$SOCKET" \
        --port="$PORT" \
        --aria-log-file-size="$DESIRED_LOG_SIZE" \
        --pid-file="$PIDFILE" \
        --log-error="$ERRLOG_PREP" &

    for i in $(seq 1 30); do
        "${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -e "SELECT 1" >/dev/null 2>&1 && break
        sleep 1
    done

    if ! "${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -e "SELECT 1" >/dev/null 2>&1; then
        fail "Server did not come back up after restart with smaller aria_log_file_size. Check $ERRLOG_PREP"
        cat "$ERRLOG_PREP" 2>/dev/null
        exit 1
    fi

    ARIA_LOG_SIZE="$DESIRED_LOG_SIZE"
    info "Server restarted with aria_log_file_size=$ARIA_LOG_SIZE"
fi

info "Dropping any leftover 'repro' schema state from previous runs..."
"${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -e "DROP DATABASE IF EXISTS repro;"

"${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -e "
CREATE DATABASE repro;
USE repro;
CREATE TABLE t (id INT PRIMARY KEY AUTO_INCREMENT, data VARCHAR(255)) ENGINE=Aria;
"

"${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot repro -e "
DELIMITER //
CREATE PROCEDURE fill()
BEGIN
  DECLARE i INT DEFAULT 0;
  WHILE i < $FILL_ROWS DO
    INSERT INTO t (data) VALUES (REPEAT('x',200));
    SET i = i + 1;
  END WHILE;
END //
DELIMITER ;
CALL fill();
" > "$(dirname "$PIDFILE")/mdev32538_fill.log" 2>&1 &
FILL_PID=$!

info "Waiting for aria_log rotation (need >= $MIN_LOGS_NEEDED files, timeout ${MAX_WAIT_SECONDS}s)..."
WAITED=0
NUM_LOGS=0
while [ "$WAITED" -lt "$MAX_WAIT_SECONDS" ]; do
    ARIA_LOGS=("$DATADIR"/aria_log.[0-9]*)
    NUM_LOGS=${#ARIA_LOGS[@]}
    if [ "$NUM_LOGS" -ge "$MIN_LOGS_NEEDED" ]; then
        info "Reached $NUM_LOGS aria_log files after ${WAITED}s."
        break
    fi
    # bail early if fill() finished on its own (nothing left to generate more logs)
    if ! kill -0 "$FILL_PID" 2>/dev/null; then
        info "fill() process finished after ${WAITED}s (only $NUM_LOGS log files so far)."
        break
    fi
    sleep 2
    WAITED=$((WAITED + 2))
done

info "Killing server uncleanly (kill -9) to simulate crash/incomplete clone mid-write"
kill -9 "$(cat "$PIDFILE")" 2>/dev/null
kill -9 "$FILL_PID" 2>/dev/null
sleep 1

ARIA_LOGS=("$DATADIR"/aria_log.[0-9]*)
NUM_LOGS=${#ARIA_LOGS[@]}
info "Found $NUM_LOGS aria_log files before deletion:"
ls -la "$DATADIR" | grep aria_log

if [ "$NUM_LOGS" -lt "$MIN_LOGS_NEEDED" ]; then
    fail "Not enough aria_log files rotated ($NUM_LOGS) after waiting ${WAITED}s. Try a smaller aria_log_file_size (3rd script arg) or a longer MAX_WAIT_SECONDS."
    exit 1
fi

TARGET_LOG="${ARIA_LOGS[2]}"   # 3rd oldest, not the newest
info "Removing: $TARGET_LOG"
rm -f "$TARGET_LOG"

info "Restarting $MARIADBD against $DATADIR"
"$MARIADBD" \
    --datadir="$DATADIR" \
    --socket="$SOCKET" \
    --port="$PORT" \
    --aria-log-file-size="$ARIA_LOG_SIZE" \
    --pid-file="$PIDFILE" \
    --log-error="$ERRLOG2" &
RESTART_PID=$!

sleep 3

echo "----- $ERRLOG2 -----"
cat "$ERRLOG2" 2>/dev/null
echo "---------------------"

if grep -q "not found" "$ERRLOG2" 2>/dev/null && grep -qE "free\(\): invalid pointer|signal 6|signal 11" "$ERRLOG2" 2>/dev/null; then
    pass "Reproduced MDEV-32538: missing aria_log file triggered crash (not graceful error) on restart."
    exit 0
elif ps -p "$RESTART_PID" >/dev/null 2>&1 && "${MARIADB_CLIENT[@]}" --socket="$SOCKET" -uroot -e "SELECT 1" >/dev/null 2>&1; then
    fail "Server recovered gracefully (or started fine) after missing aria_log file -- bug NOT reproduced on this build."
    exit 2
else
    fail "Server did not come up and no clear crash signature found -- inspect $ERRLOG2 manually."
    exit 3
fi
