#!/bin/sh

#
# This file is released under the terms of the Artistic License.
# Please see the file LICENSE, included in this package, for details.
#
# Copyright The DBT-2 Authors
#

usage()
{
	cat << EOF
$(basename "${0}") is the Database Test 2 (DBT-2) Connection Scaling Test

This script will run a series of tests based on the number of detected logical
processors.  A series of database connections will be opened up to the number
of processors on the system, where each connection will touch every warehourse
and district and run transactions without thinking or keying time.

By default, each test is 5 minutes (300 seconds) long with a 60 second warmup.
Both lengths may be configured.

Usage:
  $(basename "${0}") [OPTIONS] DBMS DIRECTORY

General options:
  --config=CONFIG
                 CONFIG file to use for executing a test.  These settings will
                 override any conflicting command line arguments.
  --db-host=ADDRESS
                 ADDRESS of database system, default ${DB_HOSTNAME}
  --db-name=NAME
                 NAME of the database, default ${DBNAME}
  --db-port=PORT
                 database listening PORT number
  --db-user=USER
                 database USER
  --dbaas        database server is a service
  -d SECONDS, --duration=SECONDS
                 SECONDS of the test duration, after warmup,
                 default ${DURATION}
  --start USERS  start with USERS users, default 1
  --step USERS   increment by USERS users, default 1
  --stop USERS   stop at USERS users, default detected number of processors
  -V, --version  output version information, then exit
  --warmup SECONDS
                 SECONDS before all database connections have finished opening,
                 default ${WARMUP}
  -w WAREHOUSES, --warehouses=WAREHOUSES
                 number of WAREHOUSES to use in the database,
                 default ${WAREHOUSES}
  -?, --help     show this help, then exit

DBMS options are:
  cockroach  CockroachDB
  mysql      MySQL
  pgsql      PostgreSQL
  sqlite     SQLite

DIRECTORY is the path to save test results.

Database Test 2 (DBT-2) project page: https://github.com/osdldbt/dbt2
EOF
}

CONFIGFILE=""
DB_HOSTNAME="localhost"
DB_PORT=""
DB_USER=""
DBNAME="dbt2"
DURATION=300
FIRST=1
LAST=0
RUNARGS=""
STEP=1
WAREHOUSES=1
WARMUP=60

