mysql脚本解读_一篇很好的关于mysqld_safe脚本源码解读的文章,收藏了!!
#!/bin/sh# 一些狀態(tài)變量的定義
KILL_MYSQLD=1; # 試圖kill多余的mysqld_safe程序,1表示需要kill
MYSQLD=# mysqld二進制可執(zhí)行文件的名稱
niceness=0# 進程的調度優(yōu)先級標識
# 下面的變量主要用于標識不使用錯誤日志和syslog
logging=init # 日志記錄狀態(tài),init代表初始化
want_syslog=0# 標識是否要使用syslog
syslog_tag=user='mysql' # --user選項值
pid_file=# pid文件的路徑
err_log=# 錯誤日志的路徑
# 這兩個都是定義的syslog中標志位,在后面需要寫入日志到syslog中時使用
syslog_tag_mysqld=mysqld
syslog_tag_mysqld_safe=mysqld_safe
trap'' 1 2 3 15# 不允許程序在終端上被人打斷(包括掛起,中斷,退出,系統(tǒng)終止的情形)
umask007# 默認權限770,其他組用戶對該程序創(chuàng)建的文件沒有任何權限
# defaults變量記載使用的配置文件的信息
defaults=
case "$1" in
--no-defaults|--defaults-file=*|--defaults-extra-file=*)
defaults="$1"; shift;;esac# usage()函數:使用--help選項時輸出的使用幫助信息
usage () {cat <
Usage: $0[OPTIONS]--no-defaults Don't read the system defaults file
--defaults-file=FILE Use the specified defaults file
--defaults-extra-file=FILE Also use defaults from the specified file
--ledir=DIRECTORY Look for mysqld inthe specified directory--open-files-limit=LIMIT Limit the number of open files--core-file-size=LIMIT Limit core files to the specified size--timezone=TZ Set the system timezone--mysqld=FILE Use the specified fileas mysqld--mysqld-version=VERSION Use "mysqld-VERSION"as mysqld--nice=NICE Set the scheduling priority of mysqld--skip-kill-mysqld Don't try to kill stray mysqld processes
--syslog Log messages to syslog with 'logger'
--skip-syslog Log messages to error log (default)--syslog-tag=TAG Pass -t "mysqld-TAG" to 'logger'All other options are passed to the mysqld program.
EOF
exit1}
# my_which的作用相當于which,通過檢索$PATH中的路徑,打印出命令的全路徑
# 這個函數就在后面一個地方用到了,就是my_which logger,意思等同于轉換logger為/usr/bin/logger
my_which ()
{
save_ifs="${IFS-UNSET}"# 保存當前的內建分隔符,用于后面重置IFS
IFS=: # 使用 : 來分割PATH中的路徑
ret=0
for file # 這種寫法等同于for file in &*
do
for dir in$PATHdo
if [ -f "$dir/$file"]then
echo "$dir/$file"continue2 # continue 第 2層, 這里就是跳出外層循環(huán)了fi
doneret=1# signal an error
breakdone# 將設置過的IFS重置回去if [ "$save_ifs" =UNSET ]thenunset IFSelseIFS="$save_ifs"
fireturn $ret # Success
}
# 日志輸出函數,這是個原型,后面被log_error和log_notice函數引用
log_generic () {
# priority 代表日志信息的分類,從后面的兩個函數可知有:daemon.error和daemon.notice兩種類別
priority="$1"
shift# 日志中記錄的msg前綴格式: 時間+mysqld_safe ,類似于系統(tǒng)日志的記錄格式
msg="`date +'%y%m%d %H:%M:%S'` mysqld_safe $*"
echo "$msg"
case $logging ininit) ;; # 初始化狀態(tài)時,只在命令行輸出msg信息,不記錄日志file) echo "$msg" >> "$err_log";; # 記錄到err_log中
syslog) logger-t "$syslog_tag_mysqld_safe" -p "$priority" "$*";; # 使用logger記錄到系統(tǒng)日志中*)echo "Internal program error (non-fatal):"\"unknown logging method '$logging'" >&2;;esac}
# 下面兩個函數是對log_generic函數中不同分類的引用
log_error () {
log_generic daemon.error"$@" >&2}
log_notice () {
log_generic daemon.notice"$@"}
# 后面就是用它啟動的mysqld,通過logging變量區(qū)分記錄日志的類型,分錯誤日志和系統(tǒng)日志syslog兩種
# 最后的eval命令會解析 $cmd 中的值并執(zhí)行命令
eval_log_error () {
cmd="$1"
case $logging in
file) cmd="$cmd >>"`shell_quote_string "$err_log"`"2>&1";;
syslog)
cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error";;*)echo "Internal program error (non-fatal):"\"unknown logging method '$logging'" >&2;;esac#echo "Running mysqld: [$cmd]"eval"$cmd"}
# 轉義函數,用于在非"a-z","A-Z","09",'/','_','.','=','-'的特殊字符前加上一個"\"
# sed中的\1代表引用前面\(\)中匹配的值
shell_quote_string() {echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g'}
# 該函數用于解析配置文件中的選項,并賦值給相應的變量
parse_arguments() {
pick_args=
if test "$1" = PICK-ARGS-FROM-ARGVthenpick_args=1
shift
fi
for arg do# 取出參數值,比如--port=3306 結果為: val = 3306 注意這里sed中使用;來分割,等同于/val=`echo "$arg" | sed -e "s;--[^=]*=;;"`case "$arg" in# 將參數值傳遞給對應的變量--basedir=*) MY_BASEDIR_VERSION="$val";;--datadir=*) DATADIR="$val";;--pid-file=*) pid_file="$val";;--user=*) user="$val"; SET_USER=1;;
# 有些值可能已經在my.cnf配置文件的[mysqld_safe]組下設置了
# 某些值會被命令行上指定的選項值覆蓋--log-error=*) err_log="$val";;--port=*) mysql_tcp_port="$val";;--socket=*) mysql_unix_port="$val";;
# 接下來這幾個特殊的選項在配置文件的[mysqld_safe]組中是必須設置的
# 我沒配置這個組,所以就用不到了(使用mysqld中的默認)--core-file-size=*) core_file_size="$val";;--ledir=*) ledir="$val";;--mysqld=*) MYSQLD="$val";;--mysqld-version=*)if test -n "$val"
thenMYSQLD="mysqld-$val"
elseMYSQLD="mysqld"
fi;;--nice=*) niceness="$val";;--open-files-limit=*) open_files="$val";;--skip-kill-mysqld*) KILL_MYSQLD=0;;--syslog) want_syslog=1;;--skip-syslog) want_syslog=0;;--syslog-tag=*) syslog_tag="$val";;--timezone=*) TZ="$val"; export TZ; ;; # 生效了一下時區(qū)設置--help) usage ;; # 調用了usage函數,輸出幫助信息*)if test -n "$pick_args"
then# 將其他命令行參數值附加到$arg的后面
append_arg_to_args"$arg"
fi;;esac
done}
########################################
# 正式工作開始了!!
########################################
#
# 下面兩段是在尋找基目錄和mysqld所在目錄
#
# 找到/usr/local/mysql3306/share/mysql目錄,使用relpkgdata來記錄相對路徑和絕對路徑
# 這個grep其實應該是想判斷一下share/mysql是不是顯示的絕對路徑,不知道這么寫的意義在哪里。if echo '/usr/local/mysql3306/share/mysql' | grep '^/usr/local/mysql3306' > /dev/null
then# 一口氣用了三個替換,分別為:
# 第一步:將/usr/local/mysql3306轉換為空
# 第二步:將/share/mysql開頭的/轉換為空
# 第三步:在share/mysql開頭加上./,結果即:./share/mysql
relpkgdata=`echo '/usr/local/mysql3306/share/mysql' | sed -e 's,^/usr/local/mysql3306,,' -e 's,^/,,' -e 's,^,./,'`elserelpkgdata='/usr/local/mysql3306/share/mysql'
fi# 這一段都是在找mysqld文件,分別判斷了libexec和bin目錄
# 找不到就使用編譯時的默認值
MY_PWD=`pwd`if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION"
then
if test -x "$MY_BASEDIR_VERSION/libexec/mysqld"
thenledir="$MY_BASEDIR_VERSION/libexec"
elseledir="$MY_BASEDIR_VERSION/bin"
fi# 這里對errmsg.sys文件進行了判斷,個人認為這是為了確認當前目錄為一個mysql安裝基目錄elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/mysqld"
thenMY_BASEDIR_VERSION="$MY_PWD"ledir="$MY_PWD/bin"
elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/mysqld"
thenMY_BASEDIR_VERSION="$MY_PWD"ledir="$MY_PWD/libexec"
elseMY_BASEDIR_VERSION='/usr/local/mysql3306'ledir='/usr/local/mysql3306/libexec'
fi#
# 接下來是找到配置文件和數據文件目錄
#
# 找到配置文件目錄
# 我的是放在了etc/目錄下,mysqld程序是會讀取到的
#
# 可以從my_print_defaults腳本中獲得默認的讀取my.cnf順序,如下
# Default options are read from the following filesinthe given order:
#/etc/my.cnf /etc/mysql/my.cnf /home/mysql/mysql_master/etc/my.cnf ~/.my.cnf
# 或者可以使用strace-e open libexec/mysqld 2>&1 | grepmy.cnf查看if test -d $MY_BASEDIR_VERSION/data/mysqlthenDATADIR=$MY_BASEDIR_VERSION/dataif test -z "$defaults" -a -r "$DATADIR/my.cnf"
thendefaults="--defaults-extra-file=$DATADIR/my.cnf"
fi# 接下來找到數據文件的目錄elif test -d $MY_BASEDIR_VERSION/var/mysqlthenDATADIR=$MY_BASEDIR_VERSION/var
# 找不到就用編譯時指定的默認值elseDATADIR=/usr/local/mysql3306/varfi# 對存在兩個配置文件情況進行沖突處理if test -z "$MYSQL_HOME"
then
if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf"
then# 優(yōu)先考慮 $MY_BASEDIR_VERSION/my.cnf 文件
log_error"WARNING: Found two instances of my.cnf -
$MY_BASEDIR_VERSION/my.cnf and
$DATADIR/my.cnf
IGNORING $DATADIR/my.cnf"MYSQL_HOME=$MY_BASEDIR_VERSIONelif test -r "$DATADIR/my.cnf"
thenlog_error"WARNING: Found $DATADIR/my.cnf
The data directory is a deprecated location formy.cnf, please move it to
$MY_BASEDIR_VERSION/my.cnf" MYSQL_HOME=$DATADIRelseMYSQL_HOME=$MY_BASEDIR_VERSIONfi
fiexport MYSQL_HOME
#
# 下面是使用bin/my_print_defaults讀取my.cnf文件中的配置信息([mysqld] and [mysqld_safe])
# 并且和命令行中傳入的參數進行合并
# 先是找到my_print_defaults執(zhí)行文件 又是各種路徑判斷if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults"
thenprint_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults"
elif test -x ./bin/my_print_defaultsthenprint_defaults="./bin/my_print_defaults"
elif test -x /usr/local/mysql3306/bin/my_print_defaultsthenprint_defaults="/usr/local/mysql3306/bin/my_print_defaults"
elif test -x /usr/local/mysql3306/bin/mysql_print_defaultsthenprint_defaults="/usr/local/mysql3306/bin/mysql_print_defaults"
elseprint_defaults="my_print_defaults"
fi# 這個函數可以將一個指定的參數附加到$arg中(在此同時執(zhí)行了轉義操作)
append_arg_to_args () {
args="$args"`shell_quote_string "$1"`
}
args=# 這里SET_USER=2是針對下面一條parse_arguments來說的
# 因為如果在緊接著的parse_arugments函數中設置了--user的值,那么SET_USER就會變?yōu)?,表示--user以被配置
# 當然如果沒有讀取到--user的值,就是說--user沒有配置,那么會在后面的if結構中設置SET_USER為0
# 這樣在后面的判斷結構中,SET_USER的值 0代表沒有配置--user的值,1代表已經配置
SET_USER=2# 解析配置文件中的參數,使用--loose-verbose來過濾[mysqld]和[server]組中的內容
parse_arguments `$print_defaults $defaults--loose-verbose mysqld server`if test $SET_USER -eq 2
thenSET_USER=0
fi# 又對[safe_mysqld]和[mysqld_safe]組中的內容進行了過濾讀取
# 在我的配置文件中已經沒有這兩個組了,估計是為兼容舊版本的需要
parse_arguments `$print_defaults $defaults--loose-verbose mysqld_safe safe_mysqld`
# 用命令行輸入選項 $@ 來覆蓋配置文件中的選項 機智
parse_arguments PICK-ARGS-FROM-ARGV "$@"#
# 下面是logging工具的使用
#
# 判斷l(xiāng)ogger工具是否可用if [ $want_syslog -eq 1]thenmy_which logger> /dev/null 2>&1
if [ $? -ne 0]thenlog_error"--syslog requested, but no 'logger' program found. Please ensure that 'logger' is in your PATH, or do not specify the --syslog option to mysqld_safe."exit1
fi
fi# 給err_log改名字。。。if [ -n "$err_log" -o $want_syslog -eq 0]then
if [ -n "$err_log"]then# 下面是為err_log添加一個.err后綴(如果現在名字沒有后綴)
# 如果不設置這個后綴,mysqld_safe和mysqld程序會將日志寫入不同的文件中
# 因為在 mysqld 程序中,它將識別帶有.的文件名為錯誤日志(腳本注釋上說的)
# 這里的expr是識別文件名中“.”前面的字符總數量(包括.),如果沒有設置后綴,返回就是0了if expr "$err_log" : '.*\.[^/]*$' > /dev/null
then:elseerr_log="$err_log".errfi
case "$err_log" in
/*) ;;
* ) err_log="$DATADIR/$err_log" ;;
esac
else
err_log=$DATADIR/`/bin/hostname`.err
fi
# 追加錯誤日志的位置選項
append_arg_to_args "--log-error=$err_log"
# 發(fā)出錯誤提示:不要使用syslog
if [ $want_syslog -eq 1 ]
then
log_error "Can't log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect."
fi
# Log to err_log file
log_notice "Logging to '$err_log'."
logging=files # 正式把logging改成files 使用錯誤日志來記錄日志
# 這個分支就是使用syslog的方法了
else
if [ -n "$syslog_tag" ]
then
# 設置各個syslog的使用標志位
syslog_tag=`echo "$syslog_tag" | sed -e 's/[^a-zA-Z0-9_-]/_/g'`
syslog_tag_mysqld_safe="${syslog_tag_mysqld_safe}-$syslog_tag"
syslog_tag_mysqld="${syslog_tag_mysqld}-$syslog_tag"
fi
log_notice "Logging to syslog."
logging=syslog
fi
# 設置--user選項
USER_OPTION=""
if test -w / -o "$USER" = "root" # 根目錄是否可寫,或者當前用戶為root
then
if test "$user" != "root" -o $SET_USER = 1
then
USER_OPTION="--user=$user"
fi
# 創(chuàng)建錯誤日志,并將日志授權給指定的用戶
if [ $want_syslog -eq 0 ]; then
touch "$err_log"
chown $user "$err_log"
fi
# 這里它還對當前用戶做了ulimit設置,包括可以打開的文件數量--open_files-limit選項
if test -n "$open_files"
then
ulimit -n $open_files
append_arg_to_args "--open-files-limit=$open_files"
fi
fi
safe_mysql_unix_port={mysql_unix_port:-${MYSQL_UNIX_PORT:-/usr/local/mysql3306/tmp/mysql.sock}}
# 確保 $safe_mysql_unix_port 目錄是存在的
mysql_unix_port_dir=`dirname $safe_mysql_unix_port`
if [ ! -d $mysql_unix_port_dir ]
then
mkdir $mysql_unix_port_dir
chown $user $mysql_unix_port_dir
chmod 755 $mysql_unix_port_dir
fi
# 如果用戶沒有制定mysqld程序的名稱,這里就默認賦值為mysqld
if test -z "$MYSQLD"
then
MYSQLD=mysqld
fi
# 下面幾段分別是對 mysqld , pid , port文件選項的檢查和設置,省略100個字
if test ! -x "$ledir/$MYSQLD"
then
log_error "The file $ledir/$MYSQLD
does not exist or is not executable. Please cd to the mysql installation
directory and restart this script from there as follows:
./bin/mysqld_safe&
Seehttp://dev.mysql.com/doc/mysql/en/mysqld-safe.htmlfor more information"
exit 1
fi
if test -z "$pid_file"
then
pid_file="$DATADIR/`/bin/hostname`.pid"
else
case "$pid_file" in
/* ) ;;
* ) pid_file="$DATADIR/$pid_file" ;;
esac
fi
append_arg_to_args "--pid-file=$pid_file"
if test -n "$mysql_unix_port"
then
append_arg_to_args "--socket=$mysql_unix_port"
fi
if test -n "$mysql_tcp_port"
then
append_arg_to_args "--port=$mysql_tcp_port"
fi
#
# 接下來是關于優(yōu)先級的設置
#
if test $niceness -eq 0
then
NOHUP_NICENESS="nohup"
else
NOHUP_NICENESS="nohup nice -$niceness"
fi
# 將當前的默認優(yōu)先級設置為0
if nohup nice > /dev/null 2>&1
then
# normal_niceness記載默認的調度優(yōu)先級
normal_niceness=`nice`
# nohup_niceness記載使用nohup執(zhí)行方式的調度優(yōu)先級
nohup_niceness=`nohup nice 2>/dev/null`
numeric_nice_values=1
# 這個for是為了檢查$normal_niceness $nohup_niceness兩個變量值的合法性
for val in $normal_niceness $nohup_niceness
do
case "$val" in
-[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \
[0-9] | [0-9][0-9] | [0-9][0-9][0-9] )
;;
* )
numeric_nice_values=0 ;;
esac
done
# 這個判斷結構很重要
# 它保證了使用nohup執(zhí)行的mysqld程序在調度優(yōu)先級上不會低于直接執(zhí)行mysqld程序的方式
if test $numeric_nice_values -eq 1
then
nice_value_diff=`expr $nohup_niceness - $normal_niceness`
if test $? -eq 0 && test $nice_value_diff -gt 0 && \
nice --$nice_value_diff echo testing > /dev/null 2>&1
then
# 進入分支說明$nohup_niceness的值比$normal_niceness大,即nohup執(zhí)行方式調度優(yōu)先級比正常執(zhí)行方式低
# 這是不希望看到的,所以下面就人為的提升了nohup的優(yōu)先級(降低niceness的值)
niceness=`expr $niceness - $nice_value_diff`
NOHUP_NICENESS="nice -$niceness nohup"
fi
fi
else
# 下面是測試nohup在當前系統(tǒng)中是否可用,不可用的話就置空NOHUP_NICENESS
if nohup echo testing > /dev/null 2>&1
then
:
else
NOHUP_NICENESS=""
fi
fi
# 指定內核文件大小
if test -n "$core_file_size"
then
ulimit -c $core_file_size
fi
#
# 如果已經存在一個pid文件,則檢查是否有已經啟動的mysqld_safe進程
if test -f "$pid_file"
then
PID=`cat "$pid_file"`
if /bin/kill -0 $PID > /dev/null 2> /dev/null
then
if /bin/ps wwwp $PID | grep -v " grep" | grep -v mysqld_safe | grep -- "$MYSQLD" > /dev/null
then
log_error "A mysqld process already exists"
exit 1
fi
fi
# 下面是處理辦法:刪除舊的pid文件并報錯
rm -f "$pid_file"
if test -f "$pid_file"
then
log_error "Fatal error: Can't remove the pid file:
$pid_file
Please remove it manually and start $0 again;
mysqld daemon not started"
exit 1
fi
fi
#
# 下面便是拼接執(zhí)行語句運行了。
#
cmd="$NOHUP_NICENESS"
# 檢查一下命令 并進行轉義操作
for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \
"--datadir=$DATADIR" "$USER_OPTION"
do
cmd="$cmd "`shell_quote_string "$i"`
done
cmd="$cmd $args"
# Avoid 'nohup: ignoring input' warning
test -n "$NOHUP_NICENESS" && cmd="$cmd < /dev/null"
log_notice "Starting $MYSQLD daemon with databases from $DATADIR"
# 后臺循環(huán) 執(zhí)行mysqld
while true
do
rm -f $safe_mysql_unix_port "$pid_file" # 保險起見,又刪除了一次pid文件
# 調用eval_log_error函數,傳入$cmd參數的值,最后使用eval命令執(zhí)行了啟動mysqld
eval_log_error "$cmd"
if test ! -f "$pid_file" # 沒有成功創(chuàng)建pid文件,則退出分支
then
break
fi
# mysqld_safe已經啟動的處理方法,保證只有一個mysqld_safe程序啟動
if true && test $KILL_MYSQLD -eq 1
then
# 統(tǒng)計啟動的mysqld進程的數目
numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"`
log_notice "Number of processes running now: $numofproces"
I=1
while test "$I" -le "$numofproces"
do
# 這個PROC的數據即是ps mysqld_safe程序的輸出 第一個數字即為進程ID
PROC=`ps xaww | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'`
# 使用T來獲取進程ID
for T in $PROC
do
break
done
# kill掉該個mysqld_safe程序
if kill -9 $T
then
log_error "$MYSQLD process hanging, pid $T - killed"
else
break
fi
# 每干掉一個mysqld_safe就把I加一,這樣沒有多余的mysqld_safe時就可以跳出循環(huán)了
I=`expr $I + 1`
done
fi
log_notice "mysqld restarted"
done
# 完結撒花
log_notice "mysqld from pid file $pid_file ended"
總結
以上是生活随笔為你收集整理的mysql脚本解读_一篇很好的关于mysqld_safe脚本源码解读的文章,收藏了!!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 奔腾b30多少钱啊?
- 下一篇: pkill mysql_每天一个linu