#! /bin/sh
#set -xv
#=========================================================================
# Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved..
#
# Name - convprep61.sh
# Installed as - convprep61
#
# Purpose -
#
# This script is executed as step 4 of GemStone/S 6.1.5 to GemStone/S 64 bit 2.x 
# conversion as outlined below. 
# It is run with a running 6.1.5 stone. This script does the following steps:
#   1. file in SmallDouble class and reorder elements of SystemRepository.
#   2. System stopOtherSessions
#   3. System _reclaimAllShadowPages
#   4. Object table scan
#   5. Data page scan
#
# CUSTOMER UPGRADE PROCEDURE
#   Please refer to the GemStone/S 64 Bit 2.x Installation Guide for detailed
#   Instructions.
# STAGE 1:
# 1. maintain your 6.1.5 environment, e.g. GEMSTONE. DO NOT set GEMSTONE to
#    the 2.x product yet!
# 2. login to 6.1.5 stone, stop all other user sessions, and set SystemUser
#    password to 'swordfish'.
# 3.1 set environment variable upgradeLogDir to a writable directory
# 3.2 set environment variable GEMSTONE_22 to be product directory of the 2.x product .
#     but do not put this directory in your path yet .
# 4. run the script $GEMSTONE_22/upgrade/convprep61  ,
#     invoking it with an explicit path.
# STAGE 2:
# 5. set up your environment ($GEMSTONE) for the 2.x product tree. Maintain
#    your GS 6.1.5 extents; they will be read from during stage 2. The environment
#    variable upgradeLogDir must remain the same for stage 2 as it was for
#    stage 1.
# 6. start a 2.x gemstone with a virgin extent0.dbf and a config file specifying
#    all extents required for your 2.x system. Extent pregrow is recommended.
# 7. run the script conv61To2x. This script exists in the 2.x product tree
#    under the bin directory, so it needn't be called with an explicit path
# 8. wait for conv61To2x to exit.
# 9. restart the 2.x stone
# 10. run the script upgradeImageFrom61. This script exists in the 2.x product
#     tree under the bin directory, so it needn't be called with an explicit
#     path.
# 11. run the script postconv. This script exists in the 2.x product tree under
#     the bin directory, so it needn't be called with an explicit path.
#
# $Id: convprep61.sh,v 1.8 2008-01-09 22:50:52 stever Exp $
#
#=========================================================================

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

if [ "a$GEMSTONE_22" = "a" ]; then
  echo "ERROR: GEMSTONE_22 environment variable is required ."
  echo "       Please set it to the directory where GemStone64 v2.x resides."
  exit 1
fi


# maintenance symbols
comid="convprep61"              # this script's name

# make sure of a minimum path
PATH=:/bin:/usr/bin:/usr/ucb:$PATH; export PATH

. $GEMSTONE/bin/misc.sh

defaultErrorControl

info() {
  echo $comid[INFO]: $*
}
error() {
  echo $comid[ERROR]: $*
}
usage() {
cat <<EOF
Usage:
convprep61 [-h] [-s <stonename>]
Prepare a GemStone/S 6.1.5 repository for conversion to GemStone/S 64 bit 2.x.
Environment requirements:
    GEMSTONE          set to a GemStone/S 6.1.5 product tree
    upgradeLogDir     set to a writable directory
Parameters:
    -h print this Usage and exit
    -s <stonename>
        where <stonename> is the name of a running 6.1.5 stone (defaults
        to gemserver61)
EOF
}

# defaults
stoneName=gemserver61

#process command line
while getopts "hs:" opt; do
  case $opt in 
    h ) usage; exit 0 ;;
    s ) stoneName=$OPTARG ;;
   \? ) error "bad arg: $opt"; usage; exit 1 ;;
  esac
done
export stoneName

# make sure $upgradeLogDir has been set
info "verifying upgradeLogDir..."
if [ a$upgradeLogDir = "a" ]; then
  error "The environment variable upgradeLogDir has not been set."
  usage
  exit 1
elif [ ! -d $upgradeLogDir ]; then
  error "$upgradeLogDir is not a directory."
  usage
  exit 1
fi
info "...found upgradeLogDir..."

# make sure $upgradeLogDir is writable
touch $upgradeLogDir/tmp$$ 2>/dev/null 
if [ "$?" != "0" ]; then
  error "$upgradeLogDir is not writable."
  usage
  exit 1
fi
rm $upgradeLogDir/tmp$$
info "...upgradeLogDir is writable."

# make sure stone is running
info "verifying $stoneName is running..."
$GEMSTONE/bin/waitstone $stoneName -1 > /dev/null 2>&1
status=$?
if [ $status -ne 0 ]; then
  error "...no stone named $stoneName found"
  usage
  exit $status
fi
info "...$stoneName is running."

