#!/bin/bash
# ==============================================================
# Validator  -  A bash script to conduct stress tests for rzip64
# ==============================================================
#
# <C> 09.12.2010 Kay Gorontzi, released under the terms of the most recent GPL.
#
# Purpose:
# It's a difficult task to verify the operation of a large file compressor. There
# are way too many factors that can potentially corrupt the compressed output file:
# algorithmic problems, memory problems, cache problems, cpu problems, I/O problems,
# kernel problems, cabling problems, ... Some of them may exist on specific hardware
# platforms only while others may be more common.
#
# So as a last resort, however, we can at least use a randomized test. And that is
# exactly what this script does.
#
# We run a simple loop:
#
#    1) Create a testfile "RData" with random size and random content
#    2) Compress the file with maximum compression rate 
#    3) Interrupt and restart rzip64 multiple random times
#    4) Backup RData to "RCmp".
#    5) Decompress RData.rz
#    6) Compare decompressed RData to RCmp
#    7) When successful, record the test run
#    8) Clean up RData and RCmp
#
# Please pay attention to your disk subsystem since it may dramatically influence
# the test speed. It's a good idea to disable timestamps in the filesystem
# and of course a good idea to use a large RAID storage for the files. Please 
# provide approx. 1 GByte RAM per core.
#
# One may think of the rzip64 validator as a stress test for cpu, memory, mainboard,
# disk subsystem and not to forget: cooling fans :-)

# How large may the testfile be?
TOPLIMIT=$[ 5 * 1024 * 1024 * 1024 ]

# How many cores should be used in parallel?
CORES=4

MAIN=..

RZIP64=$MAIN/rzip64
CRF=$MAIN/validator/CreateRandomFile

if [ $MAIN/validator/CreateRandomFile.C -nt $CRF ]
then
	# One may need to change some compile options here. Be sure large file support is active.
	g++ -O3 -m64 -march=core2 -o $MAIN/validator/CreateRandomFile $MAIN/validator/CreateRandomFile.C
fi

# INT TERM EXIT - Clean up lingering files on CTRL-c
trap "kill %+ ; rm RData* RCmp ; exit" INT TERM

# Immediately inform us when a background jobs completes
set -b

function RED
   {
   printf "\033[1;31m$1\033[0m\n"
   }

function GREEN
   {
   printf "\033[1;32m$1\033[0m\n"
   }

function BLUE
   {
   printf "\033[1;34m$1\033[0m\n"
   }

RUN=1
while true
do
	RED "==============================================="
	RED "$RUN. Run"
	RED "==============================================="

	# Make sure there are no lingering files out there
	touch RData-dummy RCmp
	rm RData* RCmp

	if [ "`uname -p | cut -c1-6`" != "x86_64" ]
	then
		# It's not a good idea to run rzip64 in 32 bit environments.
		echo "32-Bit system detected. TOPLIMIT reduced to 1 GByte."
		TOPLIMIT=$[ 1 * 1024 * 1024 * 1024 ]
	fi

	# Find out how much diskspace is available
	DSIZE=`df . | cut -c43-51 | tail -1`
	SIZE=$[ $DSIZE * 1024 ]
	# Size / 4 (for Src, Dst, Bkp and spare)
	SIZE=$[$SIZE/4]
	if [ $SIZE -gt $TOPLIMIT ]
	then
		echo "Possible test size limited from $[$SIZE/1024] MByte to $[$TOPLIMIT/1024/1024] MByte."
		SIZE=$TOPLIMIT
	fi
	
	if [ $# -eq 1 ]
	then
		# Users may override the internally calculated limit at the command
		# line. That is convenient for very large disk subsystems.
		echo "Manual limit overwrite of $[$SIZE/1024/1024] MByte by $1 MByte."
		SIZE=$[$1*1024*1024]
	fi
	echo "Final size limit is now $[$SIZE/1024/1024] MByte."
		
	# Create a testfile
	$CRF $SIZE

	# Backup RData to RCmp
   cp RData RCmp
	
	# Start compression
	RED "Compressing: ----------------------------------"

	K=1
	DELAY=1
	while [ -e RData ]
	do
		# Run/Continue rzip
		$RZIP64 -v -k -P -G -j $CORES RData &

		# Interrupt rzip64 after a while
		DELAY=$[ $DELAY + $RANDOM % 30 + 1 ]
		for i in `seq 0 2 $DELAY`
		do
			# rzip64 may complete while $DELAY is not yet elapsed.
			# We check periodically if rzip64 is still running to save some idle time.
			# $DELAY may grow quite large over the time.
			sleep 2
			J=`jobs | grep RZIP | grep -v Fertig`
			if [ "$J" == "" ]
			then
				echo "rzip64 completed after $i seconds."
				break
			fi
		done
		RED "Stop #$K after $DELAY seconds:"
		# Kill last background job of current shell
		ERR=`kill %+ 2>&1`
		if [ "$ERR" != "" ]
		then
			echo "(KILL failed - rzip64 already completed when signal was sent. Don't worry.)"
		fi
		ls -lsaFb RData*
		K=$[ $K + 1 ]
	done
	
	RED "Decompressing: --------------------------------"
	ls -lsaFb RData*
	for i in 0 1 2 3 4 5 6 7 8 9
	do
		echo "Attempt #$i>"
		$RZIP64 -v -P -d RData.rz
		if [ -e RData.rz ]
		then
			echo
			echo "   Decompression failed. Disk full?"
			echo "   Waiting 30 s "
			for t in 1 2 3 4 5 6 7 8 9 10
			do
				echo -n "."
				sleep 3
			done
			echo
		else
			break
		fi
	done
	echo
	ls -lsa RData RCmp
	
	RED "Diff: -----------------------------------------"
	RES=`diff RData RCmp`
	if [ "$RES" != "" ]
	then
		BLUE "Compression failed!"
		break
	else
		GREEN "Completed SUCCESSFULLY."
		# Record the successful run
		echo -n "+" >>GOOD-RUNS
		echo $SIZE  >>GOOD-SIZES
	fi
	echo
	RUN=$[ $RUN + 1 ]
done
