MDEV-25818: RSYNC SST failed due to busy port

This commit reduces the likelihood of getting a busy port on
quick restarts with rsync SST (problem MDEV-25818) and fixes
a number of other flaws in SST scripts, adds new functionality,
and also synchronizes the xtrabackup-v2 script with the
mariabackup script (the latter applies only to the 10.2 branch):

 1) SST via rsync: rsync and stunnel does not always get the right
    time to complete by correctly handling SIGTERM. These utilities
    are now given more time to complete normally (via normal SIGTERM
    processing) before we move on to using "kill -9";
 2) SST via rsync: attempts to terminate an rsync or stunnel process
    (via "kill" utility) are only made if it did not terminated on
    its own;
 3) SST via rsync: if a combination of stunnel and rsync is used,
    then we need to wait for both utilities to finish or stop, not
    just one of them;
 4) The config file and pid file for stunnel are now deleted after
    successful completion of SST on the donor node;
 5) The configs and pid files from rsync and stunnel should not be
    deleted unless these utilities succeed (or are sucessfully
    terminated) on the joiner node;
 6) The configs and pid files now excluded from transfer via rsync;
 7) Spaces in paths are now valid for config files as well (when
    used with SST via rsync or mariabackup / xtrabackup[-v2]);
 8) SST via mariabackup: added preliminary verification of keys and
    certificates that are used when establishing a connection using
    SSL (to avoid long timeouts and improve diagnostics) - by analogy
    with how it is done for the xtrabackup-v2 (plus check for CA file),
    while that check is skipped if the user does not have openssl
    installed (or does not have diff utility);
 9) Added backup-threads=<n> configuration option which adds
    "--parallel=<n>" for mariabackup / xtrabackup at backup and
    move-back stages;
10) Added encrypt-threads and encrypt-chunk-size configuration
    options for xbcrypt management (when xbcrypt is used);
11) Small optimization: checking the socat version and adding
    a file with parameters for 2048-bit Diffie-Hellman (if necessary)
    is done only if the user has not specified "dhparam=" in the
    "sockopt" option value;
12) SST via rsync now supports "backup-threads" configuration option
    (in server-related sections or in the "[sst]");
13) Determining the number of available processors is now supported
    for FreeBSD + mariabackup/xtrabackup: before that we might have
    problems with "--compact" (rebuild indexes) or qpress on FreeBSD;
14) The check_pid() function should not raise an error state in
    the rare cases when the pid file was created, but it is empty,
    or if it is deleted right during the check, or when zero is read
    from the pid file;
15) Iproved templates that are used to check if a requested socket
    is "listening" when using the ss utility;
16) Shortened some other templates for socket state utilities;
17) Temporary files created by mariabackup / xtrabackup are moved
    to a separate subdirectory inside tmpdir (so they don't get
    mixed with other temporary files, which can make debugging
    more difficult);
18) 10.2 only: the script for SST via xtrabackup-v2 has been brought
    in full compliance with all the bugfixes made for mariabackup (as
    it previously contained many flaws compared to the updated script
    for mariabackup).
This commit is contained in:
Julius Goryavsky 2021-05-29 19:54:25 +02:00
parent d3c77e08ae
commit 2fb4407827
17 changed files with 1182 additions and 830 deletions

View File

@ -10,4 +10,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'

View File

@ -9,4 +9,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'

View File

@ -11,4 +11,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'

View File

@ -8,5 +8,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'

View File

@ -5,10 +5,8 @@ wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth=root:
innodb_safe_truncate=OFF
[mysqld.1]
wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'

View File

@ -13,4 +13,4 @@ wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore
[sst]
transferfmt=@ENV.MTR_GALERA_TFMT
streamfmt=xbstream
streamfmt=mbstream

View File

@ -10,3 +10,4 @@ transferfmt=@ENV.MTR_GALERA_TFMT
compress=quicklz
compress-threads=2
compress-chunk-size=32768
backup-threads=2

View File

@ -15,4 +15,4 @@ wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore
[sst]
transferfmt=@ENV.MTR_GALERA_TFMT
streamfmt=xbstream
streamfmt=mbstream

View File

@ -8,4 +8,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'

View File

@ -12,4 +12,3 @@ log_bin_index=@ENV.MYSQLTEST_VARDIR/tmp/server1_binlog_index.index
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
log_bin=@ENV.MYSQLTEST_VARDIR/server2_binlog
log_bin_index=@ENV.MYSQLTEST_VARDIR/tmp/server2_binlog_index.index

View File

@ -9,3 +9,6 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore
[mysqld.2]
innodb_data_home_dir=@ENV.MYSQL_TMP_DIR/rsync_test_2
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
[sst]
backup_threads=2

View File

@ -29,7 +29,9 @@ WSREP_SST_OPT_USER="${WSREP_SST_OPT_USER:-}"
WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_PSWD:-}"
WSREP_SST_OPT_REMOTE_AUTH="${WSREP_SST_OPT_REMOTE_AUTH:-}"
WSREP_SST_OPT_DEFAULT=""
WSREP_SST_OPT_DEFAULTS=""
WSREP_SST_OPT_EXTRA_DEFAULT=""
WSREP_SST_OPT_EXTRA_DEFAULTS=""
WSREP_SST_OPT_SUFFIX_DEFAULT=""
WSREP_SST_OPT_SUFFIX_VALUE=""
WSREP_SST_OPT_MYSQLD=""
@ -152,10 +154,12 @@ case "$1" in
;;
'--defaults-file')
readonly WSREP_SST_OPT_DEFAULT="$1=$2"
readonly WSREP_SST_OPT_DEFAULTS="$1='$2'"
shift
;;
'--defaults-extra-file')
readonly WSREP_SST_OPT_EXTRA_DEFAULT="$1=$2"
readonly WSREP_SST_OPT_EXTRA_DEFAULTS="$1='$2'"
shift
;;
'--defaults-group-suffix')
@ -611,24 +615,54 @@ else
MYSQLDUMP="$(command -v mysqldump)"
fi
wsrep_log()
{
# echo everything to stderr so that it gets into common error log
# deliberately made to look different from the rest of the log
local readonly tst="$(date +%Y%m%d\ %H:%M:%S.%N | cut -b -21)"
echo "WSREP_SST: $* ($tst)" >&2
}
wsrep_log_error()
{
wsrep_log "[ERROR] $*"
}
wsrep_log_warning()
{
wsrep_log "[WARNING] $*"
}
wsrep_log_info()
{
wsrep_log "[INFO] $*"
}
if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then
MY_PRINT_DEFAULTS="$SCRIPTS_DIR/my_print_defaults"
elif [ -x "$EXTRA_DIR/my_print_defaults" ]; then
MY_PRINT_DEFAULTS="$EXTRA_DIR/my_print_defaults"
else
MY_PRINT_DEFAULTS="$(command -v my_print_defaults)"
if [ -z "$MY_PRINT_DEFAULTS" ]; then
wsrep_log_error "my_print_defaults not found in path"
exit 2
fi
fi
readonly MY_PRINT_DEFAULTS
wsrep_defaults="$WSREP_SST_OPT_DEFAULTS"
wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_EXTRA_DEFAULTS"
wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT"
readonly WSREP_SST_OPT_CONF="$wsrep_defaults"
wsrep_defaults="$WSREP_SST_OPT_DEFAULT"
if [ -n "$wsrep_defaults" ]; then
wsrep_defaults="$wsrep_defaults "
fi
wsrep_defaults="$wsrep_defaults$WSREP_SST_OPT_EXTRA_DEFAULT"
if [ -n "$wsrep_defaults" ]; then
wsrep_defaults="$wsrep_defaults "
fi
readonly WSREP_SST_OPT_CONF="$wsrep_defaults$WSREP_SST_OPT_SUFFIX_DEFAULT"
readonly MY_PRINT_DEFAULTS="$MY_PRINT_DEFAULTS $WSREP_SST_OPT_CONF"
wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_EXTRA_DEFAULT"
wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT"
readonly WSREP_SST_OPT_CONF_UNQUOTED="$wsrep_defaults"
#
# User can specify mariabackup specific settings that will be used during sst
@ -663,13 +697,21 @@ parse_cnf()
# If the group name is the same as the "mysqld" without "--" prefix,
# then try to use it together with the group suffix:
if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then
reval=$($MY_PRINT_DEFAULTS "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
reval=$("$MY_PRINT_DEFAULTS" \
${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
"mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
if [ -n "$reval" ]; then
break
fi
fi
# Let's try to use the group name as it is:
reval=$($MY_PRINT_DEFAULTS "$group" | awk "$pattern")
reval=$("$MY_PRINT_DEFAULTS" \
${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
"$group" | awk "$pattern")
if [ -n "$reval" ]; then
break
fi
@ -710,13 +752,21 @@ in_config()
# If the group name is the same as the "mysqld" without "--" prefix,
# then try to use it together with the group suffix:
if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then
found=$($MY_PRINT_DEFAULTS "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
found=$("$MY_PRINT_DEFAULTS" \
${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
"mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
if [ $found -ne 0 ]; then
break
fi
fi
# Let's try to use the group name as it is:
found=$($MY_PRINT_DEFAULTS "$group" | awk "$pattern")
found=$($MY_PRINT_DEFAULTS \
${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
"$group" | awk "$pattern")
if [ $found -ne 0 ]; then
break
fi
@ -797,29 +847,6 @@ else
SST_PROGRESS_FILE=""
fi
wsrep_log()
{
# echo everything to stderr so that it gets into common error log
# deliberately made to look different from the rest of the log
local readonly tst="$(date +%Y%m%d\ %H:%M:%S.%N | cut -b -21)"
echo "WSREP_SST: $* ($tst)" >&2
}
wsrep_log_error()
{
wsrep_log "[ERROR] $*"
}
wsrep_log_warning()
{
wsrep_log "[WARNING] $*"
}
wsrep_log_info()
{
wsrep_log "[INFO] $*"
}
wsrep_cleanup_progress_file()
{
[ -n "$SST_PROGRESS_FILE" -a \
@ -959,6 +986,43 @@ check_sockets_utils()
fi
}
#
# Check if the port is in the "listen" state.
# The first parameter is the PID of the process that should
# listen on the port - if it is not known, you can specify
# an empty string or zero.
# The second parameter is the port number.
# The third parameter is a list of the names of utilities
# (via "|") that can listen on this port during the state
# transfer.
#
check_port()
{
local pid="$1"
local port="$2"
local utils="$3"
[ -z "$pid" ] || [ $pid -eq 0 ] && pid='[0-9]+'
local rc=1
if [ $lsof_available -ne 0 ]; then
lsof -Pnl -i ":$port" 2>/dev/null | \
grep -q -E "^($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*\\(LISTEN\\)" && rc=0
elif [ $sockstat_available -ne 0 ]; then
sockstat -p "$port" 2>/dev/null | \
grep -q -E "[[:space:]]+($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*[[:space:]]LISTEN" && rc=0
elif [ $ss_available -ne 0 ]; then
ss -nlpH "( sport = :$port )" 2>/dev/null | \
grep -q -E "users:\\(.*\\(\"($utils)[^[:space:]]*\"[^)]*,pid=$pid(,[^)]*)?\\)" && rc=0
else
wsrep_log_error "unknown sockets utility"
exit 2 # ENOENT
fi
return $rc
}
#
# If the ssl_dhparams variable is already set, uses that as a source
# of dh parameters for OpenSSL. Otherwise, looks for dhparams.pem in
@ -966,28 +1030,95 @@ check_sockets_utils()
#
check_for_dhparams()
{
if [ -z "$ssl_dhparams" ]; then
ssl_dhparams="$DATA/dhparams.pem"
if [ ! -r "$ssl_dhparams" ]; then
get_openssl
if [ -n "$OPENSSL_BINARY" ]; then
wsrep_log_info "Could not find dhparams file, creating $ssl_dhparams"
if ! "$OPENSSL_BINARY" dhparam -out "$ssl_dhparams" 2048 >/dev/null 2>&1
then
wsrep_log_error "******** ERROR *****************************************"
wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *"
wsrep_log_error "********************************************************"
ssl_dhparams=""
fi
else
# Rollback: if openssl is not installed, then use
# the default parameters:
ssl_dhparams="$DATA/dhparams.pem"
if [ ! -r "$ssl_dhparams" ]; then
get_openssl
if [ -n "$OPENSSL_BINARY" ]; then
wsrep_log_info "Could not find dhparams file, creating $ssl_dhparams"
if ! "$OPENSSL_BINARY" dhparam -out "$ssl_dhparams" 2048 >/dev/null 2>&1
then
wsrep_log_error "******** ERROR *****************************************"
wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *"
wsrep_log_error "********************************************************"
ssl_dhparams=""
fi
fi
else
# Rollback: if openssl is not installed, then use
# the default parameters:
ssl_dhparams=""
fi
fi
}
#
# Verifies that the CA file verifies the certificate.
# Doing this here lets us generate better error messages.
#
# 1st param: path to the CA file.
# 2nd param: path to the certificate.
#
verify_ca_matches_cert()
{
local ca_path="$1"
local cert_path="$2"
# If the openssl utility is not installed, then
# we will not do this certificate check:
get_openssl
if [ -z "$OPENSSL_BINARY" ]; then
return
fi
if ! "$OPENSSL_BINARY" verify -verbose -CAfile "$ca_path" "$cert_path" >/dev/null 2>&1
then
wsrep_log_error "******** FATAL ERROR ********************************************"
wsrep_log_error "* The certifcate and CA (certificate authority) do not match. *"
wsrep_log_error "* It does not appear that the certificate was issued by the CA. *"
wsrep_log_error "* Please check your certificate and CA files. *"
wsrep_log_error "*****************************************************************"
exit 22
fi
}
#
# Verifies that the certificate matches the private key.
# Doing this will save us having to wait for a timeout that would
# otherwise occur.
#
# 1st param: path to the certificate.
# 2nd param: path to the private key.
#
verify_cert_matches_key()
{
local cert_path="$1"
local key_path="$2"
# If the diff utility is not installed, then
# we will not do this certificate check:
if [ -z "$(command -v diff)" ]; then
return
fi
# If the openssl utility is not installed, then
# we will not do this certificate check:
get_openssl
if [ -z "$OPENSSL_BINARY" ]; then
return
fi
# Generate the public key from the cert and the key.
# They should match (otherwise we can't create an SSL connection).
if ! diff <("$OPENSSL_BINARY" x509 -in "$cert_path" -pubkey -noout 2>/dev/null) \
<("$OPENSSL_BINARY" pkey -in "$key_path" -pubout 2>/dev/null) >/dev/null 2>&1
then
wsrep_log_error "******************* FATAL ERROR ****************"
wsrep_log_error "* The certifcate and private key do not match. *"
wsrep_log_error "* Please check your certificate and key files. *"
wsrep_log_error "************************************************"
exit 22
fi
}
#
# Compares two version strings.
# The first parameter is the version to be checked;
@ -996,22 +1127,22 @@ check_for_dhparams()
#
check_for_version()
{
y1=${1#*.}
y1="${1#*.}"
[ "$y1" = "$1" ] && y1=""
z1=${y1#*.}
[ "$z1" = "$y1" ] && z1=""
x1=${1%%.*}
y1=${y1%%.*}
z1=${z1%%.*}
x1="${1%%.*}"
y1="${y1%%.*}"
z1="${z1%%.*}"
[ -z "$y1" ] && y1=0
[ -z "$z1" ] && z1=0
y2=${2#*.}
y2="${2#*.}"
[ "$y2" = "$2" ] && y2=""
z2=${y2#*.}
z2="${y2#*.}"
[ "$z2" = "$y2" ] && z2=""
x2=${2%%.*}
y2=${y2%%.*}
z2=${z2%%.*}
x2="${2%%.*}"
y2="${y2%%.*}"
z2="${z2%%.*}"
[ -z "$y2" ] && y2=0
[ -z "$z2" ] && z2=0
[ $x1 -lt $x2 ] && return 1
@ -1032,8 +1163,8 @@ trim_string()
if [ $x -ne $z ]; then
local y="${1%$pattern*}"
y=${#y}
x=$(( $z-$x-1 ))
y=$(( $y-$x+1 ))
x=$(( z-x-1 ))
y=$(( y-x+1 ))
printf '%s' "${1:$x:$y}"
else
printf ''
@ -1043,3 +1174,105 @@ trim_string()
echo "$1" | sed -E "s/^$pattern+|$pattern+\$//g"
fi
}
#
# Check whether process is still running.
# The first parameter contains the name of the PID file.
# The second parameter is the flag of the need to delete
# the PID file.
# If the second parameter is not zero and not empty,
# then if the process terminates, the corresponding
# PID file will be deleted.
# This function also sets the CHECK_PID variable to zero
# if the process has already exited, or writes the PID
# of the process there if it is still running.
#
check_pid()
{
local pid_file="$1"
local remove=${2:-0}
if [ -r "$pid_file" ]; then
local pid=$(cat "$pid_file" 2>/dev/null)
if [ -n "$pid" ]; then
if [ $pid -ne 0 ]; then
if ps -p "$pid" >/dev/null 2>&1; then
CHECK_PID=$pid
return 0
fi
fi
fi
if [ $remove -eq 1 ]; then
rm -f "$pid_file"
fi
fi
CHECK_PID=0
return 1
}
#
# Checking that the process with the specified PID is still
# running and killing it in this case by sending SIGTERM
# (using the "kill" operation).
# The first parameter contains PID of the process.
# The second and third parameters (both optional) are the names
# of the PID and the configuration files, which should be removed
# after the process ends.
# If the first parameter (PID of the process) is zero, then
# the function immediately deletes the PID and the configuration
# files (if specified), without any additional checks.
#
cleanup_pid()
{
local pid="$1"
local pid_file="${2:-}"
local config="${3:-}"
if [ $pid -ne 0 ]; then
if ps -p $pid >/dev/null 2>&1; then
if kill $pid >/dev/null 2>&1; then
sleep 0.5
local round=0
local force=0
while ps -p $pid >/dev/null 2>&1; do
sleep 1
round=$(( round+1 ))
if [ $round -eq 16 ]; then
if [ $force -eq 0 ]; then
round=8
force=1
kill -9 $pid >/dev/null 2>&1
else
return 1;
fi
fi
done
elif ps -p $pid >/dev/null 2>&1; then
wsrep_log_warning "Unable to kill PID=$pid ($pid_file)"
return 1
fi
fi
fi
[ -n "$pid_file" ] && [ -f "$pid_file" ] && rm -f "$pid_file"
[ -n "$config" ] && [ -f "$config" ] && rm -f "$config"
return 0
}
nproc=""
get_proc()
{
if [ -z "$nproc" ]; then
set +e
if [ "$OS" = 'Linux' ]; then
nproc=$(grep -c processor /proc/cpuinfo 2>/dev/null)
elif [ "$OS" = 'Darwin' -o "$OS" = 'FreeBSD' ]; then
nproc=$(sysctl -n hw.ncpu)
fi
if [ -z "$nproc" ] || [ $nproc -eq 0 ]; then
nproc=1
fi
set -e
fi
}

View File

@ -29,11 +29,10 @@ eformat=""
ekey=""
ekeyfile=""
encrypt=0
nproc=1
ecode=0
ssyslog=""
ssystag=""
MARIABACKUP_PID=""
BACKUP_PID=""
tcert=""
tpem=""
tkey=""
@ -77,6 +76,11 @@ compress='none'
compress_chunk=""
compress_threads=""
backup_threads=""
encrypt_threads=""
encrypt_chunk=""
readonly SECRET_TAG="secret"
# Required for backup locks
@ -90,8 +94,8 @@ fi
pcmd="pv $pvopts"
declare -a RC
MARIABACKUP_BIN="$(command -v mariabackup)"
if [ ! -x "$MARIABACKUP_BIN" ]; then
BACKUP_BIN="$(command -v mariabackup)"
if [ ! -x "$BACKUP_BIN" ]; then
wsrep_log_error 'mariabackup binary not found in path'
exit 42
fi
@ -108,7 +112,8 @@ INNOBACKUPLOG="$DATA/mariabackup.backup.log"
# Setting the path for ss and ip
export PATH="/usr/sbin:/sbin:$PATH"
timeit(){
timeit()
{
local stage="$1"
shift
local cmd="$@"
@ -198,6 +203,12 @@ get_keys()
else
ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key='$ekey'"
fi
if [ -n "$encrypt_threads" ]; then
ecmd="$ecmd --encrypt-threads=$encrypt_threads"
fi
if [ -n "$encrypt_chunk" ]; then
ecmd="$ecmd --encrypt-chunk-size=$encrypt_chunk"
fi
else
wsrep_log_error "Unknown encryption format='$eformat'"
exit 2
@ -298,15 +309,6 @@ get_transfer()
exit 2
fi
# Determine the socat version
SOCAT_VERSION=$(socat -V 2>&1 | grep -m1 -oe '[0-9]\.[0-9][\.0-9]*')
if [ -z "$SOCAT_VERSION" ]; then
wsrep_log_error "******** FATAL ERROR ******************"
wsrep_log_error "* Cannot determine the socat version. *"
wsrep_log_error "***************************************"
exit 2
fi
local action='Decrypting'
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
tcmd="socat -u openssl-listen:$SST_PORT,reuseaddr"
@ -315,10 +317,22 @@ get_transfer()
action='Encrypting'
fi
if ! check_for_version "$SOCAT_VERSION" '1.7.3'; then
# socat versions < 1.7.3 will have 512-bit dhparams (too small)
# so create 2048-bit dhparams and send that as a parameter:
check_for_dhparams
if [ "${sockopt#*,dhparam=}" != "$sockopt" ]; then
if [ -z "$ssl_dhparams" ]; then
# Determine the socat version
SOCAT_VERSION=$(socat -V 2>&1 | grep -m1 -oe '[0-9]\.[0-9][\.0-9]*')
if [ -z "$SOCAT_VERSION" ]; then
wsrep_log_error "******** FATAL ERROR ******************"
wsrep_log_error "* Cannot determine the socat version. *"
wsrep_log_error "***************************************"
exit 2
fi
if ! check_for_version "$SOCAT_VERSION" '1.7.3'; then
# socat versions < 1.7.3 will have 512-bit dhparams (too small)
# so create 2048-bit dhparams and send that as a parameter:
check_for_dhparams
fi
fi
if [ -n "$ssl_dhparams" ]; then
tcmd="$tcmd,dhparam='$ssl_dhparams'"
fi
@ -330,6 +344,11 @@ get_transfer()
wsrep_log_error "Both PEM and CRT files required"
exit 22
fi
if [ ! -r "$tpem" -o ! -r "$tcert" ]; then
wsrep_log_error "Both PEM and CRT files must be readable"
exit 22
fi
verify_ca_matches_cert "$tcert" "$tpem"
tcmd="$tcmd,cert='$tpem',cafile='$tcert'$sockopt"
stagemsg="$stagemsg-OpenSSL-Encrypted-2"
wsrep_log_info "$action with cert=$tpem, cafile=$tcert"
@ -339,6 +358,11 @@ get_transfer()
wsrep_log_error "Both certificate and key files required"
exit 22
fi
if [ ! -r "$tpem" -o ! -r "$tkey" ]; then
wsrep_log_error "Both certificate and key files must be readable"
exit 22
fi
verify_cert_matches_key "$tpem" "$tkey"
stagemsg="$stagemsg-OpenSSL-Encrypted-3"
if [ -z "$tcert" ]; then
if [ $encrypt -eq 4 ]; then
@ -350,6 +374,11 @@ get_transfer()
wsrep_log_info "$action with cert=$tpem, key=$tkey, verify=0"
else
# CA verification
if [ ! -r "$tcert" ]; then
wsrep_log_error "Certificate file must be readable"
exit 22
fi
verify_ca_matches_cert "$tcert" "$tpem"
if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then
CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'"
elif [ $encrypt -eq 4 ]; then
@ -440,10 +469,10 @@ read_cnf()
tpem=$(parse_cnf 'sst' 'tcert')
tkey=$(parse_cnf 'sst' 'tkey')
fi
if [ "$tmode" != 'DISABLED' ]
then # backward-incompatible behavior
if [ -z "$tpem" -a -z "$tkey" -a -z "$tcert" ]
then # no old-style SSL config in [sst]
if [ "$tmode" != 'DISABLED' ]; then
# backward-incompatible behavior
if [ -z "$tpem" -a -z "$tkey" -a -z "$tcert" ]; then
# no old-style SSL config in [sst]
check_server_ssl_config
fi
if [ 0 -eq $encrypt -a -n "$tpem" -a -n "$tkey" ]
@ -504,21 +533,28 @@ read_cnf()
compress_threads=$(parse_cnf "$encgroups" 'compress-threads')
fi
fi
backup_threads=$(parse_cnf "$encgroups" 'backup-threads')
if [ "$eformat" = 'xbcrypt' ]; then
encrypt_threads=$(parse_cnf "$encgroups" 'encrypt-threads')
encrypt_chunk=$(parse_cnf "$encgroups" 'encrypt-chunk-size')
fi
}
get_stream()
{
if [ "$sfmt" = 'mbstream' -o "$sfmt" = 'xbstream' ]; then
sfmt='mbstream'
MBSTREAM_BIN="$(command -v mbstream)"
if [ -z "$MBSTREAM_BIN" ]; then
STREAM_BIN="$(command -v mbstream)"
if [ -z "$STREAM_BIN" ]; then
wsrep_log_error "Streaming with $sfmt, but $sfmt not found in path"
exit 42
fi
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
strmcmd="'$MBSTREAM_BIN' -x"
strmcmd="'$STREAM_BIN' -x"
else
strmcmd="'$MBSTREAM_BIN' -c '$INFO_FILE'"
strmcmd="'$STREAM_BIN' -c '$INFO_FILE'"
fi
else
sfmt='tar'
@ -531,79 +567,33 @@ get_stream()
wsrep_log_info "Streaming with $sfmt"
}
get_proc()
{
set +e
nproc=$(grep -c processor /proc/cpuinfo)
[ -z $nproc -o $nproc -eq 0 ] && nproc=1
set -e
}
sig_joiner_cleanup()
{
wsrep_log_error "Removing $MAGIC_FILE file due to signal"
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
}
cleanup_joiner()
cleanup_at_exit()
{
# Since this is invoked just after exit NNN
local estatus=$?
if [ $estatus -ne 0 ]; then
wsrep_log_error "Cleanup after exit with status:$estatus"
elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
fi
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
wsrep_log_info "Removing the sst_in_progress file"
wsrep_cleanup_progress_file
fi
if [ -n "$progress" -a -p "$progress" ]; then
wsrep_log_info "Cleaning up fifo file $progress"
rm "$progress"
fi
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
else
if [ -n "$BACKUP_PID" ]; then
if check_pid "$BACKUP_PID" 1; then
wsrep_log_error "mariabackup process is still running. Killing..."
cleanup_pid $CHECK_PID "$BACKUP_PID"
fi
fi
[ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE"
fi
exit $estatus
}
check_pid()
{
local pid_file="$1"
[ -r "$pid_file" ] && ps -p $(cat "$pid_file") 2>&1 >/dev/null
}
cleanup_donor()
{
# Since this is invoked just after exit NNN
local estatus=$?
if [ $estatus -ne 0 ]; then
wsrep_log_error "Cleanup after exit with status:$estatus"
fi
if [ -n "$MARIABACKUP_PID" ]; then
if check_pid $MARIABACKUP_PID
then
wsrep_log_error "mariabackup process is still running. Killing..."
kill_mariabackup
fi
fi
[ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE"
if [ -n "$progress" -a -p "$progress" ]; then
wsrep_log_info "Cleaning up fifo file $progress"
rm -f "$progress" || true
@ -611,8 +601,14 @@ cleanup_donor()
wsrep_log_info "Cleaning up temporary directories"
[ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || true
[ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || true
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
if [ -n "$STATDIR" ]; then
[ -d "$STATDIR" ] && rm -rf "$STATDIR"
fi
else
[ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || true
[ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || true
fi
# Final cleanup
pgid=$(ps -o pgid= $$ | grep -o '[0-9]*')
@ -623,21 +619,13 @@ cleanup_donor()
# This means a signal was delivered to the process.
# So, more cleanup.
if [ $estatus -ge 128 ]; then
kill -KILL -$$ || true
kill -KILL -- -$$ || true
fi
fi
exit $estatus
}
kill_mariabackup()
{
local PID=$(cat "$MARIABACKUP_PID")
[ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || :
wsrep_log_info "Removing mariabackup pid file ($MARIABACKUP_PID)"
rm -f "$MARIABACKUP_PID" || true
}
setup_ports()
{
SST_PORT="$WSREP_SST_OPT_PORT"
@ -648,51 +636,17 @@ setup_ports()
fi
}
check_port()
{
local PORT="$1"
local UTILS="$2"
local port_info is_util
if [ $lsof_available -ne 0 ]; then
port_info=$(lsof -i ":$PORT" -Pn 2>/dev/null | \
grep -F '(LISTEN)')
is_util=$(echo "$port_info" | \
grep -E "^($UTILS)[^[:space:]]*[[:space:]]+[0-9]+[[:space:]]+")
elif [ $sockstat_available -ne 0 ]; then
port_info=$(sockstat -p "$PORT" 2>/dev/null | \
grep -F 'LISTEN')
is_util=$(echo "$port_info" | \
grep -E "[[:space:]]+($UTILS)[^[:space:]]*[[:space:]]+[0-9]+[[:space:]]+")
elif [ $ss_available -ne 0 ]; then
port_info=$(ss -H -p -n -l "( sport = :$PORT )" 2>/dev/null)
is_util=$(echo "$port_info" | \
grep -E "users:\\(.*\\(\"($UTILS)[^[:space:]]*\".*\<pid=[0-9]+\>.*\\)")
else
wsrep_log_error "unknown sockets utility"
exit 2 # ENOENT
fi
if [ -z "$is_util" ]; then
return 1
fi
return 0
}
# waits ~10 seconds for nc to open the port and then reports ready
# (regardless of timeout)
#
# Waits ~30 seconds for socat or nc to open the port and
# then reports ready, regardless of timeout.
#
wait_for_listen()
{
local PORT="$1"
local ADDR="$2"
local MODULE="$3"
for i in {1..50}
do
if check_port "$PORT" 'socat|nc'
then
for i in {1..150}; do
if check_port "" "$PORT" 'socat|nc'; then
break
fi
sleep 0.2
@ -708,8 +662,8 @@ check_extra()
if [ "$thread_handling" = 'pool-of-threads' ]; then
local eport=$(parse_cnf '--mysqld' 'extra-port')
if [ -n "$eport" ]; then
# mariabackup works only locally, hence,
# setting host to 127.0.0.1 unconditionally:
# mariabackup works only locally.
# Hence, setting host to 127.0.0.1 unconditionally:
wsrep_log_info "SST through extra_port $eport"
INNOEXTRA="$INNOEXTRA --host=127.0.0.1 --port=$eport"
use_socket=0
@ -825,11 +779,12 @@ monitor_process()
local sst_stream_pid=$1
while true ; do
if ! ps -p "$WSREP_SST_OPT_PARENT" &>/dev/null; then
if ! ps -p "$WSREP_SST_OPT_PARENT" >/dev/null 2>&1; then
wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT) terminated unexpectedly."
kill -- -"$WSREP_SST_OPT_PARENT"
exit 32
fi
if ! ps -p "$sst_stream_pid" &>/dev/null; then
if ! ps -p "$sst_stream_pid" >/dev/null 2>&1; then
break
fi
sleep 0.1
@ -839,14 +794,14 @@ monitor_process()
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
if [ "$WSREP_SST_OPT_ROLE" != 'joiner' -a "$WSREP_SST_OPT_ROLE" != 'donor' ]; then
wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}"
wsrep_log_error "Invalid role '$WSREP_SST_OPT_ROLE'"
exit 22
fi
read_cnf
setup_ports
if "$MARIABACKUP_BIN" --help 2>/dev/null | grep -qw -- '--version-check'; then
if "$BACKUP_BIN" --help 2>/dev/null | grep -qw -- '--version-check'; then
disver='--no-version-check'
fi
@ -942,8 +897,8 @@ else
gzip "$newfile"
fi
fi
INNOAPPLY="&> '$INNOAPPLYLOG'"
INNOMOVE="&> '$INNOMOVELOG'"
INNOAPPLY="> '$INNOAPPLYLOG' 2>&1"
INNOMOVE="> '$INNOMOVELOG' 2>&1"
INNOBACKUP="2> '$INNOBACKUPLOG'"
fi
@ -953,9 +908,9 @@ setup_commands()
if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then
mysqld_args="--mysqld-args $WSREP_SST_OPT_MYSQLD"
fi
INNOAPPLY="$MARIABACKUP_BIN --prepare $disver $iapts $INNOEXTRA --target-dir='$DATA' --datadir='$DATA' $mysqld_args $INNOAPPLY"
INNOMOVE="$MARIABACKUP_BIN $WSREP_SST_OPT_CONF --move-back $disver $impts --force-non-empty-directories --target-dir='$DATA' --datadir='${TDATA:-$DATA}' $INNOMOVE"
INNOBACKUP="$MARIABACKUP_BIN $WSREP_SST_OPT_CONF --backup $disver $iopts $tmpopts $INNOEXTRA --galera-info --stream=$sfmt --target-dir='$itmpdir' --datadir='$DATA' $mysqld_args $INNOBACKUP"
INNOAPPLY="$BACKUP_BIN --prepare $disver $iapts $INNOEXTRA --target-dir='$DATA' --datadir='$DATA' $mysqld_args $INNOAPPLY"
INNOMOVE="$BACKUP_BIN $WSREP_SST_OPT_CONF --move-back $disver $impts --force-non-empty-directories --target-dir='$DATA' --datadir='${TDATA:-$DATA}' $INNOMOVE"
INNOBACKUP="$BACKUP_BIN $WSREP_SST_OPT_CONF --backup $disver $iopts $tmpopts $INNOEXTRA --galera-info --stream=$sfmt --target-dir='$itmpdir' --datadir='$DATA' $mysqld_args $INNOBACKUP"
}
get_stream
@ -963,7 +918,7 @@ get_transfer
if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]
then
trap cleanup_donor EXIT
trap cleanup_at_exit EXIT
if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
then
@ -976,12 +931,15 @@ then
tmpdir=$(parse_cnf "$encgroups" 'tmpdir')
if [ -z "$tmpdir" ]; then
xtmpdir="$(mktemp -d)"
tmpopts="--tmpdir='$xtmpdir'"
wsrep_log_info "Using $xtmpdir as mariabackup temporary directory"
else
xtmpdir=$(mktemp '-d' "--tmpdir=$tmpdir")
fi
wsrep_log_info "Using '$xtmpdir' as mariabackup temporary directory"
tmpopts="--tmpdir='$xtmpdir'"
itmpdir="$(mktemp -d)"
wsrep_log_info "Using $itmpdir as mariabackup temporary directory"
wsrep_log_info "Using '$itmpdir' as mariabackup working directory"
usrst=0
if [ -n "$WSREP_SST_OPT_USER" ]; then
@ -1048,25 +1006,29 @@ then
tcmd="$ecmd | $tcmd"
fi
iopts="$iopts --databases-exclude='lost+found'"
iopts="--databases-exclude='lost+found' $iopts"
if [ ${FORCE_FTWRL:-0} -eq 1 ]; then
wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL"
iopts="$iopts --no-backup-locks"
iopts="--no-backup-locks $iopts"
fi
# if compression is enabled for backup files, then add the
# appropriate options to the mariabackup command line:
if [ "$compress" != 'none' ]; then
iopts="$iopts --compress${compress:+=$compress}"
iopts="--compress${compress:+=$compress} $iopts"
if [ -n "$compress_threads" ]; then
iopts="$iopts --compress-threads=$compress_threads"
iopts="--compress-threads=$compress_threads $iopts"
fi
if [ -n "$compress_chunk" ]; then
iopts="$iopts --compress-chunk-size=$compress_chunk"
iopts="--compress-chunk-size=$compress_chunk $iopts"
fi
fi
if [ -n "$backup_threads" ]; then
iopts="--parallel=$backup_threads $iopts"
fi
setup_commands
set +e
timeit "$stagemsg-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
@ -1082,7 +1044,7 @@ then
fi
# mariabackup implicitly writes PID to fixed location in $xtmpdir
MARIABACKUP_PID="$xtmpdir/xtrabackup_pid"
BACKUP_PID="$xtmpdir/xtrabackup_pid"
else # BYPASS FOR IST
@ -1134,6 +1096,10 @@ then
ib_undo_dir="$INNODB_UNDO_DIR"
if [ -n "$backup_threads" ]; then
impts="--parallel=$backup_threads $impts"
fi
stagemsg='Joiner-Recv'
sencrypted=1
@ -1173,7 +1139,7 @@ then
fi
trap sig_joiner_cleanup HUP PIPE INT TERM
trap cleanup_joiner EXIT
trap cleanup_at_exit EXIT
if [ -n "$progress" ]; then
adjust_progress
@ -1196,7 +1162,7 @@ then
recv_joiner "$STATDIR" "$stagemsg-gtid" $stimeout 1 1
if ! ps -p "$WSREP_SST_OPT_PARENT" &>/dev/null
if ! ps -p "$WSREP_SST_OPT_PARENT" >/dev/null 2>&1
then
wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT) terminated unexpectedly."
exit 32
@ -1316,7 +1282,7 @@ then
fi
wsrep_log_info "Preparing the backup at ${DATA}"
wsrep_log_info "Preparing the backup at $DATA"
setup_commands
timeit "mariabackup prepare stage" "$INNOAPPLY"
@ -1327,26 +1293,26 @@ then
MAGIC_FILE="$TDATA/$INFO_FILE"
wsrep_log_info "Moving the backup to ${TDATA}"
wsrep_log_info "Moving the backup to $TDATA"
timeit "mariabackup move stage" "$INNOMOVE"
if [ $? -eq 0 ]; then
wsrep_log_info "Move successful, removing ${DATA}"
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 "Move failed, keeping '$DATA' for further diagnosis"
wsrep_log_error "Check syslog or '$INNOMOVELOG' for details"
exit 22
fi
else
wsrep_log_info "${IST_FILE} received from donor: Running IST"
wsrep_log_info "'$IST_FILE' received from donor: Running IST"
fi
if [ ! -r "$MAGIC_FILE" ]; then
wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable"
wsrep_log_error "SST magic file '$MAGIC_FILE' not found/readable"
exit 2
fi

View File

@ -103,7 +103,7 @@ then
DROP PREPARE stmt;"
fi
MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF "\
MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF_UNQUOTED "\
"$AUTH -h$WSREP_SST_OPT_HOST_UNESCAPED "\
"-P$WSREP_SST_OPT_PORT --disable-reconnect --connect_timeout=10"
@ -140,7 +140,7 @@ then
fi
# NOTE: we don't use --routines here because we're dumping mysql.proc table
MYSQLDUMP="$MYSQLDUMP $WSREP_SST_OPT_CONF $AUTH -S$WSREP_SST_OPT_SOCKET \
MYSQLDUMP="$MYSQLDUMP $WSREP_SST_OPT_CONF_UNQUOTED $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 --events"

View File

@ -1,7 +1,7 @@
#!/bin/bash -ue
# Copyright (C) 2010-2014 Codership Oy
# Copyright (C) 2017-2021 MariaDB
# Copyright (C) 2010-2014 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
@ -19,9 +19,8 @@
# This is a reference script for rsync-based state snapshot tansfer
RSYNC_PID= # rsync pid file
RSYNC_CONF= # rsync configuration file
RSYNC_REAL_PID= # rsync process id
RSYNC_REAL_PID=0 # rsync process id
STUNNEL_REAL_PID=0 # stunnel process id
OS="$(uname)"
[ "$OS" = 'Darwin' ] && export -n LD_LIBRARY_PATH
@ -36,95 +35,95 @@ wsrep_check_programs rsync
cleanup_joiner()
{
wsrep_log_info "Joiner cleanup. rsync PID: $RSYNC_REAL_PID"
[ "0" != "$RSYNC_REAL_PID" ] && \
kill $RSYNC_REAL_PID && \
sleep 0.5 && \
kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || :
[ -f "$RSYNC_CONF" ] && rm -f "$RSYNC_CONF"
[ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF"
[ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID"
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
[ -f "$RSYNC_PID" ] && rm -f "$RSYNC_PID"
local failure=0
wsrep_log_info "Joiner cleanup: rsync PID=$RSYNC_REAL_PID, stunnel PID=$STUNNEL_REAL_PID"
if [ -n "$STUNNEL" ]; then
if cleanup_pid $STUNNEL_REAL_PID "$STUNNEL_PID" "$STUNNEL_CONF"; then
if [ $RSYNC_REAL_PID -eq 0 ]; then
if [ -r "$RSYNC_PID" ]; then
RSYNC_REAL_PID=$(cat "$RSYNC_PID" 2>/dev/null)
if [ -z "$RSYNC_REAL_PID" ]; then
RSYNC_REAL_PID=0
fi
fi
fi
else
wsrep_log_warning "stunnel cleanup failed."
failure=1
fi
fi
if [ $failure -eq 0 ]; then
if cleanup_pid $RSYNC_REAL_PID "$RSYNC_PID" "$RSYNC_CONF"; then
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
else
wsrep_log_warning "rsync cleanup failed."
fi
fi
wsrep_log_info "Joiner cleanup done."
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
wsrep_cleanup_progress_file
fi
}
# Check whether rsync process is still running.
check_pid()
{
local pid_file="$1"
[ -r "$pid_file" ] && ps -p $(cat "$pid_file") 2>&1 >/dev/null
}
check_pid_and_port()
{
local pid_file="$1"
local rsync_pid=$2
local rsync_addr="$3"
local rsync_port="$4"
local pid=$2
local addr="$3"
local port="$4"
if [ -z "$rsync_port" -o -z "$rsync_addr" -o -z "$rsync_pid" ]; then
wsrep_log_error "check_pid_and_port(): bad arguments"
exit 2 # ENOENT
fi
local utils='rsync|stunnel'
local port_info is_rsync
if ! check_port "$pid" "$port" "$utils"; then
local port_info
local busy=0
if [ $lsof_available -ne 0 ]; then
port_info=$(lsof -i ":$rsync_port" -Pn 2>/dev/null | \
grep -F '(LISTEN)')
is_rsync=$(echo "$port_info" | \
grep -E "^(rsync|stunnel)[^[:space:]]*[[:space:]]+$rsync_pid[[:space:]]+")
elif [ $sockstat_available -ne 0 ]; then
port_info=$(sockstat -p "$rsync_port" 2>/dev/null | \
grep -F 'LISTEN')
is_rsync=$(echo "$port_info" | \
grep -E "[[:space:]]+(rsync|stunnel)[^[:space:]]*[[:space:]]+$rsync_pid[[:space:]]+")
elif [ $ss_available -ne 0 ]; then
port_info=$(ss -H -p -n -l "( sport = :$rsync_port )" 2>/dev/null)
is_rsync=$(echo "$port_info" | \
grep -E "users:\\(.*\\(\"(rsync|stunnel)[^[:space:]]*\".*\<pid=$rsync_pid\>.*\\)")
else
wsrep_log_error "unknown sockets utility"
exit 2 # ENOENT
fi
if [ -z "$is_rsync" ]; then
local is_listening_all
if [ $lsof_available -ne 0 ]; then
is_listening_all=$(echo "$port_info" | \
grep -E "[[:space:]](\\*|\\[?::\\]?):$rsync_port[[:space:]]")
port_info=$(lsof -Pnl -i ":$port" 2>/dev/null | \
grep -F '(LISTEN)')
echo "$port_info" | \
grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port[[:space:]]" && busy=1
else
if [ $sockstat_available -eq 0 ]; then
port_info=$(echo "$port_info" | grep -q -F 'users:(')
local filter='([^[:space:]]+[[:space:]]+){4}[^[:space:]]+'
if [ $sockstat_available -eq 1 ]; then
port_info=$(sockstat -p "$port" 2>/dev/null | \
grep -E '[[:space:]]LISTEN' | grep -o -E "$filter")
else
port_info=$(ss -nlpH "( sport = :$port )" 2>/dev/null | \
grep -F 'users:(' | grep -o -E "$filter")
fi
port_info=$(echo "$port_info" | \
grep -E "[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+" -o)
is_listening_all=$(echo "$port_info" | \
grep -E "[[:space:]](\\*|\\[?::\\]?):$rsync_port\$")
echo "$port_info" | \
grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port\$" && busy=1
fi
local is_listening_addr=$(echo "$port_info" | \
grep -w -F -- "$rsync_addr:$rsync_port")
if [ -z "$is_listening_addr" ]; then
is_listening_addr=$(echo "$port_info" | \
grep -w -F "[$rsync_addr]:$rsync_port")
if [ $busy -eq 0 ]; then
if echo "$port_info" | grep -qw -F "[$addr]:$port" || \
echo "$port_info" | grep -qw -F -- "$addr:$port"
then
busy=1
fi
fi
if [ -n "$is_listening_all" -o -n "$is_listening_addr" ]; then
wsrep_log_error "rsync or stunnel daemon port '$rsync_port' " \
if [ $busy -eq 0 ]; then
return 1
fi
if ! check_port "$pid" "$port" "$utils"; then
wsrep_log_error "rsync or stunnel daemon port '$port' " \
"has been taken by another program"
exit 16 # EBUSY
fi
return 1
fi
check_pid "$pid_file" && [ $(cat "$pid_file") -eq $rsync_pid ]
check_pid "$pid_file" && [ $CHECK_PID -eq $pid ]
}
STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf"
STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid"
MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete"
@ -201,6 +200,8 @@ FILTER="-f '- /lost+found'
-f '- /.zfs'
-f '- /.fseventsd'
-f '- /.Trashes'
-f '- /.pid'
-f '- /.conf'
-f '+ /wsrep_sst_binlog.tar'
-f '- $INNODB_DATA_HOME_DIR/ib_lru_dump'
-f '- $INNODB_DATA_HOME_DIR/ibdata*'
@ -266,7 +267,7 @@ then
else
# check if the address is an ip-address (v4 or v6):
if echo "$WSREP_SST_OPT_HOST_UNESCAPED" | \
grep -q -E '^([0-9]+(\.[0-9]+){3,3}|[0-9a-fA-F]*(\:[0-9a-fA-F]*)+)$'
grep -q -E '^([0-9]+(\.[0-9]+){3}|[0-9a-fA-F]*(\:[0-9a-fA-F]*)+)$'
then
CHECK_OPT="checkIP = $WSREP_SST_OPT_HOST_UNESCAPED"
else
@ -303,10 +304,10 @@ then
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
[ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE"
[ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID"
if [ -n "$STUNNEL" ]
then
[ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID"
cat << EOF > "$STUNNEL_CONF"
key = $SSTKEY
cert = $SSTCERT
@ -321,6 +322,8 @@ ${VERIFY_OPT}
${CHECK_OPT}
${CHECK_OPT_LOCAL}
EOF
else
[ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF"
fi
if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
@ -329,13 +332,8 @@ EOF
FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed"
ERROR="$WSREP_SST_OPT_DATA/sst_error"
rm -rf "$FLUSHED"
rm -rf "$ERROR"
# Use deltaxfer only for WAN
inv=$(basename "$0")
[ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \
|| WHOLE_FILE_OPT="--whole-file"
[ -f "$FLUSHED" ] && rm -f "$FLUSHED"
[ -f "$ERROR" ] && rm -f "$ERROR"
echo "flush tables"
@ -350,15 +348,14 @@ EOF
if [ -f "$ERROR" ]
then
# Flush tables operation failed.
rm -rf "$ERROR"
rm -f "$ERROR"
exit 255
fi
sleep 0.2
done
STATE=$(cat "$FLUSHED")
rm -rf "$FLUSHED"
rm -f "$FLUSHED"
sync
@ -385,6 +382,13 @@ EOF
cd "$OLD_PWD"
fi
# Use deltaxfer only for WAN
inv=$(basename "$0")
WHOLE_FILE_OPT=""
if [ "${inv%wsrep_sst_rsync_wan*}" != "$inv" ]; then
WHOLE_FILE_OPT="--whole-file"
fi
# first, the normal directories, so that we can detect incompatible protocol
RC=0
eval rsync ${STUNNEL:+"'--rsh=$STUNNEL'"} \
@ -436,16 +440,18 @@ EOF
fi
# then, we parallelize the transfer of database directories,
# use . so that path concatenation works:
# use '.' so that path concatenation works:
cd "$WSREP_SST_OPT_DATA"
count=1
[ "$OS" = 'Linux' ] && count=$(grep -c processor /proc/cpuinfo)
[ "$OS" = 'Darwin' -o "$OS" = 'FreeBSD' ] && count=$(sysctl -n hw.ncpu)
backup_threads=$(parse_cnf "--mysqld|sst" 'backup-threads')
if [ -z "$backup_threads" ]; then
get_proc
backup_threads=$nproc
fi
find . -maxdepth 1 -mindepth 1 -type d -not -name 'lost+found' \
-not -name '.zfs' -print0 | xargs -I{} -0 -P $count \
-not -name '.zfs' -print0 | xargs -I{} -0 -P $backup_threads \
rsync ${STUNNEL:+--rsh="$STUNNEL"} \
--owner --group --perms --links --specials \
--ignore-times --inplace --recursive --delete --quiet \
@ -484,35 +490,52 @@ EOF
echo "done $STATE"
if [ -n "$STUNNEL" ]; then
[ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF"
[ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID"
fi
elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]
then
check_sockets_utils
touch "$SST_PROGRESS_FILE"
MYSQLD_PID="$WSREP_SST_OPT_PARENT"
MODULE="rsync_sst"
RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid"
# give some time for lingering rsync from previous SST to complete
# give some time for lingering stunnel from previous SST to complete
check_round=0
while check_pid "$RSYNC_PID" && [ $check_round -lt 10 ]
while check_pid "$STUNNEL_PID" 1
do
wsrep_log_info "lingering rsync daemon found at startup, waiting for it to exit"
wsrep_log_info "lingering stunnel daemon found at startup, waiting for it to exit"
check_round=$(( check_round + 1 ))
if [ $check_round -eq 10 ]; then
wsrep_log_error "stunnel daemon already running."
exit 114 # EALREADY
fi
sleep 1
done
if check_pid "$RSYNC_PID"
then
wsrep_log_error "rsync daemon already running."
exit 114 # EALREADY
fi
MODULE="rsync_sst"
RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid"
RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf"
# give some time for lingering rsync from previous SST to complete
check_round=0
while check_pid "$RSYNC_PID" 1
do
wsrep_log_info "lingering rsync daemon found at startup, waiting for it to exit"
check_round=$(( check_round + 1 ))
if [ $check_round -eq 10 ]; then
wsrep_log_error "rsync daemon already running."
exit 114 # EALREADY
fi
sleep 1
done
[ -f "$RSYNC_PID" ] && rm -f "$RSYNC_PID"
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
[ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE"
if [ -z "$STUNNEL" ]; then
[ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF"
fi
ADDR="$WSREP_SST_OPT_ADDR"
RSYNC_PORT="$WSREP_SST_OPT_PORT"
RSYNC_ADDR="$WSREP_SST_OPT_HOST"
@ -522,7 +545,7 @@ then
trap "exit 3" INT TERM ABRT
trap cleanup_joiner EXIT
RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf"
touch "$SST_PROGRESS_FILE"
if [ -n "${MYSQL_TMP_DIR:-}" ]; then
SILENT="log file = $MYSQL_TMP_DIR/rsyncd.log"
@ -545,18 +568,18 @@ $SILENT
path = $INNODB_DATA_HOME_DIR
EOF
# rm -rf "$DATA"/ib_logfile* # we don't want old logs around
# rm -rf "$DATA/ib_logfile"* # we don't want old logs around
# If the IP is local listen only in it
# If the IP is local, listen only on it:
if is_local_ip "$RSYNC_ADDR_UNESCAPED"
then
RSYNC_EXTRA_ARGS="--address $RSYNC_ADDR_UNESCAPED"
STUNNEL_ACCEPT="$RSYNC_ADDR_UNESCAPED:$RSYNC_PORT"
else
# Not local, possibly a NAT, listen on all interfaces
# Not local, possibly a NAT, listen on all interfaces:
RSYNC_EXTRA_ARGS=""
STUNNEL_ACCEPT="$RSYNC_PORT"
# Overwrite address with all
# Overwrite address with all:
RSYNC_ADDR="*"
fi
@ -564,8 +587,9 @@ EOF
then
rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" $RSYNC_EXTRA_ARGS &
RSYNC_REAL_PID=$!
TRANSFER_REAL_PID="$RSYNC_REAL_PID"
TRANSFER_PID=$RSYNC_PID
else
[ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID"
# Let's check if the path to the config file contains a space?
if [ "${RSYNC_CONF#* }" = "$RSYNC_CONF" ]; then
cat << EOF > "$STUNNEL_CONF"
@ -606,15 +630,11 @@ execargs = $SHELL -c \$RSYNC_CMD
EOF
fi
stunnel "$STUNNEL_CONF" &
RSYNC_REAL_PID=$!
RSYNC_PID="$STUNNEL_PID"
STUNNEL_REAL_PID=$!
TRANSFER_REAL_PID="$STUNNEL_REAL_PID"
TRANSFER_PID=$STUNNEL_PID
fi
until check_pid_and_port "$RSYNC_PID" "$RSYNC_REAL_PID" "$RSYNC_ADDR_UNESCAPED" "$RSYNC_PORT"
do
sleep 0.2
done
if [ "${SSLMODE#VERIFY}" != "$SSLMODE" ]
then # backward-incompatible behavior
CN=""
@ -635,19 +655,26 @@ EOF
ADDR="$CN:$MY_SECRET@$WSREP_SST_OPT_HOST"
else
MY_SECRET="" # for check down in recv_joiner()
ADDR=$WSREP_SST_OPT_HOST
ADDR="$WSREP_SST_OPT_HOST"
fi
until check_pid_and_port "$TRANSFER_PID" $TRANSFER_REAL_PID "$RSYNC_ADDR_UNESCAPED" "$RSYNC_PORT"
do
sleep 0.2
done
echo "ready $ADDR:$RSYNC_PORT/$MODULE"
MYSQLD_PID="$WSREP_SST_OPT_PARENT"
# wait for SST to complete by monitoring magic file
while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \
ps -p $MYSQLD_PID >/dev/null
while [ ! -r "$MAGIC_FILE" ] && check_pid "$TRANSFER_PID" && \
ps -p $MYSQLD_PID >/dev/null 2>&1
do
sleep 1
done
if ! ps -p $MYSQLD_PID >/dev/null
if ! ps -p $MYSQLD_PID >/dev/null 2>&1
then
wsrep_log_error \
"Parent mysqld process (PID: $MYSQLD_PID) terminated unexpectedly."
@ -698,7 +725,7 @@ EOF
echo "rsync process ended without creating '$MAGIC_FILE'"
fi
wsrep_cleanup_progress_file
# wsrep_cleanup_progress_file
# cleanup_joiner
else
wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'"

File diff suppressed because it is too large Load Diff

View File

@ -97,8 +97,9 @@ get_keys()
fi
if [[ $encrypt -eq 0 ]];then
if $MY_PRINT_DEFAULTS xtrabackup | grep -q encrypt;then
wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
if [ -n "$ealgo" -o -n "$ekey" -o -n "$ekeyfile" ]; then
wsrep_log_error "Options for encryption are specified, " \
"but encryption itself is disabled. SST may fail."
fi
return
fi
@ -324,12 +325,6 @@ cleanup_joiner()
fi
}
check_pid()
{
local pid_file="$1"
[ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1
}
cleanup_donor()
{
# Since this is invoked just after exit NNN
@ -339,12 +334,11 @@ cleanup_donor()
fi
if [[ -n "$XTRABACKUP_PID" ]];then
if check_pid "$XTRABACKUP_PID"
if check_pid "$XTRABACKUP_PID" 1
then
wsrep_log_error "xtrabackup process is still running. Killing... "
kill_xtrabackup
cleanup_pid $CHECK_PID "$XTRABACKUP_PID"
fi
rm -f "$XTRABACKUP_PID"
fi
rm -f "${DATA}/${IST_FILE}"
@ -355,13 +349,6 @@ cleanup_donor()
fi
}
kill_xtrabackup()
{
local PID=$(cat "$XTRABACKUP_PID")
[ -n "$PID" -a $PID -ne 0 ] && kill $PID && (kill $PID && kill -9 $PID) || :
rm -f "$XTRABACKUP_PID"
}
# waits ~10 seconds for nc to open the port and then reports ready
# (regardless of timeout)
wait_for_listen()