LTO9-Optimizer/optimizer.sh

186 lines
6.6 KiB
Bash
Executable File

#!/bin/sh
###
### Usage: ./optimizer.sh </dev/sgX> <parallelism>
###
### -h | --help Shows this message
###
### optimizer.sh
### Necessary parameters:
### - sg device of the library
### - parallelism
###
### The script checks the parallelism with the available drives of the library/partition, then
### proceeds with loading *all* the tapes found in the slots. Mailboxes are ignored.
### It launches several child processes. The `timeout` command tries to unload the drives,
### it succeeds when the the tape optimization is done.
###
### Kill switch to stop the running processes: `killall optimizer.sh`
###
help() {
sed -rn 's/^### ?//;T;p' "$0"
}
if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "" ]]; then
help
exit 1
fi
log() {
echo -e "$(date +'%Y-%m-%d %H:%M:%S') $1" | tee -a ${LOG_FILE}
}
alive() {
# $1 "${LIB_SG}"
# $2 "${SLOT}"
# $3 "${DRIVE}"
# $4 "${BARCODE}"
echo "${4}" > "${TMP}/.drive${3}.lock"
local PID_ALIVE='1'
local WAIT=$((3600 + $RANDOM % 7200)) # from 1 to 2 hours
local TIMEOUT="600" # 10 minutes wait before dismounting the tape
while [ $PID_ALIVE -eq 1 ]; do
log "ALIVE [$$] - Waiting ${WAIT} seconds..."
sleep "${WAIT}"
log "ALIVE [$$] - Trying to unload drive ${3} into slot ${2} (Timeout: ${TIMEOUT} seconds)..."
timeout "${TIMEOUT}" mtx -f "${1}" unload "${2}" "${3}" # Kill after ${TIMEOUT} seconds
if [[ $(echo $?) == '0' ]]; then
log "ALIVE [$$] - OK. Drive ${3} unloaded."
grep -q "$4;drive$3;WIP" "${PROCESSED_BARCODES}" # Check if barcode is WIP
if [[ $(echo $?) == '0' ]]; then
log "ALIVE [$$] - Barcode $4 processed."
sed -i "s/$4;drive$3;WIP/$4;OK/g" "${PROCESSED_BARCODES}"
rm -f "${TMP}/.drive${3}.lock"
touch "${TMP}/.drive${3}.ready"
log "ALIVE [$$] - Drive ${3} newly available. Exit."
local PID_ALIVE='0'
return 0 # End Alive
else
log "ALIVE [$$] - ERROR. Can't find the barcode among the WIP. Exit."
return 1
fi # Barcode processed --> OK
elif [ -f "${TMP}/.drive${3}.lock" ]; then # Drive in use
log "ALIVE [$$] - Unmount drive ${3} failed, still in use (file .lock). Checking the content."
grep -q "${4}" "${TMP}/.drive${3}.lock"
if [[ $(echo $?) == '0' ]]; then
log "ALIVE [$$] - File content OK. Waiting."
continue
else
log "ALIVE [$$] - ERROR. File content of ${TMP}/.drive${3}.lock not coherent. Exit."
return 1
fi
elif [ -f "${TMP}/.drive${3}.ready" ]; then # Drive available
log "ALIVE [$$] - Found file ${TMP}/.drive${3}.ready. Drive available. Exit."
local PID_ALIVE='0'
return 0
fi
done
log "End ALIVE [$$]"
return 0
}
LIB_SG=$1
PARALLELISM=$2
WAIT=$((300))
TMP='/tmp'
LIB_CONFIG="${TMP}/lib_config.txt"
PROCESSED_SLOTS="${TMP}/processed-slots.txt"
PROCESSED_BARCODES="/root/processed-barcodes.txt"
log "***** New execution *****"
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
LOG_PATH="${SCRIPT_DIR}/log"
LOG_FILE="${LOG_PATH}/optimizer.log"
if [ ! -d "${LOG_PATH}" ]; then
echo "Creating the log directory: ${LOG_PATH}"
mkdir -vp ${LOG_PATH}
fi
mtx -f "${LIB_SG}" status > "${LIB_CONFIG}"
# Check if there are enough ($PARALLELISM) free drives
if [[ $(grep "Data Transfer Element" ${LIB_CONFIG} | grep 'Empty' | wc -l) -lt "${PARALLELISM}" ]]; then
log "ERROR. Not enough free drives. Exit."
exit 1
fi
# Clean the WIP barcodes from old executions
sed -i '/WIP/d' "${PROCESSED_BARCODES}"
# Cleaning orphan files
rm -rf ${TMP}/.drive*
rm -rf ${PROCESSED_SLOTS}
for (( i = 0 ; i < ${PARALLELISM} ; i++ )); do
grep -q "Data Transfer Element ${i}:Empty" ${LIB_CONFIG}
if [[ $(echo $?) == '0' ]]; then
if [[ ! -f "${TMP}/.drive${i}.ready" ]]; then
log "Creating file ${TMP}/.drive${i}.ready"
touch "${TMP}/.drive${i}.ready"
fi
fi
done
# List full slots
SLOTS_FULL="${TMP}/slots_full.txt"
grep 'Storage Element' ${LIB_CONFIG} | grep 'Full' | grep -v IMPORT | grep -v CLN | grep -v "(" > ${SLOTS_FULL}
COUNT=1
OFS=$IFS
IFS="
"
while [ $COUNT -le $(cat ${SLOTS_FULL} | wc -l) ]; do
RUNNING=$(ls -1q ${TMP}/.drive*.lock | wc -l)
if [[ "${RUNNING}" -lt "${PARALLELISM}" ]]; then
SLOT=$(sed "${COUNT}q;d" ${SLOTS_FULL} | awk '{print $3;}' | cut -d ':' -f 1)
BARCODE=$(sed "${COUNT}q;d" ${SLOTS_FULL} | awk '{print $4;}' | cut -d '=' -f 2)
grep -q "${SLOT}" "${PROCESSED_SLOTS}" # Check if slot is aready processed
if [[ $(echo $?) == '0' ]]; then
echo "Slot ${SLOT} already processed."
((COUNT++))
continue
fi
grep -q "${BARCODE};OK" "${PROCESSED_BARCODES}" # Check if barcode is already processed
if [[ $(echo $?) == '0' ]]; then
echo "Barcode ${BARCODE} already processed. Skip."
((COUNT++))
continue
fi
log "### SLOT ${SLOT} - BARCODE ${BARCODE}"
for (( i = 0 ; i < ${PARALLELISM} ; i++ )); do # Look for an available drive
if [ -f "${TMP}/.drive${i}.ready" ]; then # Look for ".ready" file
DRIVE=${i}
mv "${TMP}/.drive${DRIVE}.ready" "${TMP}/.drive${DRIVE}.lock"
break
fi
done
log "Loading slot ${SLOT} into drive ${DRIVE}."
mtx -f "${LIB_SG}" load "${SLOT}" "${DRIVE}"
echo "${BARCODE};drive${DRIVE};WIP" >> "${PROCESSED_BARCODES}" # Barcode WIP
echo ${SLOT} >> "${PROCESSED_SLOTS}"
log "Launching ALIVE with parameters: ${LIB_SG} - ${SLOT} - ${DRIVE} - ${BARCODE}"
alive "${LIB_SG}" "${SLOT}" "${DRIVE}" "${BARCODE}" &
RUNNING=$(ls -1q ${TMP}/.drive*.lock | wc -l)
log "MAIN - RUNNING processes: $RUNNING"
if [[ "${RUNNING}" -ge "${PARALLELISM}" ]]; then
log "MAIN (if) - Maximum parallelism. Waiting ${WAIT} seconds…"
sleep "${WAIT}"
else
((COUNT++))
log "Waiting 2 minutes to avoid too many commands."
sleep 120
fi
else
log "MAIN - Maximum parallelism. Waiting ${WAIT} seconds…"
sleep "${WAIT}"
fi
done
IFS=$OFS
rm -rf "${LIB_CONFIG}"
rm -rf "${SLOTS_FULL}"
rm -rf "${PROCESSED_SLOTS}"
log "***** End execution *****\n\n"