# Custom argument handling for hopefully most portability.
while [ "${#}" -gt 0 ] ; do
	case "${1}" in
	(--config)
		shift
		CONFIGFILE="${1}"
		;;
	(--config=*)
		CONFIGFILE="${1#*--config=}"
		;;
	(--db-host)
		shift
		DB_HOSTNAME=${1}
		;;
	(--db-host=?*)
		DB_HOSTNAME=${1#*--db-host=}
		;;
	(--db-name)
		shift
		DBNAME=${1}
		;;
	(--db-name=?*)
		DBNAME=${1#*--db-name=}
		;;
	(--db-port)
		shift
		DB_PORT="${1}"
		;;
	(--db-port=?*)
		DB_PORT="${1#*--db-port=}"
		;;
	(--db-user)
		shift
		DB_USER=${1}
		;;
	(--db-user=?*)
		DB_USER=${1#*--db-user=}
		;;
	(--dbaas)
		RUNARGS="${RUNARGS} --dbaas"
		;;
	(-d | --duration)
		shift
		DURATION="${1}"
		;;
	(-d?*)
		DURATION="${1#*-d}"
		;;
	(--duration=?*)
		DURATION="${1#*--duration=}"
		;;
	(--start)
		shift
		FIRST="${1}"
		;;
	(--start=*)
		FIRST="${1#*--start=}"
		;;
	(--step)
		shift
		STEP="${1}"
		;;
	(--step=*)
		STEP="${1#*--step=}"
		;;
	(--stop)
		shift
		LAST="${1}"
		;;
	(-V | --version)
		echo "$(basename "${0}") v0.61.6"
		exit 0
		;;
	(-w | --warehouses)
		shift
		WAREHOUSES="${1}"
		;;
	(-w?*)
		WAREHOUSES="${1#*-w}"
		;;
	(--warehouses=?*)
		WAREHOUSES="${1#*--warehouses=}"
		;;
	(--warmup)
		shift
		WARMUP="${1}"
		;;
	(--warmup=?*)
		WARMUP="${1#*--warmup=}"
		;;
	(-\? | --help)
		usage
		exit 0
		;;
	(--* | -*)
		echo "$(basename "${0}"): invalid option -- '${1}'"
		echo "try \"$(basename "${0}") --help\" for more information."
		exit 1
		;;
	(*)
		break
		;;
	esac
	shift
done

if [ $# -eq 0 ]; then
	printf "Specify which DBMS system to test, try \"%s --help\" " \
			"$(basename "${0}")"
	echo "for more information."
	exit 1
fi

DBMS=$1
shift

if [ $# -eq 0 ]; then
	echo "Specify the location to create and save test results,"
	echo "try \"$(basename "${0}") --help\" for more information."
	exit 1
fi

OUTDIR="${1}"
if [ -d "${OUTDIR}" ]; then
	echo "Directory '${OUTDIR}' exists, stopping to prevent possible"
	echo "clobbering of data, please specify another location to save results."
	exit 1
fi
mkdir -p "${OUTDIR}"

# Limit the series to the number of processors, by default, based on the
# expectation that 1 processor will be fully utilized when not using any
# thinking or keying time.
PROCS="$(nproc)"
echo "${PROCS} logical processor(s) detected"

if [ "${WAREHOUSES}" -lt "${PROCS}" ]; then
	echo "limiting max database connections to the number of warehouses: ${WAREHOUSES}"
	PROCS="${WAREHOUSES}"
fi

# Prep data file to bar plot connections and the primary metric.
RESULTSFILE="${OUTDIR}/results.dat"
echo "connections metric" > "${RESULTSFILE}"

RUNARGS="--db-host=${DB_HOSTNAME}"
if [ ! "${CONFIGFILE}" = "" ]; then
	RUNARGS="${RUNARGS} --config=${CONFIGFILE}"
fi
if [ ! "${DB_PORT}" = "" ]; then
	RUNARGS="${RUNARGS} --db-port=${DB_PORT}"
fi
if [ ! "${DB_USER}" = "" ]; then
	RUNARGS="${RUNARGS} --db-user=${DB_USER}"
fi
RUNARGS="${RUNARGS} --duration=${DURATION}"
RUNARGS="${RUNARGS} --stats"
RUNARGS="${RUNARGS} --warehouses=${WAREHOUSES}"
for I in $(seq "${FIRST}" "${STEP}" "${LAST}"); do
	DELAY=$(( (WARMUP / I) * 1000 ))
	PREFIX="${OUTDIR}/${I}"

	ARGS="${RUNARGS} --connection-delay=${DELAY}"
	ARGS="${ARGS} --terminal-limit=${I}"
	eval "dbt2 run ${ARGS} ${DBMS} ${PREFIX}" > "${PREFIX}.log" 2>&1

	NOTPM="$(grep Throughput "${PREFIX}/summary.rst" | cut -d " " -f 3)"
	echo "${I} ${NOTPM}" >> "${RESULTSFILE}"
done

# Bar plot the metric per database connection.
gnuplot << EOF
set terminal pngcairo size 1600,1000
set title "New Orders per Database Connection"
set grid
set output "${OUTDIR}/nopdbc.png"
set xlabel "Database Connections"
set ylabel "New Orders per Minute"
set yrange [0:*]
set style data histogram
set style fill solid
plot '${RESULTSFILE}' using 2:xtic(1) notitle
EOF

# Plot the transaction rate over the entire series of tests.
MIXFILES="$(find "${OUTDIR}" -type f -name 'mix*.log' -print0 2> /dev/null \
		| xargs -0)"
# shellcheck disable=SC2086
(dbt-plot transaction-rate "New Order" n tpm "${OUTDIR}" 2 ${MIXFILES} \
		|| warning "Could not create new order transaction rate charts") &

# Aggregate all of the database system's sar data.
SARDIR="${OUTDIR}/sar"
mkdir -p "${SARDIR}"
for FILE in sar-blockdev.csv sar-cpu.csv sar-mem.csv sar-net.csv \
		sar-paging.csv sar-swap.csv; do
	# Capture just the header once.
	# shellcheck disable=SC2046
	find $(find "${OUTDIR}" -name db -type d -print0 | xargs -0) -name sar \
			-type d | while IFS= read -r DIR; do
		head -n 1 "${DIR}/${FILE}" > "${SARDIR}/${FILE}"
		break
	done

	# Get just the data from all of the files.
	# shellcheck disable=SC2046
	find $(find "${OUTDIR}" -name db -type d -print0 | xargs -0) -name sar \
			-type d | sort -V | while IFS= read -r DIR; do
		tail -n +2 "${DIR}/${FILE}" >> "${SARDIR}/${FILE}"
	done
done

ts plot-sar -i "${SARDIR}"