# clean up from previous runs, if any...
rm $upgradeLogDir/convprep61.log $upgradeLogDir/*.bm $upgradeLogDir/*.topaz \
$upgradeLogDir/ClassesForListInstances.txt $upgradeLogDir/ListOfSegments.txt \
$upgradeLogDir/from*.out >/dev/null 2>&1

# start topaz
info "starting topaz for conversion prep. This may take a while..."

$GEMSTONE/bin/topaz -l -i << EOF >$upgradeLogDir/convprep61.log 2>&1
output push $upgradeLogDir/convprep61.out only
set gemstone $stoneName
set u SystemUser p swordfish
login

iferror exit 1
display resultcheck
time

! This method was added in GS 6.1.5 and is required for conversion.
expectvalue %GsMethod
run
"Generates a run-time error if the method is not present."
Repository compiledMethodAt: #_writeGs64UpgradeDataToDirectory:
%

expectvalue true
run
| ver |
"check image version"
ver := (Globals at: #ImageVersion) at: #gsVersion.
(ver matchPattern: #('6.1')) ifFalse: [
  ((ver findPattern: #('6.2') startingAt: 1) == 0) ifTrue:[
     Object halt: 'need 6.1.5 or later image, found ImageVersion at: #gsVersion = ', ver].].
"check executable version"
ver := System gemVersionReport at: #gsRelease.
(ver matchPattern: #('6.1.' \$*)) ifFalse: [
  ((ver findPattern: #('6.2') startingAt: 1) == 0) ifTrue:[
    Object halt: 'need 6.1.5 or later system, found gsRelease = ',  ver].].
^true
%

! file in the SmallDouble class
! this version only files in the class if it does not already exist
input $GEMSTONE_22/upgrade/smalldoub_61to20.gs

! fix ordering of Segments in SystemRepository to agree with 64bit image
input $GEMSTONE_22/upgrade/segmentorder_61to20.gs

! Write out the list of segments used by this repository, in order.
expectvalue true
run
|outFile outFileName|

outFileName := String withAll: '$upgradeLogDir'.
(outFileName last == $/)
  ifFalse:[outFileName add: $/].
outFileName addAll: 'ListOfSegments.txt'.
outFile := GsFile openOnServer: outFileName mode: 'w'.
(outFile == nil)
  ifTrue:[^(String withAll: 'Cannot open output file ') addAll: outFileName; yourself].

outFile nextPutAll: SystemRepository size asString; lf.
SystemRepository do:[:eachSegment|
  outFile nextPutAll: eachSegment asOop asString; lf.
].
outFile close.
^true
%

! Read the IdentitySet containing a list of classes that the User wants us to 
! locate all instances of during conversion.
! This is strictly optional.

expectvalue %Boolean
run

|setOfClasses outFile outFileName nextLine|

setOfClasses := System myUserProfile resolveSymbol: #ConversionClassesToFind.

(setOfClasses == nil)
  ifTrue:[^false].

setOfClasses := setOfClasses value.

(setOfClasses size == 0)
  ifTrue:[^false].

(setOfClasses isKindOf: IdentitySet)
  ifFalse:[^String withAll: 'ConversionClassesToFind expected to be anIdentitySet'].

outFileName := String withAll: '$upgradeLogDir'.
(outFileName last == $/)
  ifFalse:[outFileName add: $/].
outFileName addAll: 'ClassesForListInstances.txt'.
outFile := GsFile openOnServer: outFileName mode: 'w'.
(outFile == nil)
  ifTrue:[^(String withAll: 'Cannot open output file ') addAll: outFileName; yourself].

setOfClasses do:[:eachClass|
  (eachClass isBehavior _and:[eachClass isMeta not]) ifTrue:[
  |theName theOop|
  theName := eachClass name asString.
  theOop := eachClass asOop asString.
  outFile nextPutAll: theName; nextPut: $|; nextPutAll: theOop; lf.
  ].
].
outFile close.
^true
%


expectvalue true
run
|stoneStats|
stoneStats := System cacheStatistics: 1.
((stoneStats at: 140) == 0)
  ifFalse:[^'Error: vote state is not VOTE_IDLE'].
((stoneStats at: 50) == 0)
  ifFalse:[^'Error: Possible dead set not empty'].
((stoneStats at: 88) == 0)
  ifFalse:[^'Error: GcPossible dead set not empty'].
((stoneStats at: 51) == 0)
  ifFalse:[^'Error: DeadNotReclaimed set not empty'].
^true
%

! Stop all sessions.  Shadow page reclaim will be done by stone
expectvalue true
run
System stopOtherSessions.
[System currentSessions size == 1] whileFalse:[
  System sleep: 1.
  System stopOtherSessions.
  System sleep: 1.
].
^true
%

abort

expectvalue true
run
"This automagically puts us into and back out of out of transactionless mode"
System _reclaimAllShadowPages
%

abort
! Make sure we only have 1 Commit record left.
expectvalue 1
run
(System cacheStatistics: 1) at: 35
%

! All shadow pages should be gone, make sure
expectvalue 0
run
SystemRepository _shadowPagesCount
%


! Now, finally, write the conversion files
expectvalue %Array
run
SystemRepository _writeGs64UpgradeDataToDirectory: '$upgradeLogDir'
%

! do a clean shutdown
expecterror GemStoneError 4057
send System shutDown

exit 
EOF

status=$?
if [ $status -ne 0 ]; then
  error "...topaz exited with status $status"
else
  info "...conversion preparation complete."
  touch $upgradeLogDir/from61_1.out
fi
exit $status
