Yu-Ju Hong | b652f0f | 2012-08-20 11:42:42 -0700 | [diff] [blame] | 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 | |
Yu-Ju Hong | c63cc63 | 2012-08-30 09:57:26 -0700 | [diff] [blame] | 83 | if [ $# -gt 0 ] && [ ! -z "$1" ]; then |
Yu-Ju Hong | b652f0f | 2012-08-20 11:42:42 -0700 | [diff] [blame] | 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 "$@" |