#! /bin/sh
#set -xv
######################################################################
#
# Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
#
# Script for starting shared cache warming gems.
#
# Phase 1:
# Each gem reads a portion of the object table into the shared page
# cache.
#
# Phase 2: (optional)
# Each gem reads a portion of all 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
#
# $Id: startcachewarmer.sh,v 1.7 2008-01-09 22:50:53 stever Exp $
#
######################################################################

# 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 [-d|-D][-h][-l<limit>][-n<numGems>][-p<password>][-s<stone>]
        [-u<userID>][-w<delayTime>][-W]

-d              read data pages into the cache (default: only object table
                pages are read)
-D              read data pages into the UNIX file buffer cache and not the
                shared page cache. 
NOTE: -d and -D are mutually exclusive. If both -d and -D are passed on
      the command line, the last of these flags will be used.
-h              display this message and exit 
-l<cacheFullLimit>
                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)
-n<numGems>     number of gems to start (default: 1)
-p<password>    GemStone password for logging in gems (default: 'swordfish')
-s<stone>       name of running stone (default: 'gs64stone')
-u<userID>      GemStone user for logging in gems (default: 'DataCurator')
-w<delayTime>   wait <delayTime> seconds between spawning gems (default: 1)
-W              wait for cache warming gems to exit before exiting this script
                (default: spawn gems in the background and exit immediately)

Description:

Script for starting shared cache cache warming gems.

Phase 1:
Each gem reads a portion of the object table into the shared page
cache.

Phase 2: (optional)
Each gem reads a portion of all data pages.  Data pages may be read
into the UNIX file buffer cache only ('-D') option) or the shared page
cache ('-d') option.  Phase 2 is not run by default.
EOF
  exit $status
}


# ---
# defaults
# ---
readDataPagesOpCode="0"
cacheFullLimit=-1
numGems=1
password="swordfish"
stone="gs64stone"
userID="DataCurator"
delayTime=1
waitForGems=0

# ---
# process command line
# ---
while getopts "dDhl:n:p:s:u:w:W" opt; do
  case $opt in
    d) readDataPagesOpCode="1" ;;
    D) readDataPagesOpCode="2" ;;
    h) status=0; usage ;;
    l) cacheFullLimit=$OPTARG ;;
    n) numGems=$OPTARG ;;
    p) password=$OPTARG ;;
    s) stone=$OPTARG ;;
    u) userID=$OPTARG ;;
    w) delayTime=$OPTARG ;;
    W) waitForGems=1 ;;
    \?) status=1; usage ;;
  esac
done

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

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

if [ $delayTime -lt 0 ]; then
  echo "$comid [ERROR]: delayTime cannot be negative."
  status=1
  usage
fi

# ---
# do a sanity check on login parameters
# ---
$GEMSTONE/bin/topaz -il <<EOF> /dev/null 2>&1
iferror exit
set user $userID password $password gemstone $stone
login
logout
exit
EOF
status=$?
if [ $status -ne 0 ]; then
  echo "$comid [ERROR]: Failed to login with given parameters:"
  echo "        stone:    $stone"
  echo "        userID:   $userID"
  echo "        password: (set)"
  usage
fi

# ---
# function to start a single gem
# ---
spawnCacheWarmGem() {
  if [ -f "cachewarmergem$count.log" ]; then
    rm cachewarmgem$count.log >/dev/null 2>&1
  fi
  $GEMSTONE/bin/topaz -l -i << EOF >cachewarmgem$count.log
set user $userID password $password gemstone $stone
login

limit oops 5
level 1
iferror stack
display oops


run
"Set my gem name for VSD"
System _cacheName: ('CacheWarmer', $count asString).
%

time
run
SystemRepository readObjectTableForGem: $count
                 of: $numGems 
                 useSharedCache: true
                 loadDataPagesOpCode: $readDataPagesOpCode
                 cacheFullLimit: $cacheFullLimit .
%
time
logout
quit
EOF
}

# ---
# start the gems
# ---
count=1

cat <<EOF
Cache warming configuration:
            NumGems: $numGems
    Read data pages: $readDataPagesOpCode
     cacheFullLimit: $cacheFullLimit
           password: (set)
              stone: $stone
             userID: $userID
          delayTime: $delayTime
        waitForGems: $waitForGems
Spawning $numGems cache warming gems...
EOF

pids=""
while [ $count -le $numGems ]; do
  spawnCacheWarmGem >/dev/null 2>&1 &
  thisPid=$!
  pids="$thisPid $pids"
  echo "Started cache warmer gem $count with process id: $thisPid."
  if [ $count -ne $numGems ]; then
    echo "Sleeping $delayTime seconds for stone loading..."
    sleep $delayTime
  fi
  count=`expr $count + 1`
done
echo Finished spawning $numGems cache warming gems.

if [ $waitForGems -eq 1 ]; then
  echo waiting for gems with the following process IDs to exit:
  echo $pids
  wait $pids
fi

exit 0
