#! /bin/sh
#set -xv
######################################################################
#
# Copyright (C) GemTalk Systems 1986-2014.  All Rights Reserved.
#
# Script for starting shared cache warmer gem.
#
# Phase 1:
# gem reads the object table into the shared page cache.
#
# Phase 2: (optional)
# Reads data pages.  Data pages can be read into the shared cache 
# or only into the UNIX file buffer cache.  
# Phase 2 is run if '-d' or '-D; is specified on the command line.
#
# See usage() below or run 'startcachewarmer -h' for detailed 
# command line options
#
#
######################################################################

# must have $GEMSTONE
if [ "a$GEMSTONE" = "a" ]; then
  echo "ERROR: GemStone scripts require a GEMSTONE environment variable."
  echo "       Please set it to the directory where GemStone resides."
  exit 1
fi

# ensure a minimal path
if [ "x$PATH" = "x" ]; then PATH=:/bin:/usr/bin:/usr/ucb; export PATH; fi 

# error control - do not allow hup
trap '' 1

comid="startcachewarmer"

usage() {
  cat <<EOF
Usage:
$comid [-C midCacheSizeKb] [-d|-D] [-h] [-H host] [-l cacheFullLimit] [-M host] 
       [-N midCacheMaxProcs] [-s stone] [-u maxUsers] [-W] [-L logPath]

  -C    size of the mid-level cache in KB (default 75000).  Only used if the 
        -M option is also specified and the mid-level cache does not exist.
  -d    read data pages into the cache. (default: only object table pages are read).
  -D    read data pages into the UNIX file system buffers. 
NOTE: -d and -D are mutually exclusive. If both -d and -D are passed on
the command line, the last of these flags is used.
  -h    display this message and exit. 
  -H    host name or IP address where the stone is running.  ONLY to be used when warming a
        remote shared page cache.
  -l    stop cache warming if the free frame count falls below <cacheFullLimit>. 
        Use -1 to have system compute a default value. Use 0 to force cache warming 
        to continue even if the shared cache is full.  (default: -1)
  -L    path to a writable log file directory. (default: current directory)
  -M    host name or IP address where the mid-level cache is running or will be created. 
        The -H option must also be specified with this option (default: no mid-level
        cache is used)
  -n    number of warmer threads to use. (default: numberOfCpus + numExtents)
        There is always one additional "master" thread allocated and the warmer 
        will exit with an error if not enough sessions are available.
  -N    maximum number of processes that can use the mid-level cache (default: 50).
        Only used if the -M option is also specified and mid-level cache does not exist.
  -s    name of running stone. (default: 'gs64stone')
  -W    wait for cache warming gems to exit before exiting this script (default: 
        spawn gem in the background and exit immediately)

Description:

Script for starting a shared cache cache warming gem with multiple session threads.

Phase 1:
Gem reads the dependency map and object table pages into the shared page cache.

Phase 2: (only executed if either the '-d' or '-D' option is specified)
Data pages are read into the shared page cache ('-d') or only the UNIX file buffer ('-D') 

If a remote shared page cache is to be warmed (i.e., the -H option is used), then the
remote cache will be created if it does not already exist.  The options in the
configuration file specified by the GEMSTONE_EXE_CONF environment variable will be
used to specify the attributes of the new remote cache.

If a mid-level cache host name or IP address is specified (via -M), the mid-level cache will
be created if it does not already exist.  The -C and -N options will be used to specify 
the size and number of processes that can attach the mid-cache respectively.  If the 
mid-cache already exists, the -C and -N options are ignored.

Notes: 
  -The cache warming sessions run inside a transaction.
  -Warming the shared cache on the stone's host subjects the operating system to a high
   load in the form of disk reads.  GemStone system performance during stone cache warming
   should be expected to be poor.

EOF
  exit $status
}


# ---
# defaults
# ---
readDataPagesOpCode="0"
cacheFullLimit=-1
numSessions=0
stone="gs64stone"
waitForGem=0
logPath=`pwd`
midCacheHost=""
midCacheSize=0
midCacheProcs=0
# ---
# process command line
# ---
while getopts "C:dDhH:l:L:M:n:N:s:W" opt; do
  case $opt in
    C) midCacheSize=$OPTARG ;;
    d) readDataPagesOpCode="1" ;;
    D) readDataPagesOpCode="2" ;;
    h) status=0; usage ;;
    H) stoneHost=$OPTARG ;; # Fix 44298
    l) cacheFullLimit=$OPTARG ;;
    L) logPath=$OPTARG ;;
    M) midCacheHost=$OPTARG ;;
    N) midCacheProcs=$OPTARG ;;
    n) numSessions=$OPTARG ;;
    s) stone=$OPTARG ;;
    W) waitForGem=1 ;;
# Request 38663: accept a directory for log files
    \?) status=1; usage ;;
  esac
done

if [ $numSessions -lt 0 ]; then
  echo "$comid [ERROR]: numSessions is too small."
  status=1
  usage
fi

if [ $cacheFullLimit -lt -1 ]; then
  echo "$comid [ERROR]: cacheFullLimit is too small."
  status=1
  usage
fi

if [ ! -d $logPath ]; then
  echo "$comid [ERROR]: $logPath is not a directory."
  status=1
  usage
fi

if [ ! -w $logPath ]; then
  echo "$comid [ERROR]: $logPath is not writable."
  status=1
  usage
fi

if [ "$midCacheHost" = "" ]; then
  # No mid cache specified, so -C and -N shouldn't be here.  Make sure.
  if [ $midCacheProcs -ne 0 -o $midCacheSize -ne 0 ]; then
    echo "$comid [ERROR]: -C and -N options may not be specified unless -M option is also specified."
    status=1
    usage
  fi
fi

MID_NRS="''"
MID_HOST_PRINTED="(none)"
# Fix 44298 - support for warmers on remote caches
if [ "$stoneHost" = "" ]; then # Stone running on our host
  if [ "$midCacheHost" != "" ]; then
    echo "$comid [ERROR]: Cannot use a mid-level cache when running cache warmers on the stone's cache."
    status=1
    usage
  fi
  STN_NRS=$stone
  STN_WS_NRS=$stone
  STN_HOST_PRINTED="(localhost)"
else
# We are warming a remote cache.
#
# warmer gem needs single quotes around the NRS.
# waitstone does not like single quotes.
  STN_NRS="'!@$stoneHost!$stone'"
  STN_WS_NRS="!@$stoneHost!$stone"
  STN_HOST_PRINTED=$stoneHost
  if [ "$midCacheHost" != "" ]; then
    # User wants warmer to use a mid cache.
    MID_NRS="'$midCacheHost'"
    MID_HOST_PRINTED=$midCacheHost
    # Use defaults if values were not given.
    # Gem will check that values are in range.
    if [ $midCacheProcs -eq 0 ]; then
      midCacheProcs=50 
    fi
    if [ $midCacheSize -eq 0 ]; then
      midCacheSize=75000
    fi
  fi
fi

# check to make sure $stone is a running stone
$GEMSTONE/bin/waitstone $STN_WS_NRS -1 >/dev/null 2>&1
if [ $? -ne 0 ]; then
  if [ ! -w $logPath ]; then
    echo "$comid [ERROR]: $stone is not a running stone."
  else
    echo "$comid [ERROR]: $stone is not a running stone on host $stoneHost"
  fi
  status=1
  usage
fi

slash="/"
testFile=${logPath}${slash}foo
touch $testFile >/dev/null 2>&1
if [ $? -eq 0 ]; then
  rm -f $testFile >/dev/null 2>&1
else
  slash=""
  testFile=${logPath}${slash}foo
  touch $testFile >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    echo "$comid [ERROR]: cannot create file in directory $logPath"
    status=1
    usage
  fi
  rm -f $testFile >/dev/null 2>&1
fi

cat <<EOF
Cache warming configuration:
           Sessions: $numSessions
    Read data pages: $readDataPagesOpCode
     CacheFullLimit: $cacheFullLimit
              Stone: $stone
          StoneHost: $STN_HOST_PRINTED
     Mid cache host: $MID_HOST_PRINTED
     Mid cache size: $midCacheSize
    Mid cache procs: $midCacheProcs
         WaitForGem: $waitForGem
       LogDirectory: $logPath
Spawning cache warming gem...
EOF

logName=${logPath}${slash}cacheWarmer.log
rm -f $logName >/dev/null 2>&1
GEMSTONE_CHILD_LOG=$logName
export GEMSTONE_CHILD_LOG

# The default behaviour is to delete this process's log file if it exits
# normally. If you want to keep this process's log file even on normal exit
# then uncomment the following
# GEMSTONE_KEEP_LOG=1 ; export GEMSTONE_KEEP_LOG

# ---
# start the cache warmer gem
# ---

$GEMSTONE/sys/gem otCacheWarmerGem $STN_NRS $numSessions $cacheFullLimit $readDataPagesOpCode \
  $MID_NRS $midCacheSize $midCacheProcs > $logName 2>&1 &

thisPid=$!
echo "$comid [Info]: Started cache warmer gem with process id: $thisPid."

if [ $waitForGem -eq 1 ]; then
  echo "$comid [Info]: waiting for warmer gem with process ID $thisPid to finish..."
  wait $thisPid
fi

exit 0
