#!/bin/bash

DEBUG=""
BASENAME=`basename $0`
DATE="`date +%Y%m%d%H%M`"

function usage() {
	if [ "$1" == "help" ]; then
		echo -e "\n\t ./${BASENAME} \"<openldap [b|h]db backend's database directory of interest>\""
		exit 0
	elif [ "$1" != "" ]; then
		echo -e "\nerror: $1\n"
		exit 1
	fi
	exit 0
}

function getBdbStatValue() {
	if [ "$#" != "2" ]; then
		usage "internal error: \"getBdbStatValue $@\""
	fi
	bdb_filename="$1"
	bdb_property="$2"
	size=`${DB_STAT_BIN} -d "${bdb_filename}" | grep "${bdb_property}" | awk '{print $1}'`
	echo $size
}

if [ "$#" == "0" -o "$1" == "--help" -o "$1" == "-h" ]; then
	usage help
fi

if [ "$#" != "1" ]; then
	usage "invalid parameter"
fi

DB_DIR="$1"
test -d "${DB_DIR}" || { echo "given db dir \"${DB_DIR}\" does not exist" && exit 1; }

if [[ `which db_stat >& /dev/null` ]]; then 
	usage "error: \"db_stat\" not found (not installed?)"
fi
if [[ `which bc >& /dev/null` ]]; then
	usage "error: \"bc\" not found (not installed?)"
fi

DB_STAT_BIN=`which db_stat`
BC_BIN=`which bc`

echo -e "-----------------------\n${DATE}:"
#========= DATABASE CACHE SIZE CALCULATION =============
overallMainDbCacheSize=0
for mainDbFile in `ls -1 "${DB_DIR}/dn2id.bdb" "${DB_DIR}/id2entry.bdb"`; do
	PAGESIZE=`getBdbStatValue "${mainDbFile}" "Underlying database page size"`
	PAGES=`getBdbStatValue "${mainDbFile}" "Number of tree internal pages"`
	LEAFPAGES=`getBdbStatValue "${mainDbFile}" "Number of tree leaf pages"`
	DBCACHESIZE=`echo "(${PAGES}+1)*${PAGESIZE}" | "${BC_BIN}" -l`
	if [ "$DEBUG" != "" ]; then
		echo "${mainDbFile}:"
		echo -e "\tPageSize: $PAGESIZE"
		echo -e "\tPages: $PAGES"
		echo -e "\t(LeafPages: $LEAFPAGES)\n"
		echo -e "\tDbCacheSize: ${DBCACHESIZE}\n"
	fi
	overallMainDbCacheSize=$((overallMainDbCacheSize+DBCACHESIZE))
done

if [ "${overallMainDbCacheSize}" == "0" ]; then
	echo "no main db files found(?!)"
else
	echo -e "DB Cachesize Results (dn2id.bdb and id2entry.bdb):"
	echo -e "\tOverall DB Cachesize: ${overallMainDbCacheSize} bytes\n"
fi

#========= INDEX CACHE SIZE CALCULATION =============
overallIdxCacheSize=0
overallIdxCacheSizeHalf=0
for idxFile in `ls -1 "${DB_DIR}"/*.bdb | grep -v "id2entry.bdb" | grep -v "dn2id.bdb"`; do
	PAGESIZE=`getBdbStatValue "${idxFile}" "Underlying database page size"`
	# FIXME?
	# is the "number of hash buckets" (mentioned in admin guide's tuning
	# section) equivalent to db_stat's "tree internal pages"?!
	TREEINTERNALPAGES=`getBdbStatValue "${idxFile}" "Number of tree internal pages"`
	TREEOVERFLOWPAGES=`getBdbStatValue "${idxFile}" "Number of tree overflow pages"`
	TREEDUPLICATEPAGES=`getBdbStatValue "${idxFile}" "Number of tree duplicate pages"`
	IDXCACHESIZE=`echo "($TREEINTERNALPAGES+$TREEOVERFLOWPAGES+$TREEDUPLICATEPAGES)*$PAGESIZE" | "${BC_BIN}" -l`
	IDXCACHESIZE2=$((IDXCACHESIZE/2))
	if [ "$DEBUG" != "" ]; then
		echo -e "\n${idxFile}:"
		echo -e "\tPageSize: $PAGESIZE"
		echo -e "\tTreeInternalPages: ${TREEINTERNALPAGES}"
		echo -e "\tTreeOverflowPages: ${TREEOVERFLOWPAGES}"
		echo -e "\tTreeDuplicatePages: ${TREEDUPLICATEPAGES}\n"
		echo -e "\tIdxCacheSize: ${IDXCACHESIZE}"
		echo -e "\tIdxCacheSize/2: ${IDXCACHESIZE2}\n"
	fi
	overallIdxCacheSize=$((overallIdxCacheSize+IDXCACHESIZE))
done

if [ "${overallIdxCacheSize}" == "0" ]; then
	echo "no index files found(?!)"
else
	echo -e "Index Cachesize Results:"
	overallIdxCacheSizeHalf=$(( overallIdxCacheSize/2 ))
	echo -e "\tOverall Index Cachesize: ${overallIdxCacheSizeHalf} bytes (50% Index HitRatio)"
	echo -e "\tOverall Index Cachesize: ${overallIdxCacheSize} bytes"
fi

#========= RESULTS =============
echo -e "\nResulting Overall Cachesize (DB and Indexes):"
overallCacheSizeHalf=$((overallMainDbCacheSize+overallIdxCacheSizeHalf))
echo -e "\tOverall Cache Size: ${overallCacheSizeHalf} bytes (50% Index HitRatio)" 
overallCacheSize=$((overallMainDbCacheSize+overallIdxCacheSize))
echo -e "\tOverall Cache Size: ${overallCacheSize} bytes\n" 
echo -e "\tIncluding +15% bytes for growth:"
overallCacheSizeHalfSpare=`echo "1.15*${overallCacheSizeHalf}" | "${BC_BIN}"`
echo -e "\tOverall Cache Size: $overallCacheSizeHalfSpare bytes (50% Index HitRatio)" 
overallCacheSizeSpare=`echo "1.15*${overallCacheSize}" | "${BC_BIN}"`
echo -e "\tOverall Cache Size: $overallCacheSizeSpare bytes\n" 

exit 0

