mariadb/scripts/wsrep_sst_mariabackup.sh
Julius Goryavsky fd9a11d8a5 MDEV-35749: Add support for --use-memory option for SST with mariabackup
Mariabackup (mariadb-backup) supports the --use-memory option that
sets the buffer pool size for innodb. However, current SST scripts
do not use this option. This commit adds support for this option,
the value for which can be specified via the "use_memory" parameter
in the configuration file in the [sst], [mariabackup] or [xtrabackup]
sections (supported only for compatibility with old configurations).

In addition, if the innodb_buffer_pool_size option is specified in
the user configuration (in the main server configuration sections)
or passed to the SST scripts or the server via arguments, its value
is also passed to mariadb-backup as the value for the --use-memory
option.

A new section name [mariabackup] has also been added, which can
be used instead of the deprecated [xtrabackup] (the section name
"mariabackup" was specified in the documentation, but was not
actually supported by SST scripts before this commit).
2025-01-06 01:43:42 +01:00

1538 lines
49 KiB
Bash

#!/usr/bin/env bash
set -ue
# Copyright (C) 2017-2024 MariaDB
# Copyright (C) 2013 Percona Inc
#
# 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
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
# MA 02110-1335 USA.
# This is a reference script for mariadb-backup-based state snapshot transfer.
# Documentation:
# https://mariadb.com/kb/en/mariabackup-overview/
# Make sure to read that before proceeding!
. $(dirname "$0")/wsrep_sst_common
BACKUP_BIN=$(commandex 'mariadb-backup')
if [ -z "$BACKUP_BIN" ]; then
wsrep_log_error 'mariadb-backup binary not found in path'
exit 42
fi
BACKUP_PID=""
INFO_FILE='xtrabackup_galera_info'
DONOR_INFO_FILE='donor_galera_info'
IST_FILE='xtrabackup_ist'
MAGIC_FILE="$DATA/$INFO_FILE"
DONOR_MAGIC_FILE="$DATA/$DONOR_INFO_FILE"
ealgo=""
eformat=""
ekey=""
ekeyfile=""
encrypt=0
ssyslog=""
ssystag=""
tcert=""
tcap=""
tpem=""
tkey=""
tmode=""
sockopt=""
progress=""
ttime=0
totime=0
lsn=""
ecmd=""
rlimit=""
# Initially
stagemsg="$WSREP_SST_OPT_ROLE"
cpat=""
speciald=1
ib_home_dir=""
ib_log_dir=""
ib_undo_dir=""
ar_log_dir=""
sfmt=""
strmcmd=""
tfmt=""
tcmd=""
payload=0
pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p'"
pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE"
uextra=0
disver=""
STATDIR=""
tmpopts=""
itmpdir=""
xtmpdir=""
scomp=""
sdecomp=""
ssl_dhparams=""
compress='none'
compress_chunk=""
compress_threads=""
backup_threads=""
encrypt_threads=""
encrypt_chunk=""
readonly SECRET_TAG='secret'
readonly TOTAL_TAG='total'
# Required for backup locks
# For backup locks it is 1 sent by joiner
sst_ver=1
INNOAPPLYLOG="$DATA/mariabackup.prepare.log"
INNOMOVELOG="$DATA/mariabackup.move.log"
INNOBACKUPLOG="$DATA/mariabackup.backup.log"
timeit()
{
local stage="$1"
shift
local cmd="$@"
local x1 x2 took extcode
if [ $ttime -eq 1 ]; then
x1=$(date +%s)
fi
wsrep_log_info "Evaluating $cmd"
eval $cmd
extcode=$?
if [ $ttime -eq 1 ]; then
x2=$(date +%s)
took=$(( x2-x1 ))
wsrep_log_info "NOTE: $stage took $took seconds"
totime=$(( totime+took ))
fi
return $extcode
}
get_keys()
{
# $encrypt -eq 1 is for internal purposes only
if [ $encrypt -ge 2 -o $encrypt -eq -1 ]; then
return
fi
if [ $encrypt -eq 0 ]; then
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
if [ "$sfmt" = 'tar' ]; then
wsrep_log_info "NOTE: key-based encryption (encrypt=1)" \
"cannot be enabled with tar format"
encrypt=-1
return
fi
wsrep_log_info "Key based encryption enabled in my.cnf"
if [ -z "$ealgo" ]; then
wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out"
exit 3
fi
if [ -z "$ekey" -a ! -r "$ekeyfile" ]; then
wsrep_log_error "FATAL: Either key must be specified" \
"or keyfile must be readable"
exit 3
fi
if [ "$eformat" = 'openssl' ]; then
get_openssl
if [ -z "$OPENSSL_BINARY" ]; then
wsrep_log_error "If encryption using the openssl is enabled," \
"then you need to install openssl"
exit 2
fi
ecmd="'$OPENSSL_BINARY' enc -$ealgo"
if "$OPENSSL_BINARY" enc -help 2>&1 | grep -qw -F -- '-pbkdf2'; then
ecmd="$ecmd -pbkdf2"
elif "$OPENSSL_BINARY" enc -help 2>&1 | grep -qw -F -- '-iter'; then
ecmd="$ecmd -iter 1"
elif "$OPENSSL_BINARY" enc -help 2>&1 | grep -qw -F -- '-md'; then
ecmd="$ecmd -md sha256"
fi
if [ -z "$ekey" ]; then
ecmd="$ecmd -kfile '$ekeyfile'"
else
ecmd="$ecmd -k '$ekey'"
fi
elif [ "$eformat" = 'xbcrypt' ]; then
if [ -z "$(commandex xbcrypt)" ]; then
wsrep_log_error "If encryption using the xbcrypt is enabled," \
"then you need to install xbcrypt"
exit 2
fi
wsrep_log_info "NOTE: xbcrypt-based encryption," \
"supported only from Xtrabackup 2.1.4"
if [ -z "$ekey" ]; then
ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key-file='$ekeyfile'"
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
fi
[ "$WSREP_SST_OPT_ROLE" = 'joiner' ] && ecmd="$ecmd -d"
stagemsg="$stagemsg-XB-Encrypted"
}
get_socat_ver()
{
[ -n "${SOCAT_VERSION+x}" ] && return
# Determine the socat version
SOCAT_VERSION=$(socat -V 2>&1 | \
grep -m1 -owE '[0-9]+(\.[0-9]+)+' | \
head -n1 || :)
if [ -z "$SOCAT_VERSION" ]; then
wsrep_log_error "******** FATAL ERROR ******************"
wsrep_log_error "* Cannot determine the socat version. *"
wsrep_log_error "***************************************"
exit 2
fi
}
get_transfer()
{
if [ "$tfmt" = 'nc' ]; then
wsrep_log_info "Using netcat as streamer"
wsrep_check_programs nc
tcmd='nc'
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
if nc -h 2>&1 | grep -q -F 'ncat'; then
wsrep_log_info "Using Ncat as streamer"
tcmd="$tcmd -l"
elif nc -h 2>&1 | grep -qw -F -- '-d'; then
wsrep_log_info "Using Debian netcat as streamer"
tcmd="$tcmd -dl"
if [ $WSREP_SST_OPT_HOST_IPv6 -eq 1 ]; then
# When host is not explicitly specified (when only the port
# is specified) netcat can only bind to an IPv4 address if
# the "-6" option is not explicitly specified:
tcmd="$tcmd -6"
fi
else
wsrep_log_info "Using traditional netcat as streamer"
tcmd="$tcmd -l -p"
fi
tcmd="$tcmd $SST_PORT"
else
# Check to see if netcat supports the '-N' flag.
# -N Shutdown the network socket after EOF on stdin
# If it supports the '-N' flag, then we need to use the '-N'
# flag, otherwise the transfer will stay open after the file
# transfer and cause the command to timeout.
# Older versions of netcat did not need this flag and will
# return an error if the flag is used.
if nc -h 2>&1 | grep -qw -F -- '-N'; then
tcmd="$tcmd -N"
wsrep_log_info "Using nc -N"
fi
# netcat doesn't understand [] around IPv6 address
if nc -h 2>&1 | grep -q -F 'ncat'; then
wsrep_log_info "Using Ncat as streamer"
elif nc -h 2>&1 | grep -qw -F -- '-d'; then
wsrep_log_info "Using Debian netcat as streamer"
else
wsrep_log_info "Using traditional netcat as streamer"
tcmd="$tcmd -q0"
fi
tcmd="$tcmd $WSREP_SST_OPT_HOST_UNESCAPED $SST_PORT"
fi
else
tfmt='socat'
wsrep_log_info "Using socat as streamer"
wsrep_check_programs socat
if [ -n "$sockopt" ]; then
sockopt=$(trim_string "$sockopt" ',')
if [ -n "$sockopt" ]; then
sockopt=",$sockopt"
fi
fi
# Add an option for ipv6 if needed:
if [ $WSREP_SST_OPT_HOST_IPv6 -eq 1 ]; then
# If sockopt contains 'pf=ip6' somewhere in the middle,
# this will not interfere with socat, but exclude the trivial
# cases when sockopt contains 'pf=ip6' as prefix or suffix:
if [ "$sockopt" = "${sockopt#,pf=ip6,}" -a \
"$sockopt" = "${sockopt%,pf=ip6}" ]
then
sockopt=",pf=ip6$sockopt"
fi
fi
if [ $encrypt -lt 2 ]; then
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
tcmd="socat -u TCP-LISTEN:$SST_PORT,reuseaddr$sockopt stdio"
else
tcmd="socat -u stdio TCP:$REMOTEIP:$SST_PORT$sockopt"
fi
return
fi
if ! socat -V | grep -q -F 'WITH_OPENSSL 1'; then
wsrep_log_error "******** FATAL ERROR ************************************************ "
wsrep_log_error "* Encryption requested, but socat is not OpenSSL enabled (encrypt=$encrypt) *"
wsrep_log_error "********************************************************************* "
exit 2
fi
local action='Decrypting'
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
tcmd="socat -u openssl-listen:$SST_PORT,reuseaddr"
else
local addr="$REMOTEIP:$SST_PORT"
tcmd="socat -u stdio openssl-connect:$addr"
action='Encrypting'
get_socat_ver
if ! check_for_version "$SOCAT_VERSION" '1.7.4.1'; then
if check_for_version "$SOCAT_VERSION" '1.7.3.3'; then
# Workaround for a bug known as 'Red Hat issue 1870279'
# (connection reset by peer) in socat versions 1.7.3.3
# to 1.7.4.0:
tcmd="socat stdio openssl-connect:$addr,linger=10"
wsrep_log_info \
"Use workaround for socat $SOCAT_VERSION bug"
fi
fi
if check_for_version "$SOCAT_VERSION" '1.7.4'; then
tcmd="$tcmd,no-sni=1"
fi
fi
if [ "${sockopt#*,dhparam=}" = "$sockopt" ]; then
if [ -z "$ssl_dhparams" ]; then
get_socat_ver
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
fi
CN_option=",commonname=''"
if [ $encrypt -eq 2 ]; then
wsrep_log_info \
"Using openssl based encryption with socat: with crt and pem"
if [ -z "$tpem" -o -z "$tcert$tcap" ]; then
wsrep_log_error \
"Both PEM file and CRT file (or path) are required"
exit 22
fi
verify_ca_matches_cert "$tpem" "$tcert" "$tcap"
tcmd="$tcmd,cert='$tpem'"
if [ -n "$tcert" ]; then
tcmd="$tcmd,cafile='$tcert'"
fi
if [ -n "$tcap" ]; then
tcmd="$tcmd,capath='$tcap'"
fi
stagemsg="$stagemsg-OpenSSL-Encrypted-2"
wsrep_log_info "$action with cert='$tpem', ca='$tcert', capath='$tcap'"
elif [ $encrypt -eq 3 -o $encrypt -eq 4 ]; then
wsrep_log_info \
"Using openssl based encryption with socat: with key and crt"
if [ -z "$tpem" -o -z "$tkey" ]; then
wsrep_log_error "Both the certificate file (or path) and" \
"the key file are required"
exit 22
fi
verify_cert_matches_key "$tpem" "$tkey"
stagemsg="$stagemsg-OpenSSL-Encrypted-3"
if [ -z "$tcert$tcap" ]; then
if [ $encrypt -eq 4 ]; then
wsrep_log_error \
"Peer certificate file (or path) required if encrypt=4"
exit 22
fi
# no verification
CN_option=""
tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0"
wsrep_log_info \
"$action with cert='$tpem', key='$tkey', verify=0"
else
# CA verification
verify_ca_matches_cert "$tpem" "$tcert" "$tcap"
if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then
CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'"
elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' -o $encrypt -eq 4 ]
then
CN_option=",commonname=''"
elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then
CN_option=',commonname=localhost'
else
CN_option=",commonname='$WSREP_SST_OPT_HOST_UNESCAPED'"
fi
tcmd="$tcmd,cert='$tpem',key='$tkey'"
if [ -n "$tcert" ]; then
tcmd="$tcmd,cafile='$tcert'"
fi
if [ -n "$tcap" ]; then
tcmd="$tcmd,capath='$tcap'"
fi
wsrep_log_info "$action with cert='$tpem', key='$tkey'," \
"ca='$tcert', capath='$tcap'"
fi
else
wsrep_log_info "Unknown encryption mode: encrypt=$encrypt"
exit 22
fi
tcmd="$tcmd$CN_option$sockopt"
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
tcmd="$tcmd stdio"
fi
fi
}
get_footprint()
{
cd "$DATA_DIR"
local payload_data
if [ "$OS" = 'Linux' ]; then
payload_data=$(find $findopt . \
-regex '.*undo[0-9]+$\|.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' \
-type f -print0 | du --files0-from=- --bytes -c -s | \
awk 'END { print $1 }')
else
payload_data=$(find $findopt . \
-regex '.*undo[0-9]+$|.*\.ibd$|.*\.MYI$\.*\.MYD$|.*ibdata1$' \
-type f -print0 | xargs -0 stat -f '%z' | \
awk '{ sum += $1 } END { print sum }')
fi
local payload_undo=0
if [ -n "$ib_undo_dir" -a "$ib_undo_dir" != '.' -a \
"$ib_undo_dir" != "$DATA_DIR" -a -d "$ib_undo_dir" ]
then
cd "$ib_undo_dir"
if [ "$OS" = 'Linux' ]; then
payload_undo=$(find . -regex '.*undo[0-9]+$' -type f -print0 | \
du --files0-from=- --bytes -c -s | awk 'END { print $1 }')
else
payload_undo=$(find . -regex '.*undo[0-9]+$' -type f -print0 | \
xargs -0 stat -f '%z' | awk '{ sum += $1 } END { print sum }')
fi
fi
cd "$OLD_PWD"
wsrep_log_info \
"SST footprint estimate: data: $payload_data, undo: $payload_undo"
payload=$(( payload_data+payload_undo ))
if [ "$compress" != 'none' ]; then
# QuickLZ has around 50% compression ratio
# When compression/compaction used, the progress is only an approximate.
payload=$(( payload*1/2 ))
fi
if [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then
# report to parent the total footprint of the SST
echo "$TOTAL_TAG $payload"
fi
adjust_progress
}
adjust_progress()
{
pcmd=""
rcmd=""
[ "$progress" = 'none' ] && return
rlimitopts=""
if [ -n "$rlimit" -a "$WSREP_SST_OPT_ROLE" = 'donor' ]; then
wsrep_log_info "Rate-limiting SST to $rlimit"
rlimitopts=" -L $rlimit"
fi
if [ -n "$progress" ]; then
# Backward compatibility: user-configured progress output
pcmd="pv $pvopts$rlimitopts"
if [ -z "${PV_FORMAT+x}" ]; then
PV_FORMAT=0
pv --help | grep -qw -F -- '-F' && PV_FORMAT=1
fi
if [ $PV_FORMAT -eq 1 ]; then
pcmd="$pcmd $pvformat"
fi
if [ $payload -ne 0 ]; then
pcmd="$pcmd -s $payload"
fi
if [ "$progress" != '1' ]; then
if [ -e "$progress" ]; then
pcmd="$pcmd 2>>'$progress'"
else
pcmd="$pcmd 2>'$progress'"
fi
fi
elif [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then
# Default progress output parseable by parent
pcmd="pv -f -i 1 -n -b$rlimitopts"
# read progress data, add tag and post to stdout
# for the parent
rcmd="stdbuf -oL tr '\r' '\n' | xargs -n1 echo complete"
elif [ -n "$rlimitopts" ]; then
# Rate-limiting only, when rlimit is non-zero
pcmd="pv -q$rlimitopts"
fi
}
bkgroups='sst|xtrabackup|mariabackup'
encgroups="--mysqld|$bkgroups"
read_cnf()
{
sfmt=$(parse_cnf sst streamfmt 'mbstream')
tfmt=$(parse_cnf sst transferfmt 'socat')
encrypt=$(parse_cnf "$encgroups" 'encrypt' 0)
tmode=$(parse_cnf "$encgroups" 'ssl-mode' 'DISABLED' | \
tr '[[:lower:]]' '[[:upper:]]')
case "$tmode" in
'VERIFY_IDENTITY'|'VERIFY_CA'|'REQUIRED'|'DISABLED')
;;
*)
wsrep_log_error "Unrecognized ssl-mode option: '$tmode'"
exit 22 # EINVAL
;;
esac
if [ $encrypt -eq 0 -o $encrypt -ge 2 ]; then
if [ "$tmode" != 'DISABLED' -o $encrypt -ge 2 ]; then
check_server_ssl_config
fi
if [ "$tmode" != 'DISABLED' ]; then
if [ 0 -eq $encrypt -a -n "$tpem" -a -n "$tkey" ]
then
encrypt=3 # enable cert/key SSL encyption
# avoid CA verification if not set explicitly:
# nodes may happen to have different CA if self-generated,
# zeroing up tcert and tcap does the trick:
if [ "${tmode#VERIFY}" = "$tmode" ]; then
tcert=""
tcap=""
fi
fi
fi
elif [ $encrypt -eq 1 ]; then
ealgo=$(parse_cnf "$encgroups" 'encrypt-algo')
eformat=$(parse_cnf "$encgroups" 'encrypt-format' 'openssl')
ekey=$(parse_cnf "$encgroups" 'encrypt-key')
# The keyfile should be read only when the key
# is not specified or empty:
if [ -z "$ekey" ]; then
ekeyfile=$(parse_cnf "$encgroups" 'encrypt-key-file')
fi
fi
wsrep_log_info "SSL configuration: CA='$tcert', CAPATH='$tcap'," \
"CERT='$tpem', KEY='$tkey', MODE='$tmode'," \
"encrypt='$encrypt'"
if [ $encrypt -ge 2 ]; then
ssl_dhparams=$(parse_cnf "$encgroups" 'ssl-dhparams')
fi
sockopt=$(parse_cnf sst sockopt)
progress=$(parse_cnf sst progress)
ttime=$(parse_cnf sst time 0)
cpat='.*\.pem$\|.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$'
[ "$OS" = 'FreeBSD' ] && cpat=$(echo "$cpat" | sed 's/\\|/|/g')
cpat=$(parse_cnf sst cpat "$cpat")
scomp=$(parse_cnf sst compressor)
sdecomp=$(parse_cnf sst decompressor)
rlimit=$(parse_cnf sst rlimit)
uextra=$(parse_cnf sst use-extra 0)
speciald=$(parse_cnf sst 'sst-special-dirs' 1)
iopts=$(parse_cnf "$bkgroups" 'inno-backup-opts')
iapts=$(parse_cnf "$bkgroups" 'inno-apply-opts')
impts=$(parse_cnf "$bkgroups" 'inno-move-opts')
use_memory=$(parse_cnf "$bkgroups" 'use-memory')
if [ -z "$use_memory" ]; then
if [ -n "$INNODB_BUFFER_POOL_SIZE" ]; then
use_memory="$INNODB_BUFFER_POOL_SIZE"
else
use_memory=$(parse_cnf '--mysqld' 'innodb-buffer-pool-size')
fi
fi
stimeout=$(parse_cnf sst 'sst-initial-timeout' 300)
ssyslog=$(parse_cnf sst 'sst-syslog' 0)
ssystag=$(parse_cnf mysqld_safe 'syslog-tag' "${SST_SYSLOG_TAG:-}")
ssystag="$ssystag-"
sstlogarchive=$(parse_cnf sst 'sst-log-archive' 1)
sstlogarchivedir=""
if [ $sstlogarchive -ne 0 ]; then
sstlogarchivedir=$(parse_cnf sst sst-log-archive-dir \
'/tmp/sst_log_archive')
if [ -n "$sstlogarchivedir" ]; then
sstlogarchivedir=$(trim_dir "$sstlogarchivedir")
fi
fi
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
ssyslog=$(in_config 'mysqld_safe' 'syslog')
fi
if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then
compress=$(parse_cnf "$encgroups" 'compress' 'none')
if [ "$compress" != 'none' ]; then
compress_chunk=$(parse_cnf "$encgroups" 'compress-chunk-size')
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'
local STREAM_BIN=$(commandex "$sfmt")
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="'$STREAM_BIN' -x"
else
strmcmd="'$STREAM_BIN' -c '$INFO_FILE' '$DONOR_INFO_FILE'"
fi
else
sfmt='tar'
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
strmcmd='tar xfi -'
else
strmcmd="tar cf - '$INFO_FILE' '$DONOR_INFO_FILE'"
fi
fi
wsrep_log_info "Streaming with $sfmt"
}
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 [ -z "${coords:-}" -a "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
estatus=32
wsrep_log_error "Failed to get current position"
fi
[ "$(pwd)" != "$OLD_PWD" ] && cd "$OLD_PWD"
if [ "$WSREP_SST_OPT_ROLE" = 'donor' -o $estatus -ne 0 ]; then
if [ $estatus -ne 0 ]; then
wsrep_log_error "Removing $MAGIC_FILE file due to signal"
fi
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" || :
[ -f "$DONOR_MAGIC_FILE" ] && rm -f "$DONOR_MAGIC_FILE" || :
[ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" || :
fi
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
if [ -n "$BACKUP_PID" ]; then
if ps -p $BACKUP_PID >/dev/null 2>&1; then
wsrep_log_error \
"SST streaming process is still running. Killing..."
cleanup_pid $BACKUP_PID
fi
fi
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 -f "$progress" || :
fi
wsrep_log_info "Cleaning up temporary directories"
if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then
[ -n "$STATDIR" -a -d "$STATDIR" ] && rm -rf "$STATDIR" || :
else
[ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || :
[ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || :
fi
# Final cleanup
local pgid=$(ps -o 'pgid=' $$ 2>/dev/null | grep -o -E '[0-9]+' || :)
# This means no setsid done in mysqld.
# We don't want to kill mysqld here otherwise.
if [ -n "$pgid" ]; then
if [ $$ -eq $pgid ]; then
# This means a signal was delivered to the process.
# So, more cleanup.
if [ $estatus -ge 128 ]; then
kill -KILL -- -$$ || :
fi
fi
fi
if [ -n "$SST_PID" ]; then
[ -f "$SST_PID" ] && rm -f "$SST_PID" || :
fi
exit $estatus
}
setup_ports()
{
SST_PORT="$WSREP_SST_OPT_PORT"
if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then
REMOTEIP="$WSREP_SST_OPT_HOST"
lsn="$WSREP_SST_OPT_LSN"
sst_ver="$WSREP_SST_OPT_SST_VER"
fi
}
#
# Waits ~30 seconds for socat or nc to open the port and
# then reports ready, regardless of timeout.
#
wait_for_listen()
{
for i in {1..150}; do
if check_port "" "$SST_PORT" 'socat|nc|netcat'; then
break
fi
sleep 0.2
done
echo "ready $ADDR:$SST_PORT/$MODULE/$lsn/$sst_ver"
}
check_extra()
{
local use_socket=1
if [ $uextra -eq 1 ]; then
local thread_handling=$(parse_cnf '--mysqld' 'thread-handling')
if [ "$thread_handling" = 'pool-of-threads' ]; then
local eport=$(parse_cnf '--mysqld' 'extra-port')
if [ -n "$eport" ]; then
# mariadb-backup 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
else
wsrep_log_error "Extra port $eport null, failing"
exit 1
fi
else
wsrep_log_info "Thread pool not set, ignore the option use_extra"
fi
fi
if [ $use_socket -eq 1 -a -n "$WSREP_SST_OPT_SOCKET" ]; then
INNOEXTRA="$INNOEXTRA --socket='$WSREP_SST_OPT_SOCKET'"
fi
}
recv_joiner()
{
local dir="$1"
local msg="$2"
local tmt=$3
local checkf=$4
local wait=$5
if [ ! -d "$dir" ]; then
# This indicates that IST is in progress
return
fi
local ltcmd="$tcmd"
if [ $tmt -gt 0 ]; then
if [ -n "$(commandex timeout)" ]; then
local koption=0
if [ "$OS" = 'FreeBSD' -o "$OS" = 'NetBSD' -o "$OS" = 'OpenBSD' -o \
"$OS" = 'DragonFly' ]; then
if timeout 2>&1 | grep -qw -F -- '-k'; then
koption=1
fi
else
if timeout --help | grep -qw -F -- '-k'; then
koption=1
fi
fi
if [ $koption -ne 0 ]; then
ltcmd="timeout -k $(( tmt+10 )) $tmt $tcmd"
else
ltcmd="timeout -s 9 $tmt $tcmd"
fi
fi
fi
if [ $wait -ne 0 ]; then
wait_for_listen &
fi
cd "$dir"
set +e
timeit "$msg" "$ltcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )"
set -e
cd "$OLD_PWD"
if [ ${RC[0]} -eq 124 ]; then
wsrep_log_error "Possible timeout in receiving first data from" \
"donor in gtid stage: exit codes: ${RC[@]}"
exit 32
fi
for ecode in "${RC[@]}"; do
if [ $ecode -ne 0 ]; then
wsrep_log_error "Error while getting data from donor node:" \
"exit codes: ${RC[@]}"
exit 32
fi
done
if [ $checkf -eq 1 ]; then
if [ ! -r "$MAGIC_FILE" ]; then
# this message should cause joiner to abort:
wsrep_log_error "receiving process ended without creating" \
"magic file ($MAGIC_FILE)"
wsrep_log_info "Contents of datadir:"
wsrep_log_info "$(ls -l "$dir"/*)"
exit 32
fi
if [ -n "$MY_SECRET" ]; then
# Check donor supplied secret:
SECRET=$(grep -m1 -E "^$SECRET_TAG[[:space:]]" "$MAGIC_FILE" || :)
SECRET=$(trim_string "${SECRET#$SECRET_TAG}")
if [ "$SECRET" != "$MY_SECRET" ]; then
wsrep_log_error "Donor does not know my secret!"
wsrep_log_info "Donor: '$SECRET', my: '$MY_SECRET'"
exit 32
fi
fi
if [ $WSREP_SST_OPT_PROGRESS -eq 1 ]; then
# check total SST footprint
payload=$(grep -m1 -E "^$TOTAL_TAG[[:space:]]" "$MAGIC_FILE" || :)
if [ -n "$payload" ]; then
payload=$(trim_string "${payload#$TOTAL_TAG}")
if [ $payload -ge 0 ]; then
# report to parent
echo "$TOTAL_TAG $payload"
fi
fi
fi
fi
}
send_donor()
{
local dir="$1"
local msg="$2"
cd "$dir"
set +e
timeit "$msg" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
set -e
cd "$OLD_PWD"
for ecode in "${RC[@]}"; do
if [ $ecode -ne 0 ]; then
wsrep_log_error "Error while sending data to joiner node:" \
"exit codes: ${RC[@]}"
exit 32
fi
done
}
monitor_process()
{
local sst_stream_pid=$1
while :; do
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 2>&1; then
break
fi
sleep 0.1
done
}
read_cnf
setup_ports
if [ "$progress" = 'none' ]; then
wsrep_log_info "All progress/rate-limiting disabled by configuration"
elif [ -z "$(commandex pv)" ]; then
wsrep_log_info "Progress reporting tool pv not found in path: $PATH"
wsrep_log_info "Disabling all progress/rate-limiting"
progress='none'
fi
if "$BACKUP_BIN" --help 2>/dev/null | grep -qw -F -- '--version-check'; then
disver=' --no-version-check'
fi
get_stream
get_transfer
findopt='-L'
[ "$OS" = 'FreeBSD' ] && findopt="$findopt -E"
wait_previous_sst
[ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
[ -f "$DONOR_MAGIC_FILE" ] && rm -f "$DONOR_MAGIC_FILE"
[ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE"
if [ $ssyslog -eq 1 ]; then
if [ -n "$(commandex logger)" ]; then
wsrep_log_info "Logging all stderr of SST/mariadb-backup 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_warning()
{
logger -p daemon.warning -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE -- "$@"
}
wsrep_log_info()
{
logger -p daemon.info -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE -- "$@"
}
else
wsrep_log_error "logger not in path: $PATH. Ignoring"
fi
INNOAPPLY="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply"
INNOMOVE="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move"
INNOBACKUP="2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)"
else
if [ $sstlogarchive -eq 1 ]
then
ARCHIVETIMESTAMP=$(date '+%Y.%m.%d-%H.%M.%S.%N')
if [ -n "$sstlogarchivedir" ]; then
if [ ! -d "$sstlogarchivedir" ]; then
if ! mkdir -p "$sstlogarchivedir"; then
sstlogarchivedir=""
wsrep_log_warning \
"Unable to create '$sstlogarchivedir' directory"
fi
elif [ ! -w "$sstlogarchivedir" ]; then
sstlogarchivedir=""
wsrep_log_warning \
"The '$sstlogarchivedir' directory is not writtable"
fi
fi
if [ -e "$INNOAPPLYLOG" ]; then
if [ -n "$sstlogarchivedir" ]; then
newfile=$(basename "$INNOAPPLYLOG")
newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP"
else
newfile="$INNOAPPLYLOG.$ARCHIVETIMESTAMP"
fi
wsrep_log_info "Moving '$INNOAPPLYLOG' to '$newfile'"
mv "$INNOAPPLYLOG" "$newfile" && gzip "$newfile" || \
wsrep_log_warning "Failed to archive log file ('$newfile')"
fi
if [ -e "$INNOMOVELOG" ]; then
if [ -n "$sstlogarchivedir" ]; then
newfile=$(basename "$INNOMOVELOG")
newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP"
else
newfile="$INNOMOVELOG.$ARCHIVETIMESTAMP"
fi
wsrep_log_info "Moving '$INNOMOVELOG' to '$newfile'"
mv "$INNOMOVELOG" "$newfile" && gzip "$newfile" || \
wsrep_log_warning "Failed to archive log file ('$newfile')"
fi
if [ -e "$INNOBACKUPLOG" ]; then
if [ -n "$sstlogarchivedir" ]; then
newfile=$(basename "$INNOBACKUPLOG")
newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP"
else
newfile="$INNOBACKUPLOG.$ARCHIVETIMESTAMP"
fi
wsrep_log_info "Moving '$INNOBACKUPLOG' to '$newfile'"
mv "$INNOBACKUPLOG" "$newfile" && gzip "$newfile" || \
wsrep_log_warning "Failed to archive log file ('$newfile')"
fi
fi
INNOAPPLY="> '$INNOAPPLYLOG' 2>&1"
INNOMOVE="> '$INNOMOVELOG' 2>&1"
INNOBACKUP="2> '$INNOBACKUPLOG'"
fi
setup_commands()
{
local mysqld_args=""
if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then
mysqld_args=" --mysqld-args $WSREP_SST_OPT_MYSQLD"
fi
local recovery=""
if [ -n "$INNODB_FORCE_RECOVERY" ]; then
recovery=" --innodb-force-recovery=$INNODB_FORCE_RECOVERY"
fi
if [ -n "$use_memory" ]; then
INNOEXTRA="$INNOEXTRA --use-memory=$use_memory"
fi
INNOAPPLY="$BACKUP_BIN --prepare$disver$recovery${iapts:+ }$iapts$INNOEXTRA --target-dir='$DATA' --datadir='$DATA'$mysqld_args $INNOAPPLY"
INNOMOVE="$BACKUP_BIN$WSREP_SST_OPT_CONF --move-back$disver${impts:+ }$impts$INNOEXTRA --galera-info --force-non-empty-directories --target-dir='$DATA' --datadir='${TDATA:-$DATA}' $INNOMOVE"
INNOBACKUP="$BACKUP_BIN$WSREP_SST_OPT_CONF --backup$disver${iopts:+ }$iopts$tmpopts$INNOEXTRA --galera-info --stream=$sfmt --target-dir='$itmpdir' --datadir='$DATA'$mysqld_args $INNOBACKUP"
}
send_magic()
{
# Store donor's wsrep GTID (state ID) and wsrep_gtid_domain_id
# (separated by a space).
echo "$WSREP_SST_OPT_GTID $WSREP_SST_OPT_GTID_DOMAIN_ID" > "$MAGIC_FILE"
echo "$WSREP_SST_OPT_GTID $WSREP_SST_OPT_GTID_DOMAIN_ID" > "$DONOR_MAGIC_FILE"
if [ -n "$WSREP_SST_OPT_REMOTE_PSWD" ]; then
# Let joiner know that we know its secret
echo "$SECRET_TAG $WSREP_SST_OPT_REMOTE_PSWD" >> "$MAGIC_FILE"
fi
if [ $WSREP_SST_OPT_BYPASS -eq 0 -a $WSREP_SST_OPT_PROGRESS -eq 1 ]; then
# Tell joiner what to expect:
echo "$TOTAL_TAG $payload" >> "$MAGIC_FILE"
fi
}
if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then
trap cleanup_at_exit EXIT
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
tmpdir=$(parse_cnf "$encgroups" 'tmpdir')
if [ -z "$tmpdir" ]; then
xtmpdir="$(mktemp -d)"
itmpdir="$(mktemp -d)"
elif [ "$OS" = 'Linux' ]; then
xtmpdir=$(mktemp -d "--tmpdir=$tmpdir")
itmpdir=$(mktemp -d "--tmpdir=$tmpdir")
else
xtmpdir=$(TMPDIR="$tmpdir"; mktemp -d)
itmpdir=$(TMPDIR="$tmpdir"; mktemp -d)
fi
wsrep_log_info "Using '$xtmpdir' as mariadb-backup temporary directory"
tmpopts=" --tmpdir='$xtmpdir'"
wsrep_log_info "Using '$itmpdir' as mariadb-backup working directory"
if [ -n "$WSREP_SST_OPT_USER" ]; then
INNOEXTRA="$INNOEXTRA --user='$WSREP_SST_OPT_USER'"
fi
if [ -n "$WSREP_SST_OPT_PSWD" ]; then
export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
elif [ -n "$WSREP_SST_OPT_USER" ]; then
# Empty password, used for testing, debugging etc.
unset MYSQL_PWD
fi
check_extra
if [ -n "$progress" -o $WSREP_SST_OPT_PROGRESS -eq 1 ]; then
wsrep_log_info "Estimating total transfer size"
get_footprint
wsrep_log_info "To transfer: $payload"
else
adjust_progress
fi
wsrep_log_info "Streaming GTID file before SST"
send_magic
ttcmd="$tcmd"
if [ -n "$scomp" ]; then
tcmd="$scomp | $tcmd"
fi
get_keys
if [ $encrypt -eq 1 ]; then
tcmd="$ecmd | $tcmd"
fi
send_donor "$DATA" "$stagemsg-gtid"
# Restore the transport commmand to its original state
tcmd="$ttcmd"
if [ -n "$pcmd" ]; then
if [ -n "$rcmd" ]; then
# redirect pv stderr to rcmd for tagging and output to parent
tcmd="{ $pcmd 2>&3 | $tcmd; } 3>&1 | $rcmd"
else
# use user-configured pv output
tcmd="$pcmd | $tcmd"
fi
fi
wsrep_log_info "Sleeping before data transfer for SST"
sleep 10
wsrep_log_info "Streaming the backup to joiner at $REMOTEIP:$SST_PORT"
# Add compression to the head of the stream (if specified)
if [ -n "$scomp" ]; then
tcmd="$scomp | $tcmd"
fi
# Add encryption to the head of the stream (if specified)
if [ $encrypt -eq 1 ]; then
tcmd="$ecmd | $tcmd"
fi
iopts="--databases-exclude='lost+found'${iopts:+ }$iopts"
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${iopts:+ }$iopts"
fi
# if compression is enabled for backup files, then add the
# appropriate options to the mariadb-backup command line:
if [ "$compress" != 'none' ]; then
iopts="--compress${compress:+=$compress}${iopts:+ }$iopts"
if [ -n "$compress_threads" ]; then
iopts="--compress-threads=$compress_threads${iopts:+ }$iopts"
fi
if [ -n "$compress_chunk" ]; then
iopts="--compress-chunk-size=$compress_chunk${iopts:+ }$iopts"
fi
fi
if [ -n "$backup_threads" ]; then
iopts="--parallel=$backup_threads${iopts:+ }$iopts"
fi
setup_commands
set +e
timeit "$stagemsg-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
set -e
if [ ${RC[0]} -ne 0 ]; then
wsrep_log_error "mariadb-backup finished with error: ${RC[0]}." \
"Check syslog or '$INNOBACKUPLOG' for details"
exit 22
elif [ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]; then
wsrep_log_error "$tcmd finished with error: ${RC[1]}"
exit 22
fi
else # BYPASS FOR IST
wsrep_log_info "Bypassing the SST for IST"
echo 'continue' # now server can resume updating data
send_magic
echo '1' > "$DATA/$IST_FILE"
if [ -n "$scomp" ]; then
tcmd="$scomp | $tcmd"
fi
get_keys
if [ $encrypt -eq 1 ]; then
tcmd="$ecmd | $tcmd"
fi
strmcmd="$strmcmd '$IST_FILE'"
send_donor "$DATA" "$stagemsg-IST"
fi
echo "done $WSREP_SST_OPT_GTID"
wsrep_log_info "Total time on donor: $totime seconds"
else # joiner
create_dirs 1
[ -e "$SST_PROGRESS_FILE" ] && \
wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE"
[ -n "$SST_PROGRESS_FILE" ] && touch "$SST_PROGRESS_FILE"
if [ -n "$backup_threads" ]; then
impts="--parallel=$backup_threads${impts:+ }$impts"
fi
stagemsg='Joiner-Recv'
MODULE="${WSREP_SST_OPT_MODULE:-xtrabackup_sst}"
ADDR="$WSREP_SST_OPT_HOST"
if [ "${tmode#VERIFY}" != "$tmode" ]; then
# backward-incompatible behavior:
CN=""
if [ -n "$tpem" ]; then
CN=$(openssl_getCN "$tpem")
fi
MY_SECRET="$(wsrep_gen_secret)"
# Add authentication data to address
ADDR="$CN:$MY_SECRET@$ADDR"
else
MY_SECRET="" # for check down in recv_joiner()
fi
get_keys
if [ $encrypt -eq 1 ]; then
strmcmd="$ecmd | $strmcmd"
fi
if [ -n "$sdecomp" ]; then
strmcmd="$sdecomp | $strmcmd"
fi
check_sockets_utils
trap cleanup_at_exit EXIT
STATDIR="$(mktemp -d)"
MAGIC_FILE="$STATDIR/$INFO_FILE"
DONOR_MAGIC_FILE="$STATDIR/$DONOR_INFO_FILE"
recv_joiner "$STATDIR" "$stagemsg-gtid" $stimeout 1 1
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
fi
if [ ! -r "$STATDIR/$IST_FILE" ]; then
adjust_progress
if [ -n "$pcmd" ]; then
if [ -n "$rcmd" ]; then
# redirect pv stderr to rcmd for tagging and output to parent
strmcmd="{ $pcmd 2>&3 | $strmcmd; } 3>&1 | $rcmd"
else
# use user-configured pv output
strmcmd="$pcmd | $strmcmd"
fi
fi
if [ -d "$DATA/.sst" ]; then
wsrep_log_info \
"WARNING: Stale temporary SST directory:" \
"'$DATA/.sst' from previous state transfer, removing..."
rm -rf "$DATA/.sst"
fi
mkdir -p "$DATA/.sst"
(recv_joiner "$DATA/.sst" "$stagemsg-SST" 0 0 0) &
BACKUP_PID=$!
wsrep_log_info "Proceeding with SST"
get_binlog
if [ -n "$WSREP_SST_OPT_BINLOG" ]; then
binlog_dir=$(dirname "$WSREP_SST_OPT_BINLOG")
binlog_base=$(basename "$WSREP_SST_OPT_BINLOG")
binlog_index="$WSREP_SST_OPT_BINLOG_INDEX"
cd "$DATA"
wsrep_log_info "Cleaning the old binary logs"
# If there is a file with binlogs state, delete it:
[ -f "$binlog_base.state" ] && rm "$binlog_base.state" >&2
# Clean up the old binlog files and index:
if [ -f "$binlog_index" ]; then
while read bin_file || [ -n "$bin_file" ]; do
rm -f "$bin_file" >&2 || :
done < "$binlog_index"
rm "$binlog_index" >&2
fi
if [ -n "$binlog_dir" -a "$binlog_dir" != '.' -a \
-d "$binlog_dir" ]
then
cd "$binlog_dir"
if [ "$(pwd)" != "$DATA_DIR" ]; then
wsrep_log_info \
"Cleaning the binlog directory '$binlog_dir' as well"
fi
fi
rm -f "$binlog_base".[0-9]* >&2 || :
cd "$OLD_PWD"
fi
wsrep_log_info \
"Cleaning the existing datadir and innodb-data/log directories"
find $findopt ${ib_home_dir:+"$ib_home_dir"} \
${ib_undo_dir:+"$ib_undo_dir"} \
${ib_log_dir:+"$ib_log_dir"} \
${ar_log_dir:+"$ar_log_dir"} \
"$DATA" -mindepth 1 -prune -regex "$cpat" \
-o -exec rm -rf {} >&2 \+
# Deleting files from previous SST and legacy files from old versions:
[ -f "$DATA/xtrabackup_binary" ] && rm -f "$DATA/xtrabackup_binary"
[ -f "$DATA/xtrabackup_pid" ] && rm -f "$DATA/xtrabackup_pid"
[ -f "$DATA/xtrabackup_checkpoints" ] && rm -f "$DATA/xtrabackup_checkpoints"
[ -f "$DATA/xtrabackup_info" ] && rm -f "$DATA/xtrabackup_info"
[ -f "$DATA/xtrabackup_slave_info" ] && rm -f "$DATA/xtrabackup_slave_info"
[ -f "$DATA/xtrabackup_binlog_info" ] && rm -f "$DATA/xtrabackup_binlog_info"
[ -f "$DATA/xtrabackup_binlog_pos_innodb" ] && rm -f "$DATA/xtrabackup_binlog_pos_innodb"
TDATA="$DATA"
DATA="$DATA/.sst"
MAGIC_FILE="$DATA/$INFO_FILE"
wsrep_log_info "Waiting for SST streaming to complete!"
monitor_process $BACKUP_PID
BACKUP_PID=""
if [ ! -s "$DATA/xtrabackup_checkpoints" ]; then
wsrep_log_error "xtrabackup_checkpoints missing," \
"failed mariadb-backup/SST on donor"
exit 2
fi
# Compact backups are not supported by mariadb-backup
if grep -qw -F 'compact = 1' "$DATA/xtrabackup_checkpoints"; then
wsrep_log_info "Index compaction detected"
wsrep_log_error "Compact backups are not supported by mariadb-backup"
exit 2
fi
qpfiles=$(find $findopt "$DATA" -maxdepth 1 -type f -name '*.qp' -print -quit)
if [ -n "$qpfiles" ]; then
wsrep_log_info "Compressed qpress files found"
if [ -z "$(commandex qpress)" ]; then
wsrep_log_error "qpress utility not found in the path"
exit 22
fi
get_proc
dcmd="xargs -n 2 qpress -dT$nproc"
if [ -n "$progress" -a "$progress" != 'none' ] && \
pv --help | grep -qw -F -- '--line-mode'
then
count=$(find $findopt "$DATA" -maxdepth 1 -type f -name '*.qp' | wc -l)
count=$(( count*2 ))
pvopts='-f -l -N Decompression'
pvformat="-F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'"
payload=$count
adjust_progress
dcmd="$pcmd | $dcmd"
fi
# Decompress the qpress files
wsrep_log_info "Decompression with $nproc threads"
timeit 'Joiner-Decompression' \
"find $findopt '$DATA' -type f -name '*.qp' -printf '%p\n%h\n' | \
$dcmd"
extcode=$?
if [ $extcode -eq 0 ]; then
wsrep_log_info "Removing qpress files after decompression"
find $findopt "$DATA" -type f -name '*.qp' -delete
if [ $? -ne 0 ]; then
wsrep_log_error \
"Something went wrong with deletion of qpress files." \
"Investigate"
fi
else
wsrep_log_error "Decompression failed. Exit code: $extcode"
exit 22
fi
fi
wsrep_log_info "Preparing the backup at $DATA"
setup_commands
timeit 'mariadb-backup prepare stage' "$INNOAPPLY"
if [ $? -ne 0 ]; then
wsrep_log_error "mariadb-backup apply finished with errors." \
"Check syslog or '$INNOAPPLYLOG' for details."
exit 22
fi
if [ -n "$WSREP_SST_OPT_BINLOG" ]; then
cd "$DATA"
binlogs=""
if [ -f 'xtrabackup_binlog_info' ]; then
NL=$'\n'
while read bin_string || [ -n "$bin_string" ]; do
bin_file=$(echo "$bin_string" | cut -f1)
if [ -f "$bin_file" ]; then
binlogs="$binlogs${binlogs:+$NL}$bin_file"
fi
done < 'xtrabackup_binlog_info'
else
binlogs=$(ls -d -1 "$binlog_base".[0-9]* 2>/dev/null || :)
fi
cd "$DATA_DIR"
if [ -n "$binlog_dir" -a "$binlog_dir" != '.' -a \
"$binlog_dir" != "$DATA_DIR" ]
then
[ ! -d "$binlog_dir" ] && mkdir -p "$binlog_dir"
fi
index_dir=$(dirname "$binlog_index");
if [ -n "$index_dir" -a "$index_dir" != '.' -a \
"$index_dir" != "$DATA_DIR" ]
then
[ ! -d "$index_dir" ] && mkdir -p "$index_dir"
fi
if [ -n "$binlogs" ]; then
wsrep_log_info "Moving binary logs to $binlog_dir"
echo "$binlogs" | \
while read bin_file || [ -n "$bin_file" ]; do
mv "$DATA/$bin_file" "$binlog_dir"
echo "$binlog_dir${binlog_dir:+/}$bin_file" >> "$binlog_index"
done
fi
cd "$OLD_PWD"
fi
MAGIC_FILE="$TDATA/$INFO_FILE"
DONOR_MAGIC_FILE="$TDATA/$DONOR_INFO_FILE"
wsrep_log_info "Moving the backup to $TDATA"
timeit 'mariadb-backup 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 syslog or '$INNOMOVELOG' for details"
exit 22
fi
else
wsrep_log_info "'$IST_FILE' received from donor: Running IST"
if [ $WSREP_SST_OPT_BYPASS -eq 0 ]; then
readonly WSREP_SST_OPT_BYPASS=1
readonly WSREP_TRANSFER_TYPE='IST'
fi
fi
if [ ! -r "$MAGIC_FILE" ]; then
wsrep_log_error "Internal error: SST magic file '$MAGIC_FILE'" \
"not found or not readable"
exit 2
fi
# use donor magic file, if present
# if IST was used, donor magic file was not created
# Remove special tags from the magic file, and from the output:
if [ -r "$DONOR_MAGIC_FILE" ]; then
coords=$(head -n1 "$DONOR_MAGIC_FILE")
wsrep_log_info "Galera co-ords from donor: $coords"
else
coords=$(head -n1 "$MAGIC_FILE")
wsrep_log_info "Galera co-ords from recovery: $coords"
fi
echo "$coords" # Output : UUID:seqno wsrep_gtid_domain_id
wsrep_log_info "Total time on joiner: $totime seconds"
fi
wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE completed on $WSREP_SST_OPT_ROLE"
exit 0