Mysqld_safe start script source code reading and analysis _ MySQL

Source: Internet
Author: User
Tags syslog
Mysqld_safe start script source code reading and analysis I read the mysqld_safe script a few days ago. I personally think it is quite rewarding. I carefully explained the MySQL database startup process, including searching MySQL-related directories, parsing the configuration file and finally calling the mysqld program to start the instance has good reference value. at the same time, the script involves a lot of tips in shell programming, such as variable parsing, sed replacement escape, process Priority judgment and ubiquitous test structure are very suitable as the learning material of Linux shell. The following is my environment:

Database version: MySQL 5.1.45
Operating system version: Red Hat Enterprise Linux AS release 4 (Nahant Update 3)
MySQL Base Directory:/usr/local/mysql3306
Configuration file directory:/usr/local/mysql3306/etc

The database is installed with the following code:

#! /Bin/sh # Definition of some state variables KILL_MYSQLD = 1; # try to kill redundant mysqld_safe programs, 1 indicates that killMYSQLD = # mysqld binary executable file name niceness = 0 # scheduling priority ID of the process # the following variables are mainly used to identify error logs and syslogging = init # log records status, init indicates the initialization of want_syslog = 0 # identify whether to use syslogsyslog_tag = user = 'mysql' # -- user option value pid_file = # pid file path err_log = # Error log path # The Two are defined in the syslog flag, use syslog_tag_mysqld = mysqldsyslog_tag_mysqld_safe = mysqld_safetrap ''1 2 3 15 # programs cannot be interrupted on the terminal when logs need to be written to syslog, system termination) umask 007 # default permission 770, other group users do not have any permissions on the files created by the program # The defaults variable records the information of the configuration file used. defaults = case "$1" in -- no-defaults | -- defaults-file = * | -- defaults-extra-file = *) defaults = "$1"; shift; esac # usage () function: usage () {cat <
 
  
> "$ Err_log"; # syslog recorded in err_log) logger-t "$ syslog_tag_mysqld_safe"-p "$ priority" "$ *";; # use logger to log to system logs *) echo "Internal program error (non-fatal):"/"unknown logging method '$ logging'"> & 2 ;; esac} # the following two functions reference log_error () {log_generic daemon for different types of log_generic functions. error "$ @"> & 2} log_notice () {log_generic daemon. notice "$ @"} # mysqld started by using it. the logging variable is used to identify the log type, which is divided into two types: error log and system log syslog # Final The eval command will parse the value in $ cmd and execute the command 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 "} # escape function, used in non-" a-z "," A-Z "," 09 ",'/','_', '. ',' = ','-'special characters Add "/" #"/1 in sed to reference the matching value shell_quote_string () {echo" $1 "| sed-e's, /([^ a-zA-Z0-9 /_. =-]/), // 1, G'} # This function is used to parse the options in the configuration file and assign values to the corresponding variable parse_arguments () {pick_args = if test "$1" = PICK-ARGS-FROM-ARGV then pick_args = 1 shift fi for arg do # retrieve the parameter value, for example -- port = 3306 the result is: val = 3306 note that here sed uses; to separate, equivalent to/val = 'echo "$ arg" | sed-e "s; -- [^ =] * = ;; "'case" $ arg "in # pass the parameter value to the corresponding variable -- basedir = *) MY_BASEDIR_VERSION = "$ Val"; -- datadir = *) DATADIR = "$ val"; -- pid-file = *) pid_file = "$ val"; -- user = *) user = "$ val"; SET_USER = 1; # Some values may already exist in my. the cnf configuration file is set in the [mysqld_safe] group # Some values will be overwritten by the option value specified on the command line -- log-error = *) err_log = "$ val ";; -- port = *) mysql_tcp_port = "$ val"; -- socket = *) mysql_unix_port = "$ val ";; # The following special options must be set in the [mysqld_safe] group of the configuration file # I didn't configure this group, so I couldn't use it (use the default in mysqld) -- core-file-size = *) core_file_size = "$ val"; -- led Ir = *) 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; # The time zone settings take effect- -Help) usage; # Call the usage function to output help information *) if test-n "$ pick_args" then # append_arg_to_args "$ arg" fi ;; esac done }##################################### #### The official work has started !! ######################################## # The following two sections are used to find the base directory and the directory where mysqld is located # Find the/usr/local/mysql3306/share/mysql Directory, use relpkgdata to record the relative path and absolute path # this grep should actually be used to determine whether share/mysql shows the absolute path and what the meaning of this write is. If echo '/usr/local/mysql3306/share/mysql' | grep' ^/usr/local/mysql3306'>/dev/nullthen # Three replicas are used in one breath, step 1: # Convert/usr/local/mysql3306 to null # Step 2: Convert/starting with/share/mysql to null # Step 3: add at the beginning of share/mysql. /. The result is :. /share/mysql relpkgdata = 'echo '/usr/local/mysql3306/share/mysql' | sed-e's, ^/usr/local/mysql3306 ,, '-e's, ^/,'-e's, ^ ,. /, ''else relpkgdata = '/usr/local/mysql3306/share/mysql' fi # This section is all looking for the mysqld file, respectively judging li Bexec and bin directories # use the default value 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 here. the sys file is determined. I personally think this is to confirm that the current directory is a mysql installation base directory elif test-f "$ relpkgdata"/english/errmsg. sys-a-x "$ MY_PWD/bin/mysqld" then MY_BASEDIR_VERSION = "$ MY_PWD" ledir = "$ MY_PW D/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 release = '/usr/local/mysql3306 'ledir = '/usr/local/mysql3306/libexec' fi # Find the configuration file and data file directory # Find the configuration file directory # I put it under the etc/directory, mysqld program will read # get the default read from my_print_defaults script my. the cnf sequence is as follows # 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 # or use strace-e open libexec/mysqld 2> & 1 | grep my. cnf view 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 # find the data file directory elif test-d $ MY_BASEDIR_VERSION/var/mysqlthen DATADIR = $ MY_BASEDIR_VERSION/var # use the default value else DATADIR =/ usr/local/mysql3306/varfi # There are two pairs 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 file 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 director Y 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 policiexport MYSQL_HOME # The following uses bin/my_print_defaults to read my. configuration information in the cnf File ([mysqld] and [mysqld_safe]) # Merge with the input parameters in the command line # First find the my_print_defaults execution file and determine the various paths if test-x "$ MY_BASEDIR_VERSION/bin/my_print_defaults" then print_defaults = "$ MY_BASEDIR_VERSION/ bin/my_print_defa Ults "elif test-x. /bin/my_print_defaultsthen print_defaults = ". /bin/my_print_defaults "elif test-x/usr/local/mysql3306/bin/export print_defaults ="/usr/local/mysql3306/bin/my_print_defaults "elif test-x/usr/ local/mysql3306/bin/export print_defaults = "/usr/local/mysql3306/bin/mysql_print_defaults" else print_defaults = "my_print_defaults" fi # This function can append a specified parameter to $ arg (at the same time The escape operation is executed.) append_arg_to_args () {args = "$ args" 'shell _ quote_string "$1" '} args = # Here SET_USER = 2 is for the following parse_arguments # if it is in the following parse_arugments function -- user value set, then SET_USER will change to 1, indicating -- user is configured # of course, if the value of -- user is not read, that is, -- user is not configured, SET_USER is set to 0 in the later if structure. in this case, in the later judgment structure, the value 0 of SET_USER indicates that the value of -- user is not configured, 1 indicates that SET_USER = 2 # has been configured to parse the parameters in the configuration file. use -- loose-verbose to filter the content parse_arguments '$ print_defaults $ ULTS -- in the [mysqld] and [server] groups -- Loose-verbose mysqld server 'if test $ SET_USER-eq 2 then SET_USER = 0fi # filter and read the content in the [safe_mysqld] and [mysqld_safe] groups # In My configuration file no longer have these two groups, it is estimated that parse_arguments '$ print_defaults $ defaults -- loose-verbose mysqld_safe safe_mysqld' is required to be compatible with earlier versions # overwrite option wit parse_arguments PICK-ARGS-FROM-ARGV in the configuration file with command line input $ @ @ "## use of the logging tool ## determine whether the logger tool is available 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 # Rename err_log... If [-n "$ err_log"-o $ want_syslog-eq 0] then if [-n "$ err_log"] then # add one for err_log. err suffix (if the current name does not have a suffix) # if this suffix is not set, the mysqld_safe and mysqld programs will write logs into different files # because in mysqld programs, it will recognize the suffix. the file name is the error log (as described in the script comment) # The expr here is used to identify the file name ". "Total number of characters (including .), if no suffix is set, if expr "$ err_log": 'is returned ":'. */. [^/] * $ '>/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 error log location option append_arg_to_args "-- log-error = $ err_log" # Issue error prompt: do not use 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 # change logging to files to use error logs to record logs # This branch is Using syslog, else if [-n "$ syslog_tag"] then # sets the use flag of each syslog. syslog_tag = 'echo "$ syslog_tag" | sed-e's /[ ^ a-zA-Z0-9 _-]/_/g'' labels = "$ {tags}-$ syslog_tag" syslog_tag_mysqld = "$ {syslog_tag_mysqld}-$ syslog_tag" fi log_notice "Logging to syslog. "logging = syslogfi # set -- user option USER_OPTION =" if test-w/-o "$ USER" = "root" # whether the root directory is writable, or the current user is rootthen if test "$ user "! = "Root"-o $ SET_USER = 1 then USER_OPTION = "-- user = $ user" fi # create error log, and authorize the log to the specified user if [$ want_syslog-eq 0]; then touch "$ err_log" chown $ user "$ err_log" fi # Here it also sets the ulimit for the current user, includes the number of files that can be opened -- open_files-limit options if test-n "$ open_files" then ulimit-n $ open_files append_arg_to_args "-- open-files-limit = $ open_files" limit = {mysql_unix_port: -$ {MYSQL_UNIX_PORT:-/usr/local/mysql3306/tm P/mysql. sock }}# make sure that the $ safe_mysql_unix_port directory contains 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 # if the user does not specify the name of the mysqld program, here, the default value is mysqldif test-z "$ MYSQLD" then MYSQLD = mysqldfi # The following sections check and set the options of mysqld, pid, and port files, omit 100 words 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 1 fiif test-z" $ pid_file "then pid_file =" $ DATADIR/'/bin/hostname '. pid "else case" $ pid_file "in/*); *) pid_file =" $ DATADIR/$ pid_file ";; export "-- pid-file = $ pid_file" if test-n "$ mysql_unix_port" then accept "-- socket = $ mysql_unix_port" fiif test-n "$ mysql_tcp_port" then append_arg_to_args "-- = $ mysql_tcp_port "fi # priority setting # if test $ nic Eness-eq 0 then NOHUP_NICENESS = "nohup" else NOHUP_NICENESS = "nohup nice-$ niceness" fi # set the current default priority to 0if nohup nice>/dev/null 2> & 1 then # normal_niceness records the default scheduling priority normal_niceness = 'Nice '# nohup_niceness records the scheduling priority when nohup is executed; priority = 'nohup nice 2>/dev/null 'numeric_nice_values = 1 # this for is to check the legitimacy of the values of $ normal_niceness $ nohup_niceness variables 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 # this judgment structure is very important # it ensures that the mysqld program executed with nohup is not lower than the direct execution of mysqld program in the scheduling priority 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 # enter the branch description $ nohup_niceness value ratio $ normal_niceness is large, that is to say, the scheduling priority of nohup execution mode is lower than that of normal execution mode # This is not expected, so the priority of nohup is raised manually below (the niceness value is reduced) niceness = 'expr $ niceness-$ nice_value_diff 'nohup_niceness = "nice-$ niceness nohup" fi fielse # The following describes whether nohup is available in the current system, if not, leave NOHUP_NICENESS if nohup echo testing>/dev/null 2> & 1 then: Else NOHUP_NICENESS = "" fifi # specify the kernel file size if test-n "$ core_file_size" then ulimit-c $ core_file_sizefi # if a pid file already exists, check whether any mysqld_safe process has been started 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 # The following is Solution: delete the old pid file and report the error 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 $0 again; mysqld daemon not started "exit 1 fifi ## The following is a concatenated execution statement. # Cmd = "$ NOHUP_NICENESS" # Check the command and perform the escape operation 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_my SQL _unix_port "$ pid_file" # for the sake of security, a pid file is deleted. # Call the eval_log_error function and input the value of the $ cmd parameter, finally, run the eval command to start mysqld eval_log_error "$ cmd" if test! -F "$ pid_file" # if the pid file is not successfully created, exit the branch then break fi # mysqld_safe, ensure that only one mysqld_safe program starts if true & test $ KILL_MYSQLD-eq 1 then # count the number of mysqld processes started 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 # the data of this PROC is the first number output by the ps mysqld_safe program, that is, the process ID PROC =' ps xaww | grep "$ ledir/$ MYSQLD/>" | grep-v "grep" | grep "pid-file = $ pid_file" | sed-n' $ P ''# use T to obtain the process ID for T in $ PROC do break done # kill this mysqld_safe program if kill-9 $ T then log_error "$ MYSQLD process hanging, pid $ T-killed "else break fi # I is added to every time mysqld_safe is killed, in this way, when there is no redundant mysqld_safe, the loop I = 'expr $ I + 1 'done fi log_notice "mysqld restarted" done # end the log _notice "mysqld from pid file $ pid_file ended"
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.