#!/usr/bin/env bash

set -e

ROWS=$1
FILLFACTOR=$2
WORKERS=$3

PAYLOAD=500
RUNS=3
BUILDS=/home/tomas/builds

export PGCTLTIMEOUT=3600

PATH_OLD=$PATH
DATADIR=/mnt/raid-nvme/data-prefetch

export MALLOC_TOP_PAD_=$((64*1024*1024))

TS=$(date +%Y%m%d-%H%M%S)

killall -9 postgres || true
sleep 1

rm -Rf $DATADIR

mkdir $TS

PATH=$BUILDS/master/bin:$PATH_OLD

pg_ctl -D $DATADIR init
pg_checksums --disable $DATADIR
pg_ctl -D $DATADIR start
createdb test
pg_ctl -D $DATADIR stop

# use buffered I/O for generating data
cp postgresql.conf $DATADIR/postgresql.conf

pg_ctl -D $DATADIR -l $TS/pg.log start

psql test -c "CREATE EXTENSION pg_buffercache"

for w in $(seq 1 $WORKERS); do
	psql test -c "CREATE TABLE t_${w} (id SERIAL PRIMARY KEY, val INT NOT NULL, payload TEXT NOT NULL) WITH (fillfactor=$FILLFACTOR)"
	psql test -c "INSERT INTO t_${w} (val, payload) SELECT g, repeat('x', $PAYLOAD) FROM generate_series(1, $ROWS) g"
	psql test -c "CREATE INDEX ON t_${w} (val)"
	psql test -c "VACUUM ANALYZE t_${w}"
done

psql test -c "\d+"
psql test -c "\di+"

for w in $(seq 1 $WORKERS); do
	psql test -c "SELECT relname, relpages, (relpages * 8) AS size_kB FROM pg_class WHERE relname = 't_${w}'"
done

pg_ctl -D $DATADIR -l $TS/pg.log stop


for io in buffered direct; do

	for iomethod in worker io_uring; do

		for ioworkers in 32 12; do

			if [ "$iomethod" == "io_uring" ] && [ "$ioworkers" != "32" ]; then
				continue
			fi

			for sb in 128MB 8GB; do

				for branch in master patched patched-limit patched-limit-instrument; do

					for prefetch in on off; do

						for limit in 0 1 4 16 64 128; do

							# master can't do prefetch
							if [ "$branch" == "master" ] && [ "$prefetch" == "on" ]; then
								continue
							fi

							if [ "$branch" == "master" ] || [ "$branch" == "patched" ]; then
								if [ "$limit" != "0" ]; then
									continue
								fi
							fi

							if [ "$prefetch" == "off" ] && [ "$limit" != "0" ]; then
								continue
							fi

							PATH=$BUILDS/$branch/bin:$PATH_OLD

							cp postgresql.conf $DATADIR/postgresql.conf

							echo "shared_buffers = $sb" >> $DATADIR/postgresql.conf
							echo 'max_parallel_workers_per_gather = 0' >> $DATADIR/postgresql.conf
							echo 'enable_bitmapscan = off' >> $DATADIR/postgresql.conf
							echo 'enable_seqscan = off' >> $DATADIR/postgresql.conf
							echo 'enable_indexonlyscan = off' >> $DATADIR/postgresql.conf
							echo "io_workers = $ioworkers" >> $DATADIR/postgresql.conf
							echo "io_method = $iomethod" >> $DATADIR/postgresql.conf

							if [ "$io" == "direct" ]; then
								echo "debug_io_direct = 'data'" >> $DATADIR/postgresql.conf
							fi

							if [ "$branch" != "master" ]; then
								echo "enable_indexscan_prefetch = $prefetch" >> $DATADIR/postgresql.conf
							fi

							if [ "$branch" != "master" ] && [ "$branch" != "patched" ]; then
								echo "indexscan_prefetch_distance = $limit" >> $DATADIR/postgresql.conf
							fi

							pg_ctl -D $DATADIR -l $TS/pg.log start

							for r in $(seq 1 $RUNS); do

								sudo ./drop-caches.sh

								psql test -c "select pg_buffercache_evict_all()"

								# sync scans in all workers 1s from now
								s=$(psql -t -A test -c "select extract(epoch from now()) + 1.0")

								for w in $(seq 1 $WORKERS); do
									echo "EXPLAIN SELECT count(l) FROM (SELECT length(payload) AS l FROM t_${w} ORDER BY val);" > $TS/script-$w.sql
									echo "SELECT pg_sleep($s - extract(epoch from now()));" >> $TS/script-$w.sql
									echo "\timing on" >> $TS/script-$w.sql
									echo "SELECT count(l) FROM (SELECT length(payload) AS l FROM t_${w} ORDER BY val);" >> $TS/script-$w.sql

									psql test < $TS/script-$w.sql > $TS/tmp-$w.log 2>&1 &
								done

								wait

								echo "===== io: $io  iomethod: $iomethod  ioworkers: $ioworkers  sb: $sb  branch: $branch  prefetch: $prefetch  limit: $limit  run: $r =====" >> $TS/debug.log

								for w in $(seq 1 $WORKERS); do
									cat $TS/tmp-$w.log >> $TS/debug.log
									t=$(grep 'Time:' $TS/tmp-$w.log | awk '{print $2}')
									echo sequential $ROWS $FILLFACTOR $WORKERS $io $iomethod $ioworkers $sb $branch $prefetch $limit $r $w $t >> $TS/results.csv
								done

							done

							pg_ctl -D $DATADIR -l $TS/pg.log stop

						done

					done

				done

			done

		done

	done

done
