Home | History | Annotate | Download | only in site_utils
      1 #!/bin/bash
      2 
      3 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # This script creates a CPU set and binds the MySQL process to the
      8 # set. It restarts MySQL if specified in the option. This script needs
      9 # to be run with "sudo".
     10 
     11 set -e # Exit if any function returns a non-zero value.
     12 set -o nounset # Exit if any variable is used unset.
     13 
     14 MYSQL_PATH='/etc/init.d/mysql.server'
     15 MYSQL_PID_PATH='/var/lib/mysql/atlantis1.mtv.corp.google.com.pid'
     16 MYSQL_PROC_NAME='mysqld'
     17 
     18 # The directory where we mount the cpuset virutal file system to.
     19 MOUNT_DIR='/dev/cpuset'
     20 # The base cpuset directory for mysql.
     21 MYSQL_CPUSET='mysql'
     22 # CPUs in MySQL cpuset. E.g. 0-2,7,12-14.
     23 MYSQL_DEFAULT_CPUS=10-15
     24 
     25 
     26 # Display usage.
     27 function usage() {
     28   echo -e "Usage: $0 [-c <CPUs>] [-p <PID>] [-r] [-d]\n"
     29   echo -e "Create and bind the MySQL process to a specified CPU set.\n"
     30   echo -e "Options:"
     31   echo -e "  -c <CPUs>  Specify a list of CPUs to be used. E.g. 0-2,7,12-14"
     32   echo -e "             (Default: $MYSQL_DEFAULT_CPUS)."
     33   echo -e "  -d         Delete the CPU set. This option kills the current"
     34   echo -e "             MySQL process and delete the CPU set. It does not"
     35   echo -e "             restart MySQL nor create a new CPU set. (Default:"
     36   echo -e "             disabled)."
     37   echo -e "  -p <PID>   Bind <PID> to the cpuset (Default: the script searches"
     38   echo -e "             for the MySQL PID automatically)."
     39   echo -e "  -r         Restart MySQL (Default: disabled)."
     40   echo -e "  -h         Display this usage information."
     41   echo -e "\n"
     42 }
     43 
     44 function print_info() {
     45   msg=$1
     46   echo "INFO:  "$msg
     47 }
     48 
     49 function print_error() {
     50   msg=$1
     51   echo "ERROR: "$msg
     52 }
     53 
     54 # Run and print out the command if the silent flag is not set (the default).
     55 # Usage: run_cmd <cmd> [slient]
     56 function run_cmd() {
     57   cmd=""
     58   slient=0
     59 
     60   if [ $# -gt 0 ]; then
     61     cmd=$1
     62   else
     63     print_error "Empty command!"
     64     return 1
     65   fi
     66 
     67   if [ $# -gt 1 ]; then
     68     silent=$2
     69   fi
     70 
     71   if [ $slient -eq 0 ]; then
     72     print_info "Running \"${1}\""
     73   fi
     74 
     75   # Print an error message if the command failed.
     76   eval "$1" || { print_error "Failed to execute \"${cmd}\""; return 1; }
     77 }
     78 
     79 # Get the PID of the MySQL.
     80 function get_mysql_pid() {
     81   local pid=""
     82 
     83   if [ $# -gt 0 ] && [ ! -z "$1" ]; then
     84     # Use user-provided PID.
     85     pid=$1
     86   elif [ ! -z ${MYSQL_PID_PATH} -a -f ${MYSQL_PID_PATH} ]; then
     87     # Get PID from MySQL PID file if it is set.
     88     print_info "Getting MySQL PID from ${MYSQL_PID_PATH}..."
     89     pid=$(cat $MYSQL_PID_PATH) || \
     90       { print_error "No MySQL process found."; return 1; }
     91   else
     92     # Get PID of process named mysqld.
     93     print_info "Searching for MySQL PID..."
     94     # Ignore the return code to print out an error message.
     95     pid=$(pidof $MYSQL_PROC_NAME) || \
     96       { print_error "No MySQL process found."; return 1; }
     97   fi
     98 
     99   # Test if the PID is an integer
    100   if [[ $pid != [0-9]* ]]; then
    101     print_error "No MySQL process found."
    102     return 1
    103   fi
    104 
    105   # Check if the PID is a running process.
    106   if [ ! -d "/proc/${pid}" ]; then
    107     print_error "No running MySQL process is found."
    108     return 1
    109   fi
    110 
    111   _RET="$pid"
    112   print_info "MySQL PID is ${pid}."
    113 }
    114 
    115 # Mount the cpuset virtual file system.
    116 function mount_cpuset() {
    117   if (mount | grep "on ${MOUNT_DIR} type" > /dev/null)
    118   then
    119     print_info "${MOUNT_DIR} already mounted."
    120   else
    121     print_info "Mounting cpuset to $MOUNT_DIR."
    122     run_cmd "mkdir -p ${MOUNT_DIR}"
    123     run_cmd "mount -t cpuset none ${MOUNT_DIR}"
    124   fi
    125 }
    126 
    127 
    128 function clean_all() {
    129   local delete_msg="No"
    130   print_info "Will Delete existing CPU set..."
    131   echo -ne "WARNING: This operation will kill all running "
    132   echo "processes in the CPU set."
    133   echo -ne "Are you sure you want to proceed "
    134   echo -ne "(type \"yes\" or \"Yes\" to proceed)? "
    135   read delete_msg
    136 
    137   mount_cpuset
    138 
    139   local proc_list=""
    140   local proc=""
    141 
    142   if [ "$delete_msg" = "yes" -o "$delete_msg" = "Yes" ]; then
    143     if [ -d "${MOUNT_DIR}/${MYSQL_CPUSET}" ]; then
    144       proc_list=$(cat ${MOUNT_DIR}/${MYSQL_CPUSET}/cgroup.procs)
    145       for proc in $proc_list; do
    146         run_cmd "kill -9 ${proc}"
    147       done
    148       # Remove the CPU set directory.
    149       run_cmd "rmdir ${MOUNT_DIR}/${MYSQL_CPUSET}"
    150       # Unmount the cpuset virtual file system.
    151       run_cmd "umount ${MOUNT_DIR}"
    152     else
    153       print_info "The CPU set does not exist."
    154       return 1
    155     fi
    156     print_info "Done!"
    157   else
    158     # User does not wish to continue.
    159     print_info "Aborting program."
    160   fi
    161 }
    162 
    163 
    164 function main() {
    165 
    166   local MYSQL_CPUS=$MYSQL_DEFAULT_CPUS
    167   local RESTART_MYSQL_FLAG=0
    168   local DELETE_CPUSET_FLAG=0
    169   local MYSQL_PID=""
    170 
    171   # Parse command-line arguments.
    172   while getopts ":c:dhp:r" opt; do
    173     case $opt in
    174       c)
    175         MYSQL_CPUS=$OPTARG
    176         ;;
    177       d)
    178         DELETE_CPUSET_FLAG=1
    179         ;;
    180       h)
    181         usage
    182         return 0
    183         ;;
    184       p)
    185         MYSQL_PID=$OPTARG
    186         ;;
    187       r)
    188         RESTART_MYSQL_FLAG=1
    189         ;;
    190       \?)
    191         echo "Invalid option: -$OPTARG" >&2
    192         usage
    193         return 1
    194         ;;
    195       :)
    196         echo "Option -$OPTARG requires an argument." >&2
    197         usage
    198         return 1
    199         ;;
    200     esac
    201   done
    202 
    203 
    204   # Clean up and exit if the flag is set.
    205   if [ $DELETE_CPUSET_FLAG -eq 1 ]; then
    206     clean_all
    207     return 0
    208   fi
    209 
    210   # Restart MySQL.
    211   if [ $RESTART_MYSQL_FLAG -eq 1 ]; then
    212     print_info "Restarting MySQL..."
    213     $MYSQL_PATH restart
    214   fi
    215 
    216 
    217   # Get PID of MySQL.
    218   get_mysql_pid "$MYSQL_PID"
    219   MYSQL_PID=$_RET
    220 
    221   mount_cpuset
    222 
    223   # Make directory for MySql.
    224   print_info "Making a cpuset for MySQL..."
    225   run_cmd "mkdir -p ${MOUNT_DIR}/${MYSQL_CPUSET}"
    226 
    227   # Change working directory.
    228   run_cmd "cd ${MOUNT_DIR}/${MYSQL_CPUSET}"
    229 
    230   # Update the CPUs to use in the CPU set. Note that we use /bin/echo
    231   # explicitly (instead of "echo") because it displays write errors.
    232   print_info "Updating CPUs in the cpuset..."
    233   run_cmd "bash -c \"/bin/echo ${MYSQL_CPUS} > cpus\""
    234 
    235   # Attach/Rebind MySQL process to the cpuset. Note that this command
    236   # can only attach one PID at a time. This needs to be run every time
    237   # after the CPU set is modified.
    238   print_info "Bind MySQL process to the cpuset..."
    239   run_cmd "bash -c \"/bin/echo ${MYSQL_PID} > tasks\""
    240 
    241   print_info "Done!"
    242 }
    243 
    244 main "$@"
    245