diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index d52097b9046..7740a4608f6 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -18,12 +18,12 @@ # so WSREP_VERSION is produced regardless # Set the patch version -SET(WSREP_PATCH_VERSION "10") +SET(WSREP_PATCH_VERSION "12") # MariaDB addition: Revision number of the last revision merged from # codership branch visible in @@visible_comment. -# Branch : codership-mysql/5.6 -SET(WSREP_PATCH_REVNO "4144") # Should be updated on every merge. +# Branch : https://github.com/codership/mysql-wsrep/tree/5.5 +SET(WSREP_PATCH_REVNO "4f81026") # Should be updated on every merge. # MariaDB: Obtain patch revision number: # Update WSREP_PATCH_REVNO if WSREP_REV environment variable is set. diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 46f4076111f..0aa338510e0 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2014 Codership Oy +# Copyright (C) 2012-2015 Codership Oy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,8 +20,11 @@ set -u WSREP_SST_OPT_BYPASS=0 WSREP_SST_OPT_BINLOG="" +WSREP_SST_OPT_CONF_SUFFIX="" WSREP_SST_OPT_DATA="" -WSREP_SST_OPT_AUTH="" +WSREP_SST_OPT_AUTH=${WSREP_SST_OPT_AUTH:-} +WSREP_SST_OPT_USER=${WSREP_SST_OPT_USER:-} +WSREP_SST_OPT_PSWD=${WSREP_SST_OPT_PSWD:-} while [ $# -gt 0 ]; do case "$1" in @@ -29,10 +32,6 @@ case "$1" in readonly WSREP_SST_OPT_ADDR="$2" shift ;; - '--auth') - WSREP_SST_OPT_AUTH="$2" - shift - ;; '--bypass') WSREP_SST_OPT_BYPASS=1 ;; @@ -45,7 +44,7 @@ case "$1" in shift ;; '--defaults-group-suffix') - readonly WSREP_SST_OPT_CONF_SUFFIX="$2" + WSREP_SST_OPT_CONF_SUFFIX="$2" shift ;; '--host') @@ -97,6 +96,7 @@ shift done readonly WSREP_SST_OPT_BYPASS readonly WSREP_SST_OPT_BINLOG +readonly WSREP_SST_OPT_CONF_SUFFIX # try to use my_print_defaults, mysql and mysqldump that come with the sources # (for MTR suite) @@ -124,12 +124,30 @@ else MY_PRINT_DEFAULTS=$(which my_print_defaults) fi +wsrep_auth_not_set() +{ + [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ] +} + # For Bug:1200727 -if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then - if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then - WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) +if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth" +then + if wsrep_auth_not_set + then + WSREP_SST_OPT_AUTH=$(MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2) fi fi +readonly WSREP_SST_OPT_AUTH + +# Splitting AUTH into potential user:password pair +if ! wsrep_auth_not_set +then + readonly AUTH_VEC=(${WSREP_SST_OPT_AUTH//:/ }) + WSREP_SST_OPT_USER="${AUTH_VEC[0]:-}" + WSREP_SST_OPT_PSWD="${AUTH_VEC[1]:-}" +fi +readonly WSREP_SST_OPT_USER +readonly WSREP_SST_OPT_PSWD if [ -n "${WSREP_SST_OPT_DATA:-}" ] then @@ -138,7 +156,6 @@ else SST_PROGRESS_FILE="" fi - wsrep_log() { # echo everything to stderr so that it gets into common error log diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index 3153cbcdfe0..9a061f89e43 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -1,5 +1,5 @@ -#!/bin/bash -e -# Copyright (C) 2009 Codership Oy +#!/bin/bash -ue +# Copyright (C) 2009-2015 Codership Oy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -41,7 +41,6 @@ local_ip() return 1 } -if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi @@ -64,13 +63,18 @@ then exit $EINVAL fi -# For Bug:1293798 -if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then - WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1) - WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2) -fi -AUTH="-u$WSREP_SST_OPT_USER" -if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi +[ -n "$WSREP_SST_OPT_USER" ] && AUTH="-u$WSREP_SST_OPT_USER" || AUTH= + +# Refs https://github.com/codership/mysql-wsrep/issues/141 +# Passing password in MYSQL_PWD environment variable is considered +# "extremely insecure" by MySQL Guidelines for Password Security +# (https://dev.mysql.com/doc/refman/5.6/en/password-security-user.html) +# that is even less secure than passing it on a command line! It is doubtful: +# the whole command line is easily observable by any unprivileged user via ps, +# whereas (at least on Linux) unprivileged user can't see process environment +# that he does not own. So while it may be not secure in the NSA sense of the +# word, it is arguably more secure than passing password on the command line. +[ -n "$WSREP_SST_OPT_PSWD" ] && export MYSQL_PWD="$WSREP_SST_OPT_PSWD" STOP_WSREP="SET wsrep_on=OFF;" @@ -136,15 +140,15 @@ fi MYSQLDUMP="$MYSQLDUMP $AUTH -S$WSREP_SST_OPT_SOCKET \ --add-drop-database --add-drop-table --skip-add-locks --create-options \ --disable-keys --extended-insert --skip-lock-tables --quick --set-charset \ ---skip-comments --flush-privileges --all-databases" +--skip-comments --flush-privileges --all-databases --events" # need to disable logging when loading the dump # reason is that dump contains ALTER TABLE for log tables, and # this causes an error if logging is enabled -GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@GENERAL_LOG"` -SLOW_LOG_OPT=`$MYSQL --skip-column-names -e"$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` -$MYSQL -e"$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" -$MYSQL -e"$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" +GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@GENERAL_LOG"` +SLOW_LOG_OPT=`$MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@SLOW_QUERY_LOG"` +$MYSQL -e "$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF" +$MYSQL -e "$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF" # commands to restore log settings RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;" diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index f5e304a1033..b3a07f8bbf6 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -32,8 +32,8 @@ wsrep_check_programs rsync cleanup_joiner() { - wsrep_log_info "Joiner cleanup." local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) + wsrep_log_info "Joiner cleanup. rsync PID: $PID" [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ || : rm -rf "$RSYNC_CONF" diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh index d5916b81a53..e3ad8257df6 100644 --- a/scripts/wsrep_sst_xtrabackup-v2.sh +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -29,6 +29,8 @@ ekeyfile="" encrypt=0 nproc=1 ecode=0 +ssyslog="" +ssystag="" XTRABACKUP_PID="" SST_PORT="" REMOTEIP="" @@ -40,15 +42,15 @@ progress="" ttime=0 totime=0 lsn="" -incremental=0 ecmd="" rlimit="" # Initially stagemsg="${WSREP_SST_OPT_ROLE}" cpat="" -speciald=0 +speciald=1 ib_home_dir="" ib_log_dir="" +ib_undo_dir="" sfmt="tar" strmcmd="" @@ -70,6 +72,11 @@ xtmpdir="" scomp="" sdecomp="" +# Required for backup locks +# For backup locks it is 1 sent by joiner +# 5.6.21 PXC and later can't donate to an older joiner +sst_ver=1 + if which pv &>/dev/null && pv --help | grep -q FORMAT;then pvopts+=$pvformat fi @@ -77,7 +84,6 @@ pcmd="pv $pvopts" declare -a RC INNOBACKUPEX_BIN=innobackupex -readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) DATA="${WSREP_SST_OPT_DATA}" INFO_FILE="xtrabackup_galera_info" IST_FILE="xtrabackup_ist" @@ -169,7 +175,11 @@ get_transfer() fi wsrep_log_info "Using netcat as streamer" if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - tcmd="nc -dl ${TSST_PORT}" + if nc -h | grep -q ncat;then + tcmd="nc -l ${TSST_PORT}" + else + tcmd="nc -dl ${TSST_PORT}" + fi else tcmd="nc ${REMOTEIP} ${TSST_PORT}" fi @@ -253,6 +263,16 @@ get_footprint() adjust_progress() { + + if [[ ! -x `which pv` ]];then + wsrep_log_error "pv not found in path: $PATH" + wsrep_log_error "Disabling all progress/rate-limiting" + pcmd="" + rlimit="" + progress="" + return + fi + if [[ -n $progress && $progress != '1' ]];then if [[ -e $progress ]];then pcmd+=" 2>>$progress" @@ -282,8 +302,7 @@ read_cnf() progress=$(parse_cnf sst progress "") rebuild=$(parse_cnf sst rebuild 0) ttime=$(parse_cnf sst time 0) - cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*grastate\.dat$\|.*gvwstate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') - incremental=$(parse_cnf sst incremental 0) + cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$') ealgo=$(parse_cnf xtrabackup encrypt "") ekey=$(parse_cnf xtrabackup encrypt-key "") ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "") @@ -304,6 +323,20 @@ read_cnf() iapts=$(parse_cnf sst inno-apply-opts "") impts=$(parse_cnf sst inno-move-opts "") stimeout=$(parse_cnf sst sst-initial-timeout 100) + ssyslog=$(parse_cnf sst sst-syslog 0) + ssystag=$(parse_cnf mysqld_safe syslog-tag "${SST_SYSLOG_TAG:-}") + ssystag+="-" + + if [[ $speciald -eq 0 ]];then + wsrep_log_error "sst-special-dirs equal to 0 is not supported, falling back to 1" + speciald=1 + fi + + if [[ $ssyslog -ne -1 ]];then + if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld_safe | tr '_' '-' | grep -q -- "--syslog";then + ssyslog=1 + fi + fi } get_stream() @@ -347,8 +380,7 @@ cleanup_joiner() local estatus=$? if [[ $estatus -ne 0 ]];then wsrep_log_error "Cleanup after exit with status:$estatus" - fi - if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then + elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then wsrep_log_info "Removing the sst_in_progress file" wsrep_cleanup_progress_file fi @@ -359,6 +391,23 @@ cleanup_joiner() if [[ -n ${STATDIR:-} ]];then [[ -d $STATDIR ]] && rm -rf $STATDIR fi + + # Final cleanup + pgid=$(ps -o pgid= $$ | grep -o '[0-9]*') + + # This means no setsid done in mysqld. + # We don't want to kill mysqld here otherwise. + if [[ $$ -eq $pgid ]];then + + # This means a signal was delivered to the process. + # So, more cleanup. + if [[ $estatus -ge 128 ]];then + kill -KILL -$$ || true + fi + + fi + + exit $estatus } check_pid() @@ -399,6 +448,24 @@ cleanup_donor() if [[ -n $itmpdir ]];then [[ -d $itmpdir ]] && rm -rf $itmpdir || true fi + + # Final cleanup + pgid=$(ps -o pgid= $$ | grep -o '[0-9]*') + + # This means no setsid done in mysqld. + # We don't want to kill mysqld here otherwise. + if [[ $$ -eq $pgid ]];then + + # This means a signal was delivered to the process. + # So, more cleanup. + if [[ $estatus -ge 128 ]];then + kill -KILL -$$ || true + fi + + fi + + exit $estatus + } kill_xtrabackup() @@ -415,6 +482,7 @@ setup_ports() SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }') + sst_ver=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $5 }') else SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }') fi @@ -432,11 +500,7 @@ wait_for_listen() ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break sleep 0.2 done - if [[ $incremental -eq 1 ]];then - echo "ready ${ADDR}/${MODULE}/$lsn" - else - echo "ready ${ADDR}/${MODULE}" - fi + echo "ready ${ADDR}/${MODULE}//$sst_ver" } check_extra() @@ -444,7 +508,7 @@ check_extra() local use_socket=1 if [[ $uextra -eq 1 ]];then if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then - local eport=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) + local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2) if [[ -n $eport ]];then # Xtrabackup works only locally. # Hence, setting host to 127.0.0.1 unconditionally. @@ -469,8 +533,14 @@ recv_joiner() local dir=$1 local msg=$2 local tmt=$3 + local checkf=$4 local ltcmd + if [[ ! -d ${dir} ]];then + # This indicates that IST is in progress + return + fi + pushd ${dir} 1>/dev/null set +e @@ -478,7 +548,7 @@ recv_joiner() if timeout --help | grep -q -- '-k';then ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd" else - ltcmd="timeout $tmt $tcmd" + ltcmd="timeout -s9 $tmt $tcmd" fi timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )" else @@ -501,7 +571,7 @@ recv_joiner() fi done - if [ ! -r "${MAGIC_FILE}" ];then + if [[ $checkf -eq 1 && ! -r "${MAGIC_FILE}" ]];then # this message should cause joiner to abort wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" wsrep_log_info "Contents of datadir" @@ -547,18 +617,52 @@ fi read_cnf setup_ports -get_stream -get_transfer -if ${INNOBACKUPEX_BIN} /tmp --help | grep -- '--version-check' >/dev/null ; then +if ${INNOBACKUPEX_BIN} /tmp --help 2>/dev/null | grep -q -- '--version-check'; then disver="--no-version-check" fi +if [[ ${FORCE_FTWRL:-0} -eq 1 ]];then + wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL" + iopts+=" --no-backup-locks " +fi + INNOEXTRA="" -INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" -INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" -INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" + +if [[ $ssyslog -eq 1 ]];then + + if [[ ! -x `which logger` ]];then + wsrep_log_error "logger not in path: $PATH. Ignoring" + else + + wsrep_log_info "Logging all stderr of SST/Innobackupex to syslog" + + exec 2> >(logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE) + + wsrep_log_error() + { + logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@" + } + + wsrep_log_info() + { + logger -p daemon.info -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@" + } + + INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply " + INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move " + INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)" + fi + +else + INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log" + INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log" + INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log" +fi + +get_stream +get_transfer if [ "$WSREP_SST_OPT_ROLE" = "donor" ] then @@ -566,6 +670,11 @@ then if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then + if [[ -z $sst_ver ]];then + wsrep_log_error "Upgrade joiner to 5.6.21 or higher for backup locks support" + wsrep_log_error "The joiner is not supported for this version of donor" + exit 93 + fi if [[ -z $(parse_cnf mysqld tmpdir "") && -z $(parse_cnf xtrabackup tmpdir "") ]];then xtmpdir=$(mktemp -d) @@ -576,13 +685,14 @@ then itmpdir=$(mktemp -d) wsrep_log_info "Using $itmpdir as innobackupex temporary directory" - if [ "${AUTH[0]}" != "(null)" ]; then - INNOEXTRA+=" --user=${AUTH[0]}" - fi + if [ "$WSREP_SST_OPT_USER" != "(null)" ]; then + INNOEXTRA+=" --user=$WSREP_SST_OPT_USER" + fi - if [ ${#AUTH[*]} -eq 2 ]; then - INNOEXTRA+=" --password=${AUTH[1]}" - elif [ "${AUTH[0]}" != "(null)" ]; then + if [ -n "$WSREP_SST_OPT_PSWD" ]; then +# INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD" + export MYSQL_PWD="$WSREP_SST_OPT_PSWD" + else # Empty password, used for testing, debugging etc. INNOEXTRA+=" --password=" fi @@ -596,9 +706,6 @@ then fi fi - if [[ -n $lsn ]];then - INNOEXTRA+=" --incremental --incremental-lsn=$lsn " - fi check_extra @@ -686,25 +793,12 @@ then [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE - if [[ $speciald -eq 1 ]];then - ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") - ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") - if [[ -z $ib_home_dir && -z $ib_log_dir ]];then - speciald=0 - fi - fi + ib_home_dir=$(parse_cnf mysqld innodb-data-home-dir "") + ib_log_dir=$(parse_cnf mysqld innodb-log-group-home-dir "") + ib_undo_dir=$(parse_cnf mysqld innodb-undo-directory "") stagemsg="Joiner-Recv" - if [[ ! -e ${DATA}/ibdata1 ]];then - incremental=0 - fi - - if [[ $incremental -eq 1 ]];then - wsrep_log_info "Incremental SST enabled: NOT SUPPORTED yet" - lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ') - wsrep_log_info "Recovered LSN: $lsn" - fi sencrypted=1 nthreads=1 @@ -733,12 +827,6 @@ then tcmd+=" | $pcmd" fi - if [[ $incremental -eq 1 ]];then - BDATA=$DATA - DATA=$(mktemp -d) - MAGIC_FILE="${DATA}/${INFO_FILE}" - fi - get_keys if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then if [[ -n $sdecomp ]];then @@ -752,7 +840,8 @@ then STATDIR=$(mktemp -d) MAGIC_FILE="${STATDIR}/${INFO_FILE}" - recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout + recv_joiner $STATDIR "${stagemsg}-gtid" $stimeout 1 + if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null then @@ -762,51 +851,48 @@ then if [ ! -r "${STATDIR}/${IST_FILE}" ] then + + if [[ -d ${DATA}/.sst ]];then + wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous state transfer" + fi + mkdir -p ${DATA}/.sst + (recv_joiner $DATA/.sst "${stagemsg}-SST" 0 0) & + jpid=$! wsrep_log_info "Proceeding with SST" - if [[ $speciald -eq 1 && -d ${DATA}/.sst ]];then - wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous SST" - fi - if [[ $incremental -ne 1 ]];then - if [[ $speciald -eq 1 ]];then - wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" - find $ib_home_dir $ib_log_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ - else - wsrep_log_info "Cleaning the existing datadir" - find $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories" + find $ib_home_dir $ib_log_dir $ib_undo_dir $DATA -mindepth 1 -regex $cpat -prune -o -exec rm -rfv {} 1>&2 \+ + + tempdir=$(parse_cnf mysqld log-bin "") + if [[ -n ${tempdir:-} ]];then + binlog_dir=$(dirname $tempdir) + binlog_file=$(basename $tempdir) + if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then + pattern="$binlog_dir/$binlog_file\.[0-9]+$" + wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" + find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ || true + rm $binlog_dir/*.index || true fi - tempdir=$(parse_cnf mysqld log-bin "") - if [[ -n ${tempdir:-} ]];then - binlog_dir=$(dirname $tempdir) - binlog_file=$(basename $tempdir) - if [[ -n ${binlog_dir:-} && $binlog_dir != '.' && $binlog_dir != $DATA ]];then - pattern="$binlog_dir/$binlog_file\.[0-9]+$" - wsrep_log_info "Cleaning the binlog directory $binlog_dir as well" - find $binlog_dir -maxdepth 1 -type f -regex $pattern -exec rm -fv {} 1>&2 \+ - rm $binlog_dir/*.index || true - rm $binlog_dir/*.state || true - fi - fi - - else - wsrep_log_info "Removing existing ib_logfile files" - rm -f ${BDATA}/ib_logfile* fi - if [[ $speciald -eq 1 ]];then - mkdir -p ${DATA}/.sst - TDATA=${DATA} - DATA="${DATA}/.sst" - fi + + TDATA=${DATA} + DATA="${DATA}/.sst" MAGIC_FILE="${DATA}/${INFO_FILE}" - recv_joiner $DATA "${stagemsg}-SST" 0 + wsrep_log_info "Waiting for SST streaming to complete!" + wait $jpid get_proc + if [[ ! -s ${DATA}/xtrabackup_checkpoints ]];then + wsrep_log_error "xtrabackup_checkpoints missing, failed innobackupex/SST on donor" + exit 2 + fi + # Rebuild indexes for compact backups if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then wsrep_log_info "Index compaction detected" @@ -878,11 +964,6 @@ then fi - if [[ $incremental -eq 1 ]];then - # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues. - INNOAPPLY="${INNOBACKUPEX_BIN} $disver --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} \ - --ibbackup=xtrabackup_56 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log" - fi wsrep_log_info "Preparing the backup at ${DATA}" timeit "Xtrabackup prepare stage" "$INNOAPPLY" @@ -893,28 +974,22 @@ then exit 22 fi - if [[ $speciald -eq 1 ]];then - MAGIC_FILE="${TDATA}/${INFO_FILE}" - set +e - rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log - set -e - wsrep_log_info "Moving the backup to ${TDATA}" - timeit "Xtrabackup move stage" "$INNOMOVE" - if [[ $? -eq 0 ]];then - wsrep_log_info "Move successful, removing ${DATA}" - rm -rf $DATA - DATA=${TDATA} - else - wsrep_log_error "Move failed, keeping ${DATA} for further diagnosis" - wsrep_log_error "Check ${DATA}/innobackup.move.log for details" - fi + MAGIC_FILE="${TDATA}/${INFO_FILE}" + set +e + rm $TDATA/innobackup.prepare.log $TDATA/innobackup.move.log + set -e + wsrep_log_info "Moving the backup to ${TDATA}" + timeit "Xtrabackup move stage" "$INNOMOVE" + if [[ $? -eq 0 ]];then + wsrep_log_info "Move successful, removing ${DATA}" + rm -rf $DATA + DATA=${TDATA} + else + wsrep_log_error "Move failed, keeping ${DATA} for further diagnosis" + wsrep_log_error "Check ${DATA}/innobackup.move.log for details" + exit 22 fi - if [[ $incremental -eq 1 ]];then - wsrep_log_info "Cleaning up ${DATA} after incremental SST" - [[ -d ${DATA} ]] && rm -rf ${DATA} - DATA=$BDATA - fi else wsrep_log_info "${IST_FILE} received from donor: Running IST" @@ -924,6 +999,7 @@ then wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable" exit 2 fi + wsrep_log_info "Galera co-ords from recovery: $(cat ${MAGIC_FILE})" cat "${MAGIC_FILE}" # output UUID:seqno wsrep_log_info "Total time on joiner: $totime seconds" fi diff --git a/scripts/wsrep_sst_xtrabackup.sh b/scripts/wsrep_sst_xtrabackup.sh index 044f9995580..7279c623288 100644 --- a/scripts/wsrep_sst_xtrabackup.sh +++ b/scripts/wsrep_sst_xtrabackup.sh @@ -61,7 +61,6 @@ pcmd="pv $pvopts" declare -a RC INNOBACKUPEX_BIN=innobackupex -readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) DATA="${WSREP_SST_OPT_DATA}" INFO_FILE="xtrabackup_galera_info" IST_FILE="xtrabackup_ist" @@ -150,7 +149,11 @@ get_transfer() fi wsrep_log_info "Using netcat as streamer" if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then - tcmd="nc -dl ${TSST_PORT}" + if nc -h | grep -q ncat;then + tcmd="nc -l ${TSST_PORT}" + else + tcmd="nc -dl ${TSST_PORT}" + fi else tcmd="nc ${REMOTEIP} ${TSST_PORT}" fi @@ -435,13 +438,14 @@ then then TMPDIR="${TMPDIR:-/tmp}" - if [ "${AUTH[0]}" != "(null)" ]; then - INNOEXTRA+=" --user=${AUTH[0]}" - fi + if [ "$WSREP_SST_OPT_USER" != "(null)" ]; then + INNOEXTRA+=" --user=$WSREP_SST_OPT_USER" + fi - if [ ${#AUTH[*]} -eq 2 ]; then - INNOEXTRA+=" --password=${AUTH[1]}" - elif [ "${AUTH[0]}" != "(null)" ]; then + if [ -n "$WSREP_SST_OPT_PSWD" ]; then +# INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD" + export MYSQL_PWD="$WSREP_SST_OPT_PSWD" + else # Empty password, used for testing, debugging etc. INNOEXTRA+=" --password=" fi diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index cc8a6b64526..548db8245c3 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -777,19 +777,10 @@ bool wsrep_start_replication() wsrep_sst_donor, bootstrap))) { - if (-ESOCKTNOSUPPORT == rcode) - { - DBUG_PRINT("wsrep",("unrecognized cluster address: '%s', rcode: %d", - wsrep_cluster_address, rcode)); - WSREP_ERROR("unrecognized cluster address: '%s', rcode: %d", - wsrep_cluster_address, rcode); - } - else - { - DBUG_PRINT("wsrep",("wsrep->connect() failed: %d", rcode)); - WSREP_ERROR("wsrep::connect() failed: %d", rcode); - } - + DBUG_PRINT("wsrep",("wsrep->connect(%s) failed: %d", + wsrep_cluster_address, rcode)); + WSREP_ERROR("wsrep::connect(%s) failed: %d", + wsrep_cluster_address, rcode); return false; } else diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc index 6eefb961b62..e7d30d5a9c1 100644 --- a/sql/wsrep_notify.cc +++ b/sql/wsrep_notify.cc @@ -97,7 +97,7 @@ void wsrep_notify_status (wsrep_member_status_t status, return; } - wsp::process p(cmd_ptr, "r"); + wsp::process p(cmd_ptr, "r", NULL); p.wait(); int err = p.error(); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 73fd9d9a0f5..b697a557476 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -296,12 +296,14 @@ void wsrep_sst_continue () struct sst_thread_arg { const char* cmd; - int err; + char** env; char* ret_str; + int err; mysql_mutex_t lock; mysql_cond_t cond; - sst_thread_arg (const char* c) : cmd(c), err(-1), ret_str(0) + sst_thread_arg (const char* c, char** e) + : cmd(c), env(e), ret_str(0), err(-1) { mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL); @@ -386,7 +388,7 @@ static void* sst_joiner_thread (void* a) WSREP_INFO("Running: '%s'", arg->cmd); - wsp::process proc (arg->cmd, "r"); + wsp::process proc (arg->cmd, "r", arg->env); if (proc.pipe() && !proc.error()) { @@ -460,12 +462,44 @@ static void* sst_joiner_thread (void* a) return NULL; } +#define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH" + +static int sst_append_auth_env(wsp::env& env, const char* sst_auth) +{ + int const sst_auth_size= strlen(WSREP_SST_AUTH_ENV) + 1 /* = */ + + (sst_auth ? strlen(sst_auth) : 0) + 1 /* \0 */; + + wsp::string sst_auth_str(sst_auth_size); // for automatic cleanup on return + if (!sst_auth_str()) return -ENOMEM; + + int ret= snprintf(sst_auth_str(), sst_auth_size, "%s=%s", + WSREP_SST_AUTH_ENV, sst_auth ? sst_auth : ""); + + if (ret < 0 || ret >= sst_auth_size) + { + WSREP_ERROR("sst_append_auth_env(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); + } + + env.append(sst_auth_str()); + return -env.error(); +} + static ssize_t sst_prepare_other (const char* method, + const char* sst_auth, const char* addr_in, const char** addr_out) { - char cmd_str[1024]; - const char* sst_dir= mysql_real_data_home; + int const cmd_len= 4096; + wsp::string cmd_str(cmd_len); + + if (!cmd_str()) + { + WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %d bytes", + cmd_len); + return -ENOMEM; + } + const char* binlog_opt= ""; char* binlog_opt_val= NULL; @@ -478,37 +512,48 @@ static ssize_t sst_prepare_other (const char* method, } if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; - - ret= snprintf (cmd_str, sizeof(cmd_str), + ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'joiner' " WSREP_SST_OPT_ADDR" '%s' " - WSREP_SST_OPT_AUTH" '%s' " WSREP_SST_OPT_DATA" '%s' " WSREP_SST_OPT_CONF" '%s' " WSREP_SST_OPT_CONF_SUFFIX" '%s' " WSREP_SST_OPT_PARENT" '%d'" " %s '%s' ", - method, addr_in, (sst_auth_real) ? sst_auth_real : "", - sst_dir, wsrep_defaults_file, wsrep_defaults_group_suffix, - (int) getpid(), binlog_opt, binlog_opt_val); + method, addr_in, mysql_real_data_home, + wsrep_defaults_file, wsrep_defaults_group_suffix, + (int)getpid(), binlog_opt, binlog_opt_val); my_free(binlog_opt_val); - if (ret < 0 || ret >= (int)sizeof(cmd_str)) + if (ret < 0 || ret >= cmd_len) { WSREP_ERROR("sst_prepare_other(): snprintf() failed: %d", ret); return (ret < 0 ? ret : -EMSGSIZE); } + wsp::env env(NULL); + if (env.error()) + { + WSREP_ERROR("sst_prepare_other(): env. var ctor failed: %d", -env.error()); + return -env.error(); + } + + if ((ret= sst_append_auth_env(env, sst_auth))) + { + WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret); + return ret; + } + pthread_t tmp; - sst_thread_arg arg(cmd_str); + sst_thread_arg arg(cmd_str(), env()); mysql_mutex_lock (&arg.lock); ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg); if (ret) { WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)", ret, strerror(ret)); - return ret; + return -ret; } mysql_cond_wait (&arg.cond, &arg.lock); @@ -650,7 +695,8 @@ ssize_t wsrep_sst_prepare (void** msg) return 0; } - addr_len = sst_prepare_other (wsrep_sst_method, addr_in, &addr_out); + addr_len = sst_prepare_other (wsrep_sst_method, sst_auth_real, + addr_in, &addr_out); if (addr_len < 0) { WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.", @@ -683,13 +729,13 @@ ssize_t wsrep_sst_prepare (void** msg) } // helper method for donors -static int sst_run_shell (const char* cmd_str, int max_tries) +static int sst_run_shell (const char* cmd_str, char** env, int max_tries) { int ret = 0; for (int tries=1; tries <= max_tries; tries++) { - wsp::process proc (cmd_str, "r"); + wsp::process proc (cmd_str, "r", env); if (NULL != proc.pipe()) { @@ -719,17 +765,12 @@ static void sst_reject_queries(my_bool close_conn) if (TRUE == close_conn) wsrep_close_client_connections(FALSE); } -static int sst_mysqldump_check_addr (const char* user, const char* pswd, - const char* host, const char* port) -{ - return 0; -} - static int sst_donate_mysqldump (const char* addr, const wsrep_uuid_t* uuid, const char* uuid_str, wsrep_seqno_t seqno, - bool bypass) + bool bypass, + char** env) // carries auth info { size_t host_len; const char* port = strchr (addr, ':'); @@ -750,53 +791,41 @@ static int sst_donate_mysqldump (const char* addr, strncpy (host, addr, host_len - 1); host[host_len - 1] = '\0'; - const char* auth = sst_auth_real; - const char* pswd = (auth) ? strchr (auth, ':') : NULL; - size_t user_len; + int const cmd_len= 4096; + wsp::string cmd_str(cmd_len); - if (pswd) + if (!cmd_str()) { - pswd += 1; - user_len = pswd - auth; - } - else - { - pswd = ""; - user_len = (auth) ? strlen (auth) + 1 : 1; + WSREP_ERROR("sst_donate_mysqldump(): " + "could not allocate cmd buffer of %d bytes", cmd_len); + return -ENOMEM; } - char *user= (char *) alloca(user_len); + if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); - strncpy (user, (auth) ? auth : "", user_len - 1); - user[user_len - 1] = '\0'; + int ret= snprintf (cmd_str(), cmd_len, + "wsrep_sst_mysqldump " + WSREP_SST_OPT_HOST" '%s' " + WSREP_SST_OPT_PORT" '%s' " + WSREP_SST_OPT_LPORT" '%u' " + WSREP_SST_OPT_SOCKET" '%s' " + WSREP_SST_OPT_CONF" '%s' " + WSREP_SST_OPT_GTID" '%s:%lld'" + "%s", + host, port, mysqld_port, mysqld_unix_port, + wsrep_defaults_file, uuid_str, + (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); - int ret = sst_mysqldump_check_addr (user, pswd, host, port); - if (!ret) + if (ret < 0 || ret >= cmd_len) { - char cmd_str[1024]; - - if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE); - - snprintf (cmd_str, sizeof(cmd_str), - "wsrep_sst_mysqldump " - WSREP_SST_OPT_USER" '%s' " - WSREP_SST_OPT_PSWD" '%s' " - WSREP_SST_OPT_HOST" '%s' " - WSREP_SST_OPT_PORT" '%s' " - WSREP_SST_OPT_LPORT" '%u' " - WSREP_SST_OPT_SOCKET" '%s' " - WSREP_SST_OPT_CONF" '%s' " - WSREP_SST_OPT_GTID" '%s:%lld'" - "%s", - user, pswd, host, port, mysqld_port, mysqld_unix_port, - wsrep_defaults_file, uuid_str, - (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); - - WSREP_DEBUG("Running: '%s'", cmd_str); - - ret= sst_run_shell (cmd_str, 3); + WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret); + return (ret < 0 ? ret : -EMSGSIZE); } + WSREP_DEBUG("Running: '%s'", cmd_str()); + + ret= sst_run_shell (cmd_str(), env, 3); + wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)}; wsrep->sst_sent (wsrep, &state_id, ret); @@ -950,7 +979,7 @@ static void* sst_donor_thread (void* a) wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can // operate with wsrep_ready == OFF - wsp::process proc(arg->cmd, "r"); + wsp::process proc(arg->cmd, "r", arg->env); err= proc.error(); @@ -1037,9 +1066,19 @@ static int sst_donate_other (const char* method, const char* addr, const char* uuid, wsrep_seqno_t seqno, - bool bypass) + bool bypass, + char** env) // carries auth info { - char cmd_str[4096]; + int const cmd_len= 4096; + wsp::string cmd_str(cmd_len); + + if (!cmd_str()) + { + WSREP_ERROR("sst_donate_other(): " + "could not allocate cmd buffer of %d bytes", cmd_len); + return -ENOMEM; + } + const char* binlog_opt= ""; char* binlog_opt_val= NULL; @@ -1051,11 +1090,10 @@ static int sst_donate_other (const char* method, } if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG; - ret= snprintf (cmd_str, sizeof(cmd_str), + ret= snprintf (cmd_str(), cmd_len, "wsrep_sst_%s " WSREP_SST_OPT_ROLE" 'donor' " WSREP_SST_OPT_ADDR" '%s' " - WSREP_SST_OPT_AUTH" '%s' " WSREP_SST_OPT_SOCKET" '%s' " WSREP_SST_OPT_DATA" '%s' " WSREP_SST_OPT_CONF" '%s' " @@ -1063,14 +1101,14 @@ static int sst_donate_other (const char* method, " %s '%s' " WSREP_SST_OPT_GTID" '%s:%lld'" "%s", - method, addr, sst_auth_real, mysqld_unix_port, - mysql_real_data_home, wsrep_defaults_file, - wsrep_defaults_group_suffix, binlog_opt, binlog_opt_val, + method, addr, mysqld_unix_port, mysql_real_data_home, + wsrep_defaults_file, wsrep_defaults_group_suffix, + binlog_opt, binlog_opt_val, uuid, (long long) seqno, bypass ? " "WSREP_SST_OPT_BYPASS : ""); my_free(binlog_opt_val); - if (ret < 0 || ret >= (int) sizeof(cmd_str)) + if (ret < 0 || ret >= cmd_len) { WSREP_ERROR("sst_donate_other(): snprintf() failed: %d", ret); return (ret < 0 ? ret : -EMSGSIZE); @@ -1079,7 +1117,7 @@ static int sst_donate_other (const char* method, if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE); pthread_t tmp; - sst_thread_arg arg(cmd_str); + sst_thread_arg arg(cmd_str(), env); mysql_mutex_lock (&arg.lock); ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg); if (ret) @@ -1112,18 +1150,32 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, char uuid_str[37]; wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str)); + wsp::env env(NULL); + if (env.error()) + { + WSREP_ERROR("wsrep_sst_donate_cb(): env var ctor failed: %d", -env.error()); + return WSREP_CB_FAILURE; + } + int ret; + if ((ret= sst_append_auth_env(env, sst_auth_real))) + { + WSREP_ERROR("wsrep_sst_donate_cb(): appending auth env failed: %d", ret); + return WSREP_CB_FAILURE; + } + if (!strcmp (WSREP_SST_MYSQLDUMP, method)) { ret = sst_donate_mysqldump(data, ¤t_gtid->uuid, uuid_str, - current_gtid->seqno, bypass); + current_gtid->seqno, bypass, env()); } else { - ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass); + ret = sst_donate_other(method, data, uuid_str, + current_gtid->seqno, bypass, env()); } - return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE); + return (ret >= 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE); } void wsrep_SE_init_grab() diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index 7a87d38d430..719e8e6b473 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -63,7 +63,7 @@ wsrep_prepend_PATH (const char* path) size_t const new_path_len(strlen(old_path) + strlen(":") + strlen(path) + 1); - char* const new_path (reinterpret_cast(malloc(new_path_len))); + char* const new_path (static_cast(malloc(new_path_len))); if (new_path) { @@ -89,6 +89,90 @@ wsrep_prepend_PATH (const char* path) namespace wsp { +bool +env::ctor_common(char** e) +{ + env_ = static_cast(malloc((len_ + 1) * sizeof(char*))); + + if (env_) + { + for (size_t i(0); i < len_; ++i) + { + assert(e[i]); // caller should make sure about len_ + env_[i] = strdup(e[i]); + if (!env_[i]) + { + errno_ = errno; + WSREP_ERROR("Failed to allocate env. var: %s", e[i]); + return true; + } + } + + env_[len_] = NULL; + return false; + } + else + { + errno_ = errno; + WSREP_ERROR("Failed to allocate env. var vector of length: %zu", len_); + return true; + } +} + +void +env::dtor() +{ + if (env_) + { + /* don't need to go beyond the first NULL */ + for (size_t i(0); env_[i] != NULL; ++i) { free(env_[i]); } + free(env_); + env_ = NULL; + } + len_ = 0; +} + +env::env(char** e) + : len_(0), env_(NULL), errno_(0) +{ + if (!e) { e = environ; } + /* count the size of the vector */ + while (e[len_]) { ++len_; } + + if (ctor_common(e)) dtor(); +} + +env::env(const env& e) + : len_(e.len_), env_(0), errno_(0) +{ + if (ctor_common(e.env_)) dtor(); +} + +env::~env() { dtor(); } + +int +env::append(const char* val) +{ + char** tmp = static_cast(realloc(env_, (len_ + 2)*sizeof(char*))); + + if (tmp) + { + env_ = tmp; + env_[len_] = strdup(val); + + if (env_[len_]) + { + ++len_; + env_[len_] = NULL; + } + else errno_ = errno; + } + else errno_ = errno; + + return errno_; +} + + #define PIPE_READ 0 #define PIPE_WRITE 1 #define STDIN_FD 0 @@ -98,7 +182,7 @@ namespace wsp # define POSIX_SPAWN_USEVFORK 0 #endif -process::process (const char* cmd, const char* type) +process::process (const char* cmd, const char* type, char** env) : str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0) { if (0 == str_) @@ -120,6 +204,8 @@ process::process (const char* cmd, const char* type) return; } + if (NULL == env) { env = environ; } // default to global environment + int pipe_fds[2] = { -1, }; if (::pipe(pipe_fds)) { @@ -215,7 +301,7 @@ process::process (const char* cmd, const char* type) goto cleanup_fact; } - err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ); + err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, env); if (err_) { WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)", @@ -309,6 +395,7 @@ process::wait () { case 126: err_ = EACCES; break; /* Permission denied */ case 127: err_ = ENOENT; break; /* No such file or directory */ + case 143: err_ = EINTR; break; /* Subprocess killed */ } WSREP_ERROR("Process completed with error: %s: %d (%s)", str_, err_, strerror(err_)); diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h index dfb68bcd1b7..7d864603c7f 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Codership Oy +/* Copyright (C) 2013-2015 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,6 +44,25 @@ private: extern wsp::node_status local_status; namespace wsp { +/* a class to manage env vars array */ +class env +{ +private: + size_t len_; + char** env_; + int errno_; + bool ctor_common(char** e); + void dtor(); + env& operator =(env); +public: + explicit env(char** env); + explicit env(const env&); + ~env(); + int append(const char* var); /* add a new env. var */ + int error() const { return errno_; } + char** operator()() { return env_; } +}; + /* A small class to run external programs. */ class process { @@ -56,8 +75,9 @@ private: public: /*! @arg type is a pointer to a null-terminated string which must contain either the letter 'r' for reading or the letter 'w' for writing. + @arg env optional null-terminated vector of environment variables */ - process (const char* cmd, const char* type); + process (const char* cmd, const char* type, char** env); ~process (); FILE* pipe () { return io_; } @@ -90,6 +110,8 @@ class string { public: string() : string_(0) {} + explicit string(size_t s) : string_(static_cast(malloc(s))) {} + char* operator()() { return string_; } void set(char* str) { if (string_) free (string_); string_ = str; } ~string() { set (0); } private: