blob: 4c8ae6213a00df82131c77955e143c4f7b022140 [file] [log] [blame]
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Environment Variables
#
# DRILL_CONF_DIR Alternate drill conf dir. Default is ${DRILL_HOME}/conf.
# DRILL_LOG_DIR Where log files are stored. Default is /var/log/drill if
# that exists, else $DRILL_HOME/log
# DRILL_PID_DIR The pid files are stored. $DRILL_HOME by default.
# DRILL_IDENT_STRING A string representing this instance of drillbit.
# $USER by default
# DRILL_NICENESS The scheduling priority for daemons. Defaults to 0.
# DRILL_STOP_TIMEOUT Time, in seconds, after which we kill -9 the server if
# it has not stopped.
# Default 120 seconds.
# SERVER_LOG_GC Set to "1" to enable Java garbage collector logging.
#
# See also the environment variables defined in drill-config.sh
# and runbit. Most of the above can be set in drill-env.sh for
# each site.
#
# Modeled after $HADOOP_HOME/bin/hadoop-daemon.sh
#
# Usage:
#
# drillbit.sh [--config conf-dir] cmd [arg1 arg2 ...]
#
# The configuration directory, if provided, must exist and contain a Drill
# configuration file. The option takes precedence over the
# DRILL_CONF_DIR environment variable.
#
# The command is one of: start|stop|status|restart|run|graceful_stop
#
# Additional arguments are passed as JVM options to the Drill-bit.
# They typically are of the form:
#
# -Dconfig-var=value
#
# Where config-var is a fully expanded form of a configuration variable.
# The value overrides any value in the user or Drill configuration files.
usage="Usage: drillbit.sh [--config|--site <site-dir>]\
(start|stop|status|restart|run|graceful_stop) [args]"
bin=`dirname "${BASH_SOURCE-$0}"`
bin=`cd -P "$bin">/dev/null; pwd`
base=`basename "${BASH_SOURCE-$0}"`
command=${base/.*/}
# Environment variable to indicate Drillbit is being setup. Later drill-env.sh
# and distrib-env.sh can consume this to set common environment variable differently
# for Drillbit and Sqlline.
export DRILLBIT_CONTEXT=1
# Setup environment. This parses, and removes, the
# options --config conf-dir parameters.
. "$bin/drill-config.sh"
# if no args specified, show usage
if [ ${#args[@]} = 0 ]; then
echo $usage
exit 1
fi
# Get command. all other args are JVM args, typically properties.
startStopStatus="${args[0]}"
args[0]=''
export args
# Set default scheduling priority
DRILL_NICENESS=${DRILL_NICENESS:-0}
GRACEFUL_FILE=$DRILL_HOME/$GRACEFUL_SIGFILE
waitForProcessEnd()
{
pidKilled=$1
commandName=$2
kill_drillbit=$3
processedAt=`date +%s`
triggered_shutdown=false
origcnt=${DRILL_STOP_TIMEOUT:-120}
while kill -0 $pidKilled > /dev/null 2>&1;
do
echo -n "."
sleep 1;
#Incase of graceful shutdown, create graceful file and wait till the process ends.
if [ "$kill_drillbit" = false ]; then
if [ "$triggered_shutdown" = false ]; then
touch $GRACEFUL_FILE
triggered_shutdown=true
fi
fi
if [ "$kill_drillbit" = true ] ; then
# if process persists more than $DRILL_STOP_TIMEOUT (default 120 sec) no mercy
if [ $(( `date +%s` - $processedAt )) -gt $origcnt ]; then
break;
fi
fi
done
echo
# process still there : kill -9
if kill -0 $pidKilled > /dev/null 2>&1; then
echo "$commandName did not complete after $origcnt seconds, killing with kill -9 $pidKilled"
`dirname $JAVA`/jstack -l $pidKilled > "$logout" 2>&1
kill -9 $pidKilled > /dev/null 2>&1
fi
}
check_before_start()
{
#check that the process is not running
mkdir -p "$DRILL_PID_DIR"
if [ -f $pidFile ]; then
if kill -0 `cat $pidFile` > /dev/null 2>&1; then
echo "$command is already running as process `cat $pidFile`. Stop it first."
exit 1
fi
fi
#remove any previous uncleaned graceful file
if [ -f "$GRACEFUL_FILE" ]; then
rm $GRACEFUL_FILE
rm_status=$?
if [ $rm_status -ne 0 ];then
echo "Error: Failed to remove $GRACEFUL_FILE!"
exit $rm_status
fi
fi
}
check_after_start(){
dbitPid=$1;
# Check and enforce for CGroup
if [ -n "$DRILLBIT_CGROUP" ]; then
check_and_enforce_cgroup $dbitPid
fi
}
check_and_enforce_cgroup(){
dbitPid=$1;
kill -0 $dbitPid
if [ $? -gt 0 ]; then
echo "ERROR: Failed to add Drillbit to CGroup ( $DRILLBIT_CGROUP ) for 'cpu'. Ensure that the Drillbit ( pid=$dbitPid ) started up." >&2
exit 1
fi
SYS_CGROUP_DIR=${SYS_CGROUP_DIR:-"/sys/fs/cgroup"}
if [ -f $SYS_CGROUP_DIR/cpu/$DRILLBIT_CGROUP/cgroup.procs ]; then
echo $dbitPid > $SYS_CGROUP_DIR/cpu/$DRILLBIT_CGROUP/cgroup.procs
# Verify Enforcement
cgroupStatus=`grep -w $dbitPid $SYS_CGROUP_DIR/cpu/${DRILLBIT_CGROUP}/cgroup.procs`
if [ -n "$cgroupStatus" ]; then
#Ref: https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
cpu_quota=`cat ${SYS_CGROUP_DIR}/cpu/${DRILLBIT_CGROUP}/cpu.cfs_quota_us`
cpu_period=`cat ${SYS_CGROUP_DIR}/cpu/${DRILLBIT_CGROUP}/cpu.cfs_period_us`
if [ $cpu_period -gt 0 ] && [ $cpu_quota -gt 0 ]; then
coresAllowed=`echo $(( 100 * $cpu_quota / $cpu_period )) | sed 's/..$/.&/'`
echo "INFO: CGroup (drillcpu) will limit Drill to $coresAllowed cpu(s)"
fi
else
echo "ERROR: Failed to add Drillbit to CGroup ( $DRILLBIT_CGROUP ) for 'cpu'. Ensure that the cgroup manages 'cpu'" >&2
fi
else
echo "ERROR: CGroup $DRILLBIT_CGROUP not found. Ensure that daemon is running, SYS_CGROUP_DIR is correctly set (currently, $SYS_CGROUP_DIR ), and that the CGroup exists" >&2
fi
}
wait_until_done ()
{
p=$1
cnt=${DRILLBIT_TIMEOUT:-300}
origcnt=$cnt
while kill -0 $p > /dev/null 2>&1; do
if [ $cnt -gt 1 ]; then
cnt=`expr $cnt - 1`
sleep 1
else
echo "Process did not complete after $origcnt seconds, killing."
kill -9 $p
exit 1
fi
done
return 0
}
start_bit ( )
{
check_before_start
echo "Starting $command, logging to $logout"
echo "`date` Starting $command on `hostname`" >> "$DRILLBIT_LOG_PATH"
echo "`ulimit -a`" >> "$DRILLBIT_LOG_PATH" 2>&1
nohup nice -n $DRILL_NICENESS "$DRILL_HOME/bin/runbit" exec ${args[@]} >> "$logout" 2>&1 &
procId=$!
echo $procId > $pidFile # Yeah, $pidFile is a file, $procId is the pid...
echo $! > $pidFile
sleep 1
check_after_start $procId
}
stop_bit ( )
{
kill_drillbit=$1
if [ -f $pidFile ]; then
pidToKill=`cat $pidFile`
# kill -0 == see if the PID exists
if kill -0 $pidToKill > /dev/null 2>&1; then
echo "Stopping $command"
echo "`date` Terminating $command pid $pidToKill" >> "$DRILLBIT_LOG_PATH"
if [ $kill_drillbit = true ]; then
kill $pidToKill > /dev/null 2>&1
fi
waitForProcessEnd $pidToKill $command $kill_drillbit
retval=0
else
retval=$?
echo "No $command to stop because kill -0 of pid $pidToKill failed with status $retval"
fi
rm $pidFile > /dev/null 2>&1
else
echo "No $command to stop because no pid file $pidFile"
retval=1
fi
return $retval
}
pidFile=$DRILL_PID_DIR/drillbit.pid
logout="${DRILL_LOG_PREFIX}.out"
thiscmd=$0
case $startStopStatus in
(start)
start_bit
;;
(run)
# Launch Drill as a child process. Does not redirect stderr or stdout.
# Does not capture the Drillbit pid.
# Use this when launching Drill from your own script that manages the
# process, such as (roll-your-own) YARN, Mesos, supervisord, etc.
echo "`date` Starting $command on `hostname`"
echo "`ulimit -a`"
$DRILL_HOME/bin/runbit exec ${args[@]}
;;
(stop)
kill_drillbit=true
stop_bit $kill_drillbit
exit $?
;;
# Shutdown the drillbit gracefully without disrupting the in-flight queries.
# In this case, if there are any long running queries the drillbit will take a
# little longer to shutdown. Incase if the user wishes to shutdown immediately
# they can issue stop instead of graceful_stop.
(graceful_stop)
kill_drillbit=false
stop_bit $kill_drillbit
exit $?
;;
(restart)
# stop the command
kill_drillbit=true
stop_bit $kill_drillbit
# wait a user-specified sleep period
sp=${DRILL_RESTART_SLEEP:-3}
if [ $sp -gt 0 ]; then
sleep $sp
fi
# start the command
start_bit
;;
(status)
if [ -f $pidFile ]; then
TARGET_PID=`cat $pidFile`
if kill -0 $TARGET_PID > /dev/null 2>&1; then
echo "$command is running."
else
echo "$pidFile file is present but $command is not running."
exit 1
fi
else
echo "$command is not running."
exit 1
fi
;;
(debug)
# Undocumented command to print out environment and Drillbit
# command line after all adjustments.
echo "command: $command"
echo "args: ${args[@]}"
echo "cwd:" `pwd`
# Print Drill command line
"$DRILL_HOME/bin/runbit" debug ${args[@]}
;;
(*)
echo $usage
exit 1
;;
esac