Error[8]: Undefined offset: 4, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

概述介绍《Mysql应用mysqld_safe启动脚本源码阅读、分析》开发教程,希望对您有用。

《MysqL应用MysqLd_safe启动脚本源码阅读、分析》要点:
本文介绍了MysqL应用MysqLd_safe启动脚本源码阅读、分析,希望对您有用。如果有疑问,可以联系我们。
@H_404_5@

前几天读了下MysqLd_safe脚本,个人感觉还是收获蛮大的,其中细致的交代了MysqL数据库的启动流程,包括查找MysqL相关目录,解析配置文件以及最后如何调用MysqLd程序来启动实例等,有着不错的参考价值;与此同时,脚本中涉及了很多shell编程中的小技巧,像变量解析,sed替换转义,进程优先级的判断以及无处不在test结构等等,当作linux shell的学习素材还是非常合适的,下面是我的环境:MysqL实例@H_404_5@

数据库版本: MysqL 5.1.45
*** 作系统版本: Red Hat Enterprise linux AS release 4 (Nahant Update 3)
MysqL基目录: /usr/local/MysqL3306
配置文件目录: /usr/local/MysqL3306/etcMysqL实例@H_404_5@

数据库是安装好了的,代码如下:
MysqL实例@H_404_5@

#!/bin/sh# 一些状态变量的定义KILL_MysqLD=1;  # 试图kill多余的MysqLd_safe程序,1表示需要killMysqLD=      # MysqLd二进制可执行文件的名称niceness=0    # 进程的调度优先级标识# 下面的变量主要用于标识不使用错误日志和sysloglogging=init   # 日志记录状态,init代表初始化want_syslog=0   # 标识是否要使用syslogsyslog_tag=user='MysqL'   # --user选项值pID_file=     # pID文件的路径err_log=     # 错误日志的路径# 这两个都是定义的syslog中标志位,在后面需要写入日志到syslog中时使用syslog_tag_MysqLd=MysqLdsyslog_tag_MysqLd_safe=MysqLd_safetrap '' 1 2 3 15   # 不允许程序在终端上被人打断(包括挂起,中断,退出,系统终止的情形)umask 007       # 默认权限770,其他组用户对该程序创建的文件没有任何权限# defaults变量记载使用的配置文件的信息defaults=case "" in  --no-defaults|--defaults-file=*|--defaults-extra-file=*)   defaults=""; shift   ;;esac# usage()函数:使用--help选项时输出的使用帮助信息usage () {    cat <<EOFUsage: [+++] [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 in the 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 file as 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    exit 1}# my_which的作用相当于which,通过检索$PATH中的路径,打印出命令的全路径# 这个函数就在后面一个地方用到了,就是my_which logger,意思等同于转换logger为/usr/bin/loggermy_which (){ save_ifs="${IFS-UNSET}"   # 保存当前的内建分隔符,用于后面重置IFS IFS=:            # 使用 : 来分割PATH中的路径 ret=0 for file           # 这种写法等同于for file in &* do  for dir in $PATH  do   if [ -f "$dir/$file" ]   then    echo "$dir/$file"    continue 2       # continue 第 2 层,这里就是跳出外层循环了   fi  done ret=1 # signal an error break done# 将设置过的IFS重置回去 if [ "$save_ifs" = UNSET ] then  unset IFS else  IFS="$save_ifs" fi return $ret # Success}# 日志输出函数,这是个原型,后面被log_error和log_notice函数引用log_generic () { # priority 代表日志信息的分类,从后面的两个函数可知有:daemon.error和daemon.notice两种类别 priority=""  shift# 日志中记录的msg前缀格式: 时间 + MysqLd_safe,类似于系统日志的记录格式 msg="`date +'%y%m%d %H:%M:%s'` MysqLd_safe $*" echo "$msg" case $logging in  init) ;;                # 初始化状态时,只在命令行输出msg信息,不记录日志  file) echo "$msg" >> "$err_log" ;;   # 记录到err_log中  syslog) logger -t "$syslog_tag_MysqLd_safe" -p "$priority" "$*" ;; # 使用logger记录到系统日志中  *)   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变量区分记录日志的类型,分错误日志和系统日志syslog两种# 最后的eval命令会解析 $cmd 中的值并执行命令eval_log_error () { cmd="" 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中的代表引用前面\(\)中匹配的值shell_quote_string() { echo "" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\,g'}# 该函数用于解析配置文件中的选项,并赋值给相应的变量parse_arguments() { pick_args= if test "" = PICK-ARGS-FROM-ARGV then  pick_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"    then     MysqLD="MysqLd-$val"    else     MysqLD="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; ;; # 生效了一下时区设置   --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/nullthen # 一口气用了三个替换,分别为: # 第一步:将/usr/local/MysqL3306转换为空 # 第二步:将/share/MysqL开头的/转换为空 # 第三步:在share/MysqL开头加上./,结果即:./share/MysqL relpkgdata=`echo '/usr/local/MysqL3306/share/MysqL' | sed -e 's,^/usr/local/MysqL3306,' -e 's,^/,^,./,'`else relpkgdata='/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" then  ledir="$MY_BASEDIR_VERSION/libexec" else  ledir="$MY_BASEDIR_VERSION/bin" fi# 这里对errmsg.sys文件进行了判断,个人认为这是为了确认当前目录为一个MysqL安装基目录elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/MysqLd"then MY_BASEDIR_VERSION="$MY_PWD" ledir="$MY_PWD/bin"elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/MysqLd"then MY_BASEDIR_VERSION="$MY_PWD" ledir="$MY_PWD/libexec"else MY_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 files in the 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 | grep my.cnf查看if test -d $MY_BASEDIR_VERSION/data/MysqLthen DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then  defaults="--defaults-extra-file=$DATADIR/my.cnf" fi# 接下来找到数据文件的目录elif test -d $MY_BASEDIR_VERSION/var/MysqLthen DATADIR=$MY_BASEDIR_VERSION/var# 找不到就用编译时指定的默认值else DATADIR=/usr/local/MysqL3306/varfi# 对存在两个配置文件情况进行冲突处理if test -z "$MysqL_HOME"then  if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf" then  # 优先考虑 $MY_BASEDIR_VERSION/my.cnf 文件  log_error "WARNING: Found two instances of my.cnf -$MY_BASEDIR_VERSION/my.cnf and$DATADIR/my.cnfIGnorING $DATADIR/my.cnf"  MysqL_HOME=$MY_BASEDIR_VERSION elif test -r "$DATADIR/my.cnf" then  log_error "WARNING: Found $DATADIR/my.cnfThe data directory is a deprecated location for my.cnf,please move it to$MY_BASEDIR_VERSION/my.cnf"  MysqL_HOME=$DATADIR else  MysqL_HOME=$MY_BASEDIR_VERSION fifiexport MysqL_HOME## 下面是使用bin/my_print_defaults读取my.cnf文件中的配置信息([MysqLd] and [MysqLd_safe])# 并且和命令行中传入的参数进行合并# 先是找到my_print_defaults执行文件 又是各种路径判断if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults"then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults"elif test -x ./bin/my_print_defaultsthen print_defaults="./bin/my_print_defaults"elif test -x /usr/local/MysqL3306/bin/my_print_defaultsthen print_defaults="/usr/local/MysqL3306/bin/my_print_defaults"elif test -x /usr/local/MysqL3306/bin/MysqL_print_defaultsthen print_defaults="/usr/local/MysqL3306/bin/MysqL_print_defaults"else print_defaults="my_print_defaults"fi# 这个函数可以将一个指定的参数附加到$arg中(在此同时执行了转义 *** 作)append_arg_to_args () { args="$args "`shell_quote_string ""`}args=# 这里SET_USER=2是针对下面一条parse_arguments来说的# 因为如果在紧接着的parse_arugments函数中设置了--user的值,那么SET_USER就会变为1,表示--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 2then SET_USER=0fi# 又对[safe_MysqLd]和[MysqLd_safe]组中的内容进行了过滤读取# 在我的配置文件中已经没有这两个组了,估计是为兼容旧版本的需要parse_arguments `$print_defaults $defaults --loose-verbose MysqLd_safe safe_MysqLd`# 用命令行输入选项 $@ 来覆盖配置文件中的选项 机智parse_arguments PICK-ARGS-FROM-ARGV "$@"## 下面是logging工具的使用## 判断logger工具是否可用if [ $want_syslog -eq 1 ]then my_which logger > /dev/null 2>&1 if [ $? -ne 0 ] then  log_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."  exit 1 fifi# 给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    :  else   err_log="$err_log".err  fi  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" # 发出错误提示:不要使用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=syslogfi# 设置--user选项 USER_OPTION=""if test -w / -o "$USER" = "root" # 根目录是否可写,或者当前用户为rootthen if test "$user" != "root" -o $SET_USER = 1 then  USER_OPTION="--user=$user" fi # 创建错误日志,并将日志授权给指定的用户 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" fifisafe_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_dirfi# 如果用户没有制定MysqLd程序的名称,这里就默认赋值为MysqLdif test -z "$MysqLD"then MysqLD=MysqLdfi# 下面几段分别是对 MysqLd,pID,port文件选项的检查和设置,省略100个字if test ! -x "$ledir/$MysqLD"then log_error "The file $ledir/$MysqLDdoes not exist or is not executable. Please cd to the MysqL installationdirectory and restart this script from there as follows:./bin/MysqLd_safe&See http://dev.MysqL.com/doc/MysqL/en/MysqLd-safe.HTML for more information" exit 1fiif test -z "$pID_file"then pID_file="$DATADIR/`/bin/hostname`.pID"else case "$pID_file" in  /* ) ;;  * ) pID_file="$DATADIR/$pID_file" ;; esacfiappend_arg_to_args "--pID-file=$pID_file"if test -n "$MysqL_unix_port"then append_arg_to_args "--socket=$MysqL_unix_port"fiif test -n "$MysqL_tcp_port"then append_arg_to_args "--port=$MysqL_tcp_port"fi## 接下来是关于优先级的设置#if test $niceness -eq 0then NOHUP_NICEnesS="nohup"else NOHUP_NICEnesS="nohup nice -$niceness"fi# 将当前的默认优先级设置为0if nohup nice > /dev/null 2>&1then  # normal_niceness记载默认的调度优先级  normal_niceness=`nice`  # nohup_niceness记载使用nohup执行方式的调度优先级  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执行的MysqLd程序在调度优先级上不会低于直接执行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执行方式调度优先级比正常执行方式低      # 这是不希望看到的,所以下面就人为的提升了nohup的优先级(降低niceness的值)      niceness=`expr $niceness - $nice_value_diff`      NOHUP_NICEnesS="nice -$niceness nohup"    fi  fielse  # 下面是测试nohup在当前系统中是否可用,不可用的话就置空NOHUP_NICEnesS  if nohup echo testing > /dev/null 2>&1  then    :  else    NOHUP_NICEnesS=""  fifi# 指定内核文件大小if test -n "$core_file_size"then ulimit -c $core_file_sizefi## 如果已经存在一个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_filePlease remove it manually and start [+++] again;MysqLd daemon not started"  exit 1 fifi## 下面便是拼接执行语句运行了.#cmd="$NOHUP_NICEnesS"# 检查一下命令 并进行转义 *** 作for i in "$ledir/$MysqLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "$USER_OPTION"do cmd="$cmd "`shell_quote_string "$i"`donecmd="$cmd $args"# AvoID 'nohup: ignoring input' warningtest -n "$NOHUP_NICEnesS" && cmd="$cmd < /dev/null"log_notice "Starting $MysqLD daemon with databases from $DATADIR"# 后台循环 执行MysqLdwhile truedo rm -f $safe_MysqL_unix_port "$pID_file" # 保险起见,又删除了一次pID文件 # 调用eval_log_error函数,传入$cmd参数的值,最后使用eval命令执行了启动MysqLd eval_log_error "$cmd" if test ! -f "$pID_file"  # 没有成功创建pID文件,则退出分支 then  break fi # MysqLd_safe已经启动的处理方法,保证只有一个MysqLd_safe程序启动 if true && test $KILL_MysqLD -eq 1 then  # 统计启动的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时就可以跳出循环了   I=`expr $I + 1`  done fi log_notice "MysqLd restarted"done# 完结撒花log_notice "MysqLd from pID file $pID_file ended"

欢迎参与《MysqL应用MysqLd_safe启动脚本源码阅读、分析》讨论,分享您的想法,内存溢出PHP学院为您提供专业教程。@H_404_5@ 总结

以上是内存溢出为你收集整理的Mysql应用mysqld_safe启动脚本源码阅读、分析全部内容,希望文章能够帮你解决Mysql应用mysqld_safe启动脚本源码阅读、分析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Error[8]: Undefined offset: 5, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

概述介绍《Mysql应用mysqld_safe启动脚本源码阅读、分析》开发教程,希望对您有用。

《MysqL应用MysqLd_safe启动脚本源码阅读、分析》要点:
本文介绍了MysqL应用MysqLd_safe启动脚本源码阅读、分析,希望对您有用。如果有疑问,可以联系我们。
@H_404_5@

前几天读了下MysqLd_safe脚本,个人感觉还是收获蛮大的,其中细致的交代了MysqL数据库的启动流程,包括查找MysqL相关目录,解析配置文件以及最后如何调用MysqLd程序来启动实例等,有着不错的参考价值;与此同时,脚本中涉及了很多shell编程中的小技巧,像变量解析,sed替换转义,进程优先级的判断以及无处不在test结构等等,当作linux shell的学习素材还是非常合适的,下面是我的环境:MysqL实例@H_404_5@

数据库版本: MysqL 5.1.45
*** 作系统版本: Red Hat Enterprise linux AS release 4 (Nahant Update 3)
MysqL基目录: /usr/local/MysqL3306
配置文件目录: /usr/local/MysqL3306/etcMysqL实例@H_404_5@

数据库是安装好了的,代码如下:
MysqL实例@H_404_5@

#!/bin/sh# 一些状态变量的定义KILL_MysqLD=1;  # 试图kill多余的MysqLd_safe程序,1表示需要killMysqLD=      # MysqLd二进制可执行文件的名称niceness=0    # 进程的调度优先级标识# 下面的变量主要用于标识不使用错误日志和sysloglogging=init   # 日志记录状态,init代表初始化want_syslog=0   # 标识是否要使用syslogsyslog_tag=user='MysqL'   # --user选项值pID_file=     # pID文件的路径err_log=     # 错误日志的路径# 这两个都是定义的syslog中标志位,在后面需要写入日志到syslog中时使用syslog_tag_MysqLd=MysqLdsyslog_tag_MysqLd_safe=MysqLd_safetrap '' 1 2 3 15   # 不允许程序在终端上被人打断(包括挂起,中断,退出,系统终止的情形)umask 007       # 默认权限770,其他组用户对该程序创建的文件没有任何权限# defaults变量记载使用的配置文件的信息defaults=case "" in  --no-defaults|--defaults-file=*|--defaults-extra-file=*)   defaults=""; shift   ;;esac# usage()函数:使用--help选项时输出的使用帮助信息usage () {    cat <<EOFUsage:  [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 in the 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 file as 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    exit 1}# my_which的作用相当于which,通过检索$PATH中的路径,打印出命令的全路径# 这个函数就在后面一个地方用到了,就是my_which logger,意思等同于转换logger为/usr/bin/loggermy_which (){ save_ifs="${IFS-UNSET}"   # 保存当前的内建分隔符,用于后面重置IFS IFS=:            # 使用 : 来分割PATH中的路径 ret=0 for file           # 这种写法等同于for file in &* do  for dir in $PATH  do   if [ -f "$dir/$file" ]   then    echo "$dir/$file"    continue 2       # continue 第 2 层,这里就是跳出外层循环了   fi  done ret=1 # signal an error break done# 将设置过的IFS重置回去 if [ "$save_ifs" = UNSET ] then  unset IFS else  IFS="$save_ifs" fi return $ret # Success}# 日志输出函数,这是个原型,后面被log_error和log_notice函数引用log_generic () { # priority 代表日志信息的分类,从后面的两个函数可知有:daemon.error和daemon.notice两种类别 priority=""  shift# 日志中记录的msg前缀格式: 时间 + MysqLd_safe,类似于系统日志的记录格式 msg="`date +'%y%m%d %H:%M:%s'` MysqLd_safe $*" echo "$msg" case $logging in  init) ;;                # 初始化状态时,只在命令行输出msg信息,不记录日志  file) echo "$msg" >> "$err_log" ;;   # 记录到err_log中  syslog) logger -t "$syslog_tag_MysqLd_safe" -p "$priority" "$*" ;; # 使用logger记录到系统日志中  *)   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变量区分记录日志的类型,分错误日志和系统日志syslog两种# 最后的eval命令会解析 $cmd 中的值并执行命令eval_log_error () { cmd="" 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中的代表引用前面\(\)中匹配的值shell_quote_string() { echo "" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\,g'}# 该函数用于解析配置文件中的选项,并赋值给相应的变量parse_arguments() { pick_args= if test "" = PICK-ARGS-FROM-ARGV then  pick_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"    then     MysqLD="MysqLd-$val"    else     MysqLD="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; ;; # 生效了一下时区设置   --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/nullthen # 一口气用了三个替换,分别为: # 第一步:将/usr/local/MysqL3306转换为空 # 第二步:将/share/MysqL开头的/转换为空 # 第三步:在share/MysqL开头加上./,结果即:./share/MysqL relpkgdata=`echo '/usr/local/MysqL3306/share/MysqL' | sed -e 's,^/usr/local/MysqL3306,' -e 's,^/,^,./,'`else relpkgdata='/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" then  ledir="$MY_BASEDIR_VERSION/libexec" else  ledir="$MY_BASEDIR_VERSION/bin" fi# 这里对errmsg.sys文件进行了判断,个人认为这是为了确认当前目录为一个MysqL安装基目录elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/MysqLd"then MY_BASEDIR_VERSION="$MY_PWD" ledir="$MY_PWD/bin"elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/MysqLd"then MY_BASEDIR_VERSION="$MY_PWD" ledir="$MY_PWD/libexec"else MY_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 files in the 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 | grep my.cnf查看if test -d $MY_BASEDIR_VERSION/data/MysqLthen DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then  defaults="--defaults-extra-file=$DATADIR/my.cnf" fi# 接下来找到数据文件的目录elif test -d $MY_BASEDIR_VERSION/var/MysqLthen DATADIR=$MY_BASEDIR_VERSION/var# 找不到就用编译时指定的默认值else DATADIR=/usr/local/MysqL3306/varfi# 对存在两个配置文件情况进行冲突处理if test -z "$MysqL_HOME"then  if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf" then  # 优先考虑 $MY_BASEDIR_VERSION/my.cnf 文件  log_error "WARNING: Found two instances of my.cnf -$MY_BASEDIR_VERSION/my.cnf and$DATADIR/my.cnfIGnorING $DATADIR/my.cnf"  MysqL_HOME=$MY_BASEDIR_VERSION elif test -r "$DATADIR/my.cnf" then  log_error "WARNING: Found $DATADIR/my.cnfThe data directory is a deprecated location for my.cnf,please move it to$MY_BASEDIR_VERSION/my.cnf"  MysqL_HOME=$DATADIR else  MysqL_HOME=$MY_BASEDIR_VERSION fifiexport MysqL_HOME## 下面是使用bin/my_print_defaults读取my.cnf文件中的配置信息([MysqLd] and [MysqLd_safe])# 并且和命令行中传入的参数进行合并# 先是找到my_print_defaults执行文件 又是各种路径判断if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults"then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults"elif test -x ./bin/my_print_defaultsthen print_defaults="./bin/my_print_defaults"elif test -x /usr/local/MysqL3306/bin/my_print_defaultsthen print_defaults="/usr/local/MysqL3306/bin/my_print_defaults"elif test -x /usr/local/MysqL3306/bin/MysqL_print_defaultsthen print_defaults="/usr/local/MysqL3306/bin/MysqL_print_defaults"else print_defaults="my_print_defaults"fi# 这个函数可以将一个指定的参数附加到$arg中(在此同时执行了转义 *** 作)append_arg_to_args () { args="$args "`shell_quote_string ""`}args=# 这里SET_USER=2是针对下面一条parse_arguments来说的# 因为如果在紧接着的parse_arugments函数中设置了--user的值,那么SET_USER就会变为1,表示--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 2then SET_USER=0fi# 又对[safe_MysqLd]和[MysqLd_safe]组中的内容进行了过滤读取# 在我的配置文件中已经没有这两个组了,估计是为兼容旧版本的需要parse_arguments `$print_defaults $defaults --loose-verbose MysqLd_safe safe_MysqLd`# 用命令行输入选项 $@ 来覆盖配置文件中的选项 机智parse_arguments PICK-ARGS-FROM-ARGV "$@"## 下面是logging工具的使用## 判断logger工具是否可用if [ $want_syslog -eq 1 ]then my_which logger > /dev/null 2>&1 if [ $? -ne 0 ] then  log_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."  exit 1 fifi# 给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    :  else   err_log="$err_log".err  fi  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" # 发出错误提示:不要使用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=syslogfi# 设置--user选项 USER_OPTION=""if test -w / -o "$USER" = "root" # 根目录是否可写,或者当前用户为rootthen if test "$user" != "root" -o $SET_USER = 1 then  USER_OPTION="--user=$user" fi # 创建错误日志,并将日志授权给指定的用户 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" fifisafe_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_dirfi# 如果用户没有制定MysqLd程序的名称,这里就默认赋值为MysqLdif test -z "$MysqLD"then MysqLD=MysqLdfi# 下面几段分别是对 MysqLd,pID,port文件选项的检查和设置,省略100个字if test ! -x "$ledir/$MysqLD"then log_error "The file $ledir/$MysqLDdoes not exist or is not executable. Please cd to the MysqL installationdirectory and restart this script from there as follows:./bin/MysqLd_safe&See http://dev.MysqL.com/doc/MysqL/en/MysqLd-safe.HTML for more information" exit 1fiif test -z "$pID_file"then pID_file="$DATADIR/`/bin/hostname`.pID"else case "$pID_file" in  /* ) ;;  * ) pID_file="$DATADIR/$pID_file" ;; esacfiappend_arg_to_args "--pID-file=$pID_file"if test -n "$MysqL_unix_port"then append_arg_to_args "--socket=$MysqL_unix_port"fiif test -n "$MysqL_tcp_port"then append_arg_to_args "--port=$MysqL_tcp_port"fi## 接下来是关于优先级的设置#if test $niceness -eq 0then NOHUP_NICEnesS="nohup"else NOHUP_NICEnesS="nohup nice -$niceness"fi# 将当前的默认优先级设置为0if nohup nice > /dev/null 2>&1then  # normal_niceness记载默认的调度优先级  normal_niceness=`nice`  # nohup_niceness记载使用nohup执行方式的调度优先级  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执行的MysqLd程序在调度优先级上不会低于直接执行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执行方式调度优先级比正常执行方式低      # 这是不希望看到的,所以下面就人为的提升了nohup的优先级(降低niceness的值)      niceness=`expr $niceness - $nice_value_diff`      NOHUP_NICEnesS="nice -$niceness nohup"    fi  fielse  # 下面是测试nohup在当前系统中是否可用,不可用的话就置空NOHUP_NICEnesS  if nohup echo testing > /dev/null 2>&1  then    :  else    NOHUP_NICEnesS=""  fifi# 指定内核文件大小if test -n "$core_file_size"then ulimit -c $core_file_sizefi## 如果已经存在一个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_filePlease remove it manually and start [+++] again;MysqLd daemon not started"  exit 1 fifi## 下面便是拼接执行语句运行了.#cmd="$NOHUP_NICEnesS"# 检查一下命令 并进行转义 *** 作for i in "$ledir/$MysqLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "$USER_OPTION"do cmd="$cmd "`shell_quote_string "$i"`donecmd="$cmd $args"# AvoID 'nohup: ignoring input' warningtest -n "$NOHUP_NICEnesS" && cmd="$cmd < /dev/null"log_notice "Starting $MysqLD daemon with databases from $DATADIR"# 后台循环 执行MysqLdwhile truedo rm -f $safe_MysqL_unix_port "$pID_file" # 保险起见,又删除了一次pID文件 # 调用eval_log_error函数,传入$cmd参数的值,最后使用eval命令执行了启动MysqLd eval_log_error "$cmd" if test ! -f "$pID_file"  # 没有成功创建pID文件,则退出分支 then  break fi # MysqLd_safe已经启动的处理方法,保证只有一个MysqLd_safe程序启动 if true && test $KILL_MysqLD -eq 1 then  # 统计启动的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时就可以跳出循环了   I=`expr $I + 1`  done fi log_notice "MysqLd restarted"done# 完结撒花log_notice "MysqLd from pID file $pID_file ended"

欢迎参与《MysqL应用MysqLd_safe启动脚本源码阅读、分析》讨论,分享您的想法,内存溢出PHP学院为您提供专业教程。@H_404_5@ 总结

以上是内存溢出为你收集整理的Mysql应用mysqld_safe启动脚本源码阅读、分析全部内容,希望文章能够帮你解决Mysql应用mysqld_safe启动脚本源码阅读、分析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Mysql应用mysqld_safe启动脚本源码阅读、分析_mysql_内存溢出

Mysql应用mysqld_safe启动脚本源码阅读、分析

Mysql应用mysqld_safe启动脚本源码阅读、分析,第1张

概述介绍《Mysql应用mysqld_safe启动脚本源码阅读、分析》开发教程,希望对您有用。

《MysqL应用MysqLd_safe启动脚本源码阅读、分析》要点:
本文介绍了MysqL应用MysqLd_safe启动脚本源码阅读、分析,希望对您有用。如果有疑问,可以联系我们。
@H_404_5@

前几天读了下MysqLd_safe脚本,个人感觉还是收获蛮大的,其中细致的交代了MysqL数据库的启动流程,包括查找MysqL相关目录,解析配置文件以及最后如何调用MysqLd程序来启动实例等,有着不错的参考价值;与此同时,脚本中涉及了很多shell编程中的小技巧,像变量解析,sed替换转义,进程优先级的判断以及无处不在test结构等等,当作linux shell的学习素材还是非常合适的,下面是我的环境:MysqL实例@H_404_5@

数据库版本: MysqL 5.1.45
*** 作系统版本: Red Hat Enterprise linux AS release 4 (Nahant Update 3)
MysqL基目录: /usr/local/MysqL3306
配置文件目录: /usr/local/MysqL3306/etcMysqL实例@H_404_5@

数据库是安装好了的,代码如下:
MysqL实例@H_404_5@

#!/bin/sh# 一些状态变量的定义KILL_MysqLD=1;  # 试图kill多余的MysqLd_safe程序,1表示需要killMysqLD=      # MysqLd二进制可执行文件的名称niceness=0    # 进程的调度优先级标识# 下面的变量主要用于标识不使用错误日志和sysloglogging=init   # 日志记录状态,init代表初始化want_syslog=0   # 标识是否要使用syslogsyslog_tag=user='MysqL'   # --user选项值pID_file=     # pID文件的路径err_log=     # 错误日志的路径# 这两个都是定义的syslog中标志位,在后面需要写入日志到syslog中时使用syslog_tag_MysqLd=MysqLdsyslog_tag_MysqLd_safe=MysqLd_safetrap '' 1 2 3 15   # 不允许程序在终端上被人打断(包括挂起,中断,退出,系统终止的情形)umask 007       # 默认权限770,其他组用户对该程序创建的文件没有任何权限# defaults变量记载使用的配置文件的信息defaults=case "" in  --no-defaults|--defaults-file=*|--defaults-extra-file=*)   defaults=""; shift   ;;esac# usage()函数:使用--help选项时输出的使用帮助信息usage () {    cat <<EOFUsage:  [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 in the 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 file as 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    exit 1}# my_which的作用相当于which,通过检索$PATH中的路径,打印出命令的全路径# 这个函数就在后面一个地方用到了,就是my_which logger,意思等同于转换logger为/usr/bin/loggermy_which (){ save_ifs="${IFS-UNSET}"   # 保存当前的内建分隔符,用于后面重置IFS IFS=:            # 使用 : 来分割PATH中的路径 ret=0 for file           # 这种写法等同于for file in &* do  for dir in $PATH  do   if [ -f "$dir/$file" ]   then    echo "$dir/$file"    continue 2       # continue 第 2 层,这里就是跳出外层循环了   fi  done ret=1 # signal an error break done# 将设置过的IFS重置回去 if [ "$save_ifs" = UNSET ] then  unset IFS else  IFS="$save_ifs" fi return $ret # Success}# 日志输出函数,这是个原型,后面被log_error和log_notice函数引用log_generic () { # priority 代表日志信息的分类,从后面的两个函数可知有:daemon.error和daemon.notice两种类别 priority=""  shift# 日志中记录的msg前缀格式: 时间 + MysqLd_safe,类似于系统日志的记录格式 msg="`date +'%y%m%d %H:%M:%s'` MysqLd_safe $*" echo "$msg" case $logging in  init) ;;                # 初始化状态时,只在命令行输出msg信息,不记录日志  file) echo "$msg" >> "$err_log" ;;   # 记录到err_log中  syslog) logger -t "$syslog_tag_MysqLd_safe" -p "$priority" "$*" ;; # 使用logger记录到系统日志中  *)   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变量区分记录日志的类型,分错误日志和系统日志syslog两种# 最后的eval命令会解析 $cmd 中的值并执行命令eval_log_error () { cmd="" 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中的代表引用前面\(\)中匹配的值shell_quote_string() { echo "" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\,g'}# 该函数用于解析配置文件中的选项,并赋值给相应的变量parse_arguments() { pick_args= if test "" = PICK-ARGS-FROM-ARGV then  pick_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"    then     MysqLD="MysqLd-$val"    else     MysqLD="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; ;; # 生效了一下时区设置   --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/nullthen # 一口气用了三个替换,分别为: # 第一步:将/usr/local/MysqL3306转换为空 # 第二步:将/share/MysqL开头的/转换为空 # 第三步:在share/MysqL开头加上./,结果即:./share/MysqL relpkgdata=`echo '/usr/local/MysqL3306/share/MysqL' | sed -e 's,^/usr/local/MysqL3306,' -e 's,^/,^,./,'`else relpkgdata='/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" then  ledir="$MY_BASEDIR_VERSION/libexec" else  ledir="$MY_BASEDIR_VERSION/bin" fi# 这里对errmsg.sys文件进行了判断,个人认为这是为了确认当前目录为一个MysqL安装基目录elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/MysqLd"then MY_BASEDIR_VERSION="$MY_PWD" ledir="$MY_PWD/bin"elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/MysqLd"then MY_BASEDIR_VERSION="$MY_PWD" ledir="$MY_PWD/libexec"else MY_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 files in the 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 | grep my.cnf查看if test -d $MY_BASEDIR_VERSION/data/MysqLthen DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then  defaults="--defaults-extra-file=$DATADIR/my.cnf" fi# 接下来找到数据文件的目录elif test -d $MY_BASEDIR_VERSION/var/MysqLthen DATADIR=$MY_BASEDIR_VERSION/var# 找不到就用编译时指定的默认值else DATADIR=/usr/local/MysqL3306/varfi# 对存在两个配置文件情况进行冲突处理if test -z "$MysqL_HOME"then  if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf" then  # 优先考虑 $MY_BASEDIR_VERSION/my.cnf 文件  log_error "WARNING: Found two instances of my.cnf -$MY_BASEDIR_VERSION/my.cnf and$DATADIR/my.cnfIGnorING $DATADIR/my.cnf"  MysqL_HOME=$MY_BASEDIR_VERSION elif test -r "$DATADIR/my.cnf" then  log_error "WARNING: Found $DATADIR/my.cnfThe data directory is a deprecated location for my.cnf,please move it to$MY_BASEDIR_VERSION/my.cnf"  MysqL_HOME=$DATADIR else  MysqL_HOME=$MY_BASEDIR_VERSION fifiexport MysqL_HOME## 下面是使用bin/my_print_defaults读取my.cnf文件中的配置信息([MysqLd] and [MysqLd_safe])# 并且和命令行中传入的参数进行合并# 先是找到my_print_defaults执行文件 又是各种路径判断if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults"then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults"elif test -x ./bin/my_print_defaultsthen print_defaults="./bin/my_print_defaults"elif test -x /usr/local/MysqL3306/bin/my_print_defaultsthen print_defaults="/usr/local/MysqL3306/bin/my_print_defaults"elif test -x /usr/local/MysqL3306/bin/MysqL_print_defaultsthen print_defaults="/usr/local/MysqL3306/bin/MysqL_print_defaults"else print_defaults="my_print_defaults"fi# 这个函数可以将一个指定的参数附加到$arg中(在此同时执行了转义 *** 作)append_arg_to_args () { args="$args "`shell_quote_string ""`}args=# 这里SET_USER=2是针对下面一条parse_arguments来说的# 因为如果在紧接着的parse_arugments函数中设置了--user的值,那么SET_USER就会变为1,表示--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 2then SET_USER=0fi# 又对[safe_MysqLd]和[MysqLd_safe]组中的内容进行了过滤读取# 在我的配置文件中已经没有这两个组了,估计是为兼容旧版本的需要parse_arguments `$print_defaults $defaults --loose-verbose MysqLd_safe safe_MysqLd`# 用命令行输入选项 $@ 来覆盖配置文件中的选项 机智parse_arguments PICK-ARGS-FROM-ARGV "$@"## 下面是logging工具的使用## 判断logger工具是否可用if [ $want_syslog -eq 1 ]then my_which logger > /dev/null 2>&1 if [ $? -ne 0 ] then  log_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."  exit 1 fifi# 给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    :  else   err_log="$err_log".err  fi  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" # 发出错误提示:不要使用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=syslogfi# 设置--user选项 USER_OPTION=""if test -w / -o "$USER" = "root" # 根目录是否可写,或者当前用户为rootthen if test "$user" != "root" -o $SET_USER = 1 then  USER_OPTION="--user=$user" fi # 创建错误日志,并将日志授权给指定的用户 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" fifisafe_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_dirfi# 如果用户没有制定MysqLd程序的名称,这里就默认赋值为MysqLdif test -z "$MysqLD"then MysqLD=MysqLdfi# 下面几段分别是对 MysqLd,pID,port文件选项的检查和设置,省略100个字if test ! -x "$ledir/$MysqLD"then log_error "The file $ledir/$MysqLDdoes not exist or is not executable. Please cd to the MysqL installationdirectory and restart this script from there as follows:./bin/MysqLd_safe&See http://dev.MysqL.com/doc/MysqL/en/MysqLd-safe.HTML for more information" exit 1fiif test -z "$pID_file"then pID_file="$DATADIR/`/bin/hostname`.pID"else case "$pID_file" in  /* ) ;;  * ) pID_file="$DATADIR/$pID_file" ;; esacfiappend_arg_to_args "--pID-file=$pID_file"if test -n "$MysqL_unix_port"then append_arg_to_args "--socket=$MysqL_unix_port"fiif test -n "$MysqL_tcp_port"then append_arg_to_args "--port=$MysqL_tcp_port"fi## 接下来是关于优先级的设置#if test $niceness -eq 0then NOHUP_NICEnesS="nohup"else NOHUP_NICEnesS="nohup nice -$niceness"fi# 将当前的默认优先级设置为0if nohup nice > /dev/null 2>&1then  # normal_niceness记载默认的调度优先级  normal_niceness=`nice`  # nohup_niceness记载使用nohup执行方式的调度优先级  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执行的MysqLd程序在调度优先级上不会低于直接执行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执行方式调度优先级比正常执行方式低      # 这是不希望看到的,所以下面就人为的提升了nohup的优先级(降低niceness的值)      niceness=`expr $niceness - $nice_value_diff`      NOHUP_NICEnesS="nice -$niceness nohup"    fi  fielse  # 下面是测试nohup在当前系统中是否可用,不可用的话就置空NOHUP_NICEnesS  if nohup echo testing > /dev/null 2>&1  then    :  else    NOHUP_NICEnesS=""  fifi# 指定内核文件大小if test -n "$core_file_size"then ulimit -c $core_file_sizefi## 如果已经存在一个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_filePlease remove it manually and start  again;MysqLd daemon not started"  exit 1 fifi## 下面便是拼接执行语句运行了.#cmd="$NOHUP_NICEnesS"# 检查一下命令 并进行转义 *** 作for i in "$ledir/$MysqLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "$USER_OPTION"do cmd="$cmd "`shell_quote_string "$i"`donecmd="$cmd $args"# AvoID 'nohup: ignoring input' warningtest -n "$NOHUP_NICEnesS" && cmd="$cmd < /dev/null"log_notice "Starting $MysqLD daemon with databases from $DATADIR"# 后台循环 执行MysqLdwhile truedo rm -f $safe_MysqL_unix_port "$pID_file" # 保险起见,又删除了一次pID文件 # 调用eval_log_error函数,传入$cmd参数的值,最后使用eval命令执行了启动MysqLd eval_log_error "$cmd" if test ! -f "$pID_file"  # 没有成功创建pID文件,则退出分支 then  break fi # MysqLd_safe已经启动的处理方法,保证只有一个MysqLd_safe程序启动 if true && test $KILL_MysqLD -eq 1 then  # 统计启动的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时就可以跳出循环了   I=`expr $I + 1`  done fi log_notice "MysqLd restarted"done# 完结撒花log_notice "MysqLd from pID file $pID_file ended"

欢迎参与《MysqL应用MysqLd_safe启动脚本源码阅读、分析》讨论,分享您的想法,内存溢出PHP学院为您提供专业教程。@H_404_5@ 总结

以上是内存溢出为你收集整理的Mysql应用mysqld_safe启动脚本源码阅读、分析全部内容,希望文章能够帮你解决Mysql应用mysqld_safe启动脚本源码阅读、分析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1154959.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-01
下一篇 2022-06-01

发表评论

登录后才能评论

评论列表(0条)

保存