1#!/usr/local/bin/bash
2# Copyright (C) 2013 Percona Inc
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; version 2 of the License.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; see the file COPYING. If not, write to the
15# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
16# MA  02110-1301  USA.
17
18# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html
19# Make sure to read that before proceeding!
20
21set -o nounset -o errexit
22
23. $(dirname $0)/wsrep_sst_common
24
25ealgo=""
26ekey=""
27ekeyfile=""
28encrypt=0
29nproc=1
30ecode=0
31XTRABACKUP_PID=""
32SST_PORT=""
33REMOTEIP=""
34tcert=""
35tpem=""
36sockopt=""
37progress=""
38ttime=0
39totime=0
40lsn=""
41incremental=0
42ecmd=""
43rlimit=""
44
45sfmt="tar"
46strmcmd=""
47tfmt=""
48tcmd=""
49rebuild=0
50rebuildcmd=""
51payload=0
52pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' "
53pvopts="-f  -i 10 -N $WSREP_SST_OPT_ROLE "
54uextra=0
55
56if which pv &>/dev/null && pv --help | grep -q FORMAT;then
57    pvopts+=$pvformat
58fi
59pcmd="pv $pvopts"
60declare -a RC
61
62INNOBACKUPEX_BIN=innobackupex
63DATA="${WSREP_SST_OPT_DATA}"
64INFO_FILE="xtrabackup_galera_info"
65IST_FILE="xtrabackup_ist"
66MAGIC_FILE="${DATA}/${INFO_FILE}"
67
68# Setting the path for ss and ip
69export PATH="/usr/sbin:/sbin:$PATH"
70
71timeit(){
72    local stage=$1
73    shift
74    local cmd="$@"
75    local x1 x2 took extcode
76
77    if [[ $ttime -eq 1 ]];then
78        x1=$(date +%s)
79        wsrep_log_info "Evaluating $cmd"
80        eval "$cmd"
81        extcode=$?
82        x2=$(date +%s)
83        took=$(( x2-x1 ))
84        wsrep_log_info "NOTE: $stage took $took seconds"
85        totime=$(( totime+took ))
86    else
87        wsrep_log_info "Evaluating $cmd"
88        eval "$cmd"
89        extcode=$?
90    fi
91    return $extcode
92}
93
94get_keys()
95{
96    if [[ $encrypt -eq 2 ]];then
97        return
98    fi
99
100    if [[ $encrypt -eq 0 ]];then
101        if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then
102            wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
103        fi
104        return
105    fi
106
107    if [[ $sfmt == 'tar' ]];then
108        wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format"
109        encrypt=0
110        return
111    fi
112
113    wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4"
114
115    if [[ -z $ealgo ]];then
116        wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out"
117        exit 3
118    fi
119
120    if [[ -z $ekey && ! -r $ekeyfile ]];then
121        wsrep_log_error "FATAL: Either key or keyfile must be readable"
122        exit 3
123    fi
124
125    if [[ -z $ekey ]];then
126        ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile"
127    else
128        ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey"
129    fi
130
131    if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
132        ecmd+=" -d"
133    fi
134}
135
136get_transfer()
137{
138    if [[ -z $SST_PORT ]];then
139        TSST_PORT=4444
140    else
141        TSST_PORT=$SST_PORT
142    fi
143
144    if [[ $tfmt == 'nc' ]];then
145        if [[ ! -x `which nc` ]];then
146            wsrep_log_error "nc(netcat) not found in path: $PATH"
147            exit 2
148        fi
149        wsrep_log_info "Using netcat as streamer"
150        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
151            if nc -h | grep -q ncat;then
152                tcmd="nc -l ${TSST_PORT}"
153            else
154                tcmd="nc -dl ${TSST_PORT}"
155            fi
156        else
157            tcmd="nc ${REMOTEIP} ${TSST_PORT}"
158        fi
159    else
160        tfmt='socat'
161        wsrep_log_info "Using socat as streamer"
162        if [[ ! -x `which socat` ]];then
163            wsrep_log_error "socat not found in path: $PATH"
164            exit 2
165        fi
166
167        if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then
168            wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer"
169            encrypt=0
170        fi
171
172        if [[ $encrypt -eq 2 ]];then
173            wsrep_log_info "Using openssl based encryption with socat"
174            if [[ -z $tpem || -z $tcert ]];then
175                wsrep_log_error "Both PEM and CRT files required"
176                exit 22
177            fi
178            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
179                wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert"
180                tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio"
181            else
182                wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert"
183                tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}"
184            fi
185        else
186            if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
187                tcmd="socat -u TCP-LISTEN:${TSST_PORT},reuseaddr${sockopt} stdio"
188            else
189                tcmd="socat -u stdio TCP:${REMOTEIP}:${TSST_PORT}${sockopt}"
190            fi
191        fi
192    fi
193
194}
195
196parse_cnf()
197{
198    local group=$1
199    local var=$2
200    reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-)
201    if [[ -z $reval ]];then
202        [[ -n $3 ]] && reval=$3
203    fi
204    echo $reval
205}
206
207get_footprint()
208{
209    pushd $WSREP_SST_OPT_DATA 1>/dev/null
210    payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | xargs -0 du --block-size=1 -c | awk 'END { print $1 }')
211    if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then
212        # QuickLZ has around 50% compression ratio
213        # When compression/compaction used, the progress is only an approximate.
214        payload=$(( payload*1/2 ))
215    fi
216    popd 1>/dev/null
217    pcmd+=" -s $payload"
218    adjust_progress
219}
220
221adjust_progress()
222{
223    if [[ -n $progress && $progress != '1' ]];then
224        if [[ -e $progress ]];then
225            pcmd+=" 2>>$progress"
226        else
227            pcmd+=" 2>$progress"
228        fi
229    elif [[ -z $progress && -n $rlimit  ]];then
230            # When rlimit is non-zero
231            pcmd="pv -q"
232    fi
233
234    if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE"  == "donor" ]];then
235        wsrep_log_info "Rate-limiting SST to $rlimit"
236        pcmd+=" -L \$rlimit"
237    fi
238}
239
240read_cnf()
241{
242    sfmt=$(parse_cnf sst streamfmt "tar")
243    tfmt=$(parse_cnf sst transferfmt "socat")
244    tcert=$(parse_cnf sst tca "")
245    tpem=$(parse_cnf sst tcert "")
246    encrypt=$(parse_cnf sst encrypt 0)
247    sockopt=$(parse_cnf sst sockopt "")
248    progress=$(parse_cnf sst progress "")
249    rebuild=$(parse_cnf sst rebuild 0)
250    ttime=$(parse_cnf sst time 0)
251    incremental=$(parse_cnf sst incremental 0)
252    ealgo=$(parse_cnf xtrabackup encrypt "")
253    ekey=$(parse_cnf xtrabackup encrypt-key "")
254    ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "")
255
256    # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html
257    if [[ -z $ealgo ]];then
258        ealgo=$(parse_cnf sst encrypt-algo "")
259        ekey=$(parse_cnf sst encrypt-key "")
260        ekeyfile=$(parse_cnf sst encrypt-key-file "")
261    fi
262    rlimit=$(parse_cnf sst rlimit "")
263    uextra=$(parse_cnf sst use_extra 0)
264}
265
266get_stream()
267{
268    if [[ $sfmt == 'xbstream' ]];then
269        wsrep_log_info "Streaming with xbstream"
270        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
271            strmcmd="xbstream -x"
272        else
273            strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}"
274        fi
275    else
276        sfmt="tar"
277        wsrep_log_info "Streaming with tar"
278        if [[ "$WSREP_SST_OPT_ROLE"  == "joiner" ]];then
279            strmcmd="tar xfi - --recursive-unlink -h"
280        else
281            strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}"
282        fi
283
284    fi
285}
286
287get_proc()
288{
289    set +e
290    nproc=$(grep -c processor /proc/cpuinfo)
291    [[ -z $nproc || $nproc -eq 0 ]] && nproc=1
292    set -e
293}
294
295sig_joiner_cleanup()
296{
297    wsrep_log_error "Removing $MAGIC_FILE file due to signal"
298    rm -f "$MAGIC_FILE"
299}
300
301cleanup_joiner()
302{
303    # Since this is invoked just after exit NNN
304    local estatus=$?
305    if [[ $estatus -ne 0 ]];then
306        wsrep_log_error "Cleanup after exit with status:$estatus"
307    fi
308    if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then
309        wsrep_log_info "Removing the sst_in_progress file"
310        wsrep_cleanup_progress_file
311    fi
312    if [[ -n $progress && -p $progress ]];then
313        wsrep_log_info "Cleaning up fifo file $progress"
314        rm $progress
315    fi
316}
317
318check_pid()
319{
320    local pid_file="$1"
321    [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1
322}
323
324cleanup_donor()
325{
326    # Since this is invoked just after exit NNN
327    local estatus=$?
328    if [[ $estatus -ne 0 ]];then
329        wsrep_log_error "Cleanup after exit with status:$estatus"
330    fi
331
332    if [[ -n $XTRABACKUP_PID ]];then
333        if check_pid $XTRABACKUP_PID
334        then
335            wsrep_log_error "xtrabackup process is still running. Killing... "
336            kill_xtrabackup
337        fi
338
339        rm -f $XTRABACKUP_PID
340    fi
341    rm -f ${DATA}/${IST_FILE}
342
343    if [[ -n $progress && -p $progress ]];then
344        wsrep_log_info "Cleaning up fifo file $progress"
345        rm $progress
346    fi
347}
348
349kill_xtrabackup()
350{
351    local PID=$(cat $XTRABACKUP_PID)
352    [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || :
353    rm -f "$XTRABACKUP_PID"
354}
355
356setup_ports()
357{
358    if [[ "$WSREP_SST_OPT_ROLE"  == "donor" ]];then
359        SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }')
360        REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }')
361        lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }')
362    else
363        SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }')
364    fi
365}
366
367# waits ~10 seconds for nc to open the port and then reports ready
368# (regardless of timeout)
369wait_for_listen()
370{
371    local PORT=$1
372    local ADDR=$2
373    local MODULE=$3
374    for i in {1..50}
375    do
376        ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break
377        sleep 0.2
378    done
379    if [[ $incremental -eq 1 ]];then
380        echo "ready ${ADDR}/${MODULE}/$lsn"
381    else
382    echo "ready ${ADDR}/${MODULE}"
383    fi
384}
385
386check_extra()
387{
388    local use_socket=1
389    if [[ $uextra -eq 1 ]];then
390        if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then
391            local eport=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2)
392            if [[ -n $eport ]];then
393                # Xtrabackup works only locally.
394                # Hence, setting host to 127.0.0.1 unconditionally.
395                wsrep_log_info "SST through extra_port $eport"
396                INNOEXTRA+=" --host=127.0.0.1 --port=$eport "
397                use_socket=0
398            else
399                wsrep_log_error "Extra port $eport null, failing"
400                exit 1
401            fi
402        else
403            wsrep_log_info "Thread pool not set, ignore the option use_extra"
404        fi
405    fi
406    if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then
407        INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}"
408    fi
409}
410
411if [[ ! -x `which innobackupex` ]];then
412    wsrep_log_error "innobackupex not in path: $PATH"
413    exit 2
414fi
415
416rm -f "${MAGIC_FILE}"
417
418if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then
419    wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}"
420    exit 22
421fi
422
423read_cnf
424setup_ports
425get_stream
426get_transfer
427
428INNOEXTRA=""
429INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log"
430INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log"
431
432if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
433then
434    trap cleanup_donor EXIT
435
436    if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
437    then
438        usrst=0
439        TMPDIR="${TMPDIR:-/tmp}"
440
441        if [[ -n "${WSREP_SST_OPT_USER:-}" && "$WSREP_SST_OPT_USER" != "(null)" ]]; then
442           INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
443           usrst=1
444        fi
445
446        if [ -n "${WSREP_SST_OPT_PSWD:-}" ]; then
447           INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
448        elif [[ $usrst -eq 1 ]];then
449           # Empty password, used for testing, debugging etc.
450           INNOEXTRA+=" --password="
451        fi
452
453        get_keys
454        if [[ $encrypt -eq 1 ]];then
455            if [[ -n $ekey ]];then
456                INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey "
457            else
458                INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile "
459            fi
460        fi
461
462        if [[ -n $lsn ]];then
463                INNOEXTRA+=" --incremental --incremental-lsn=$lsn "
464        fi
465
466        check_extra
467
468        wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}"
469
470        if [[ -n $progress ]];then
471            get_footprint
472            tcmd="$pcmd | $tcmd"
473        elif [[ -n $rlimit ]];then
474            adjust_progress
475            tcmd="$pcmd | $tcmd"
476        fi
477
478        set +e
479        timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
480        set -e
481
482        if [ ${RC[0]} -ne 0 ]; then
483          wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \
484                          "Check ${DATA}/innobackup.backup.log"
485          exit 22
486        elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then
487          wsrep_log_error "$tcmd finished with error: ${RC[1]}"
488          exit 22
489        fi
490
491        # innobackupex implicitly writes PID to fixed location in ${TMPDIR}
492        XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid"
493
494
495    else # BYPASS FOR IST
496
497        wsrep_log_info "Bypassing the SST for IST"
498        STATE="${WSREP_SST_OPT_GTID}"
499        echo "continue" # now server can resume updating data
500        echo "${STATE}" > "${MAGIC_FILE}"
501        echo "1" > "${DATA}/${IST_FILE}"
502        get_keys
503        pushd ${DATA} 1>/dev/null
504        set +e
505        if [[ $encrypt -eq 1 ]];then
506            tcmd=" $ecmd | $tcmd"
507        fi
508        timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
509        set -e
510        popd 1>/dev/null
511
512        for ecode in "${RC[@]}";do
513            if [[ $ecode -ne 0 ]];then
514                wsrep_log_error "Error while streaming data to joiner node: " \
515                                "exit codes: ${RC[@]}"
516                exit 1
517            fi
518        done
519    fi
520
521    echo "done ${WSREP_SST_OPT_GTID}"
522    wsrep_log_info "Total time on donor: $totime seconds"
523
524elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ]
525then
526    [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE"
527    touch $SST_PROGRESS_FILE
528
529    if [[ ! -e ${DATA}/ibdata1 ]];then
530        incremental=0
531    fi
532
533    if [[ $incremental -eq 1 ]];then
534        wsrep_log_info "Incremental SST enabled"
535        #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF  --basedir=/pxc  --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1)
536        lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ')
537        wsrep_log_info "Recovered LSN: $lsn"
538    fi
539
540    sencrypted=1
541    nthreads=1
542
543    MODULE="xtrabackup_sst"
544
545    # May need xtrabackup_checkpoints later on
546    rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info  ${DATA}/xtrabackup_logfile
547
548    ADDR=${WSREP_SST_OPT_ADDR}
549    if [ -z "${SST_PORT}" ]
550    then
551        SST_PORT=4444
552        ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}"
553    fi
554
555    wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} &
556
557    trap sig_joiner_cleanup HUP PIPE INT TERM
558    trap cleanup_joiner EXIT
559
560    if [[ -n $progress ]];then
561        adjust_progress
562        tcmd+=" | $pcmd"
563    fi
564
565    if [[ $incremental -eq 1 ]];then
566        BDATA=$DATA
567        DATA=$(mktemp -d)
568        MAGIC_FILE="${DATA}/${INFO_FILE}"
569    fi
570
571    get_keys
572    set +e
573    if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then
574        strmcmd=" $ecmd | $strmcmd"
575    fi
576
577    pushd ${DATA} 1>/dev/null
578    timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )"
579    popd 1>/dev/null
580
581    set -e
582
583    if [[ $sfmt == 'xbstream' ]];then
584        # Special handling till lp:1193240 is fixed"
585        if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then
586            wsrep_log_error "Xbstream failed"
587            wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \
588                            "Manual intervention required in that case"
589            exit 32
590        fi
591    fi
592
593    wait %% # join for wait_for_listen thread
594
595    for ecode in "${RC[@]}";do
596        if [[ $ecode -ne 0 ]];then
597            wsrep_log_error "Error while getting data from donor node: " \
598                            "exit codes: ${RC[@]}"
599            exit 32
600        fi
601    done
602
603    if [ ! -r "${MAGIC_FILE}" ]
604    then
605        # this message should cause joiner to abort
606        wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'"
607        wsrep_log_info "Contents of datadir"
608        wsrep_log_info "$(ls -l ${DATA}/**/*)"
609        exit 32
610    fi
611
612    if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null
613    then
614        wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly."
615        exit 32
616    fi
617
618    if [ ! -r "${DATA}/${IST_FILE}" ]
619    then
620        wsrep_log_info "Proceeding with SST"
621        wsrep_log_info "Removing existing ib_logfile files"
622        if [[ $incremental -ne 1 ]];then
623            rm -f ${DATA}/ib_logfile*
624        else
625            rm -f ${BDATA}/ib_logfile*
626        fi
627
628        get_proc
629
630        # Rebuild indexes for compact backups
631        if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then
632            wsrep_log_info "Index compaction detected"
633            rebuild=1
634        fi
635
636        if [[ $rebuild -eq 1 ]];then
637            nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc)
638            wsrep_log_info "Rebuilding during prepare with $nthreads threads"
639            rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads"
640        fi
641
642        if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then
643
644            wsrep_log_info "Compressed qpress files found"
645
646            if [[ ! -x `which qpress` ]];then
647                wsrep_log_error "qpress not found in path: $PATH"
648                exit 22
649            fi
650
651            if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then
652                count=$(find ${DATA} -type f -name '*.qp' | wc -l)
653                count=$(( count*2 ))
654                if pv --help | grep -q FORMAT;then
655                    pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'"
656                else
657                    pvopts="-f -s $count -l -N Decompression"
658                fi
659                pcmd="pv $pvopts"
660                adjust_progress
661                dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d"
662            else
663                dcmd="xargs -n 2 qpress -T${nproc}d"
664            fi
665
666            wsrep_log_info "Removing existing ibdata1 file"
667            rm -f ${DATA}/ibdata1
668
669            # Decompress the qpress files
670            wsrep_log_info "Decompression with $nproc threads"
671            timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd"
672            extcode=$?
673
674            if [[ $extcode -eq 0 ]];then
675                wsrep_log_info "Removing qpress files after decompression"
676                find ${DATA} -type f -name '*.qp' -delete
677                if [[ $? -ne 0 ]];then
678                    wsrep_log_error "Something went wrong with deletion of qpress files. Investigate"
679                fi
680            else
681                wsrep_log_error "Decompression failed. Exit code: $extcode"
682                exit 22
683            fi
684        fi
685
686        if [[ $incremental -eq 1 ]];then
687            # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues.
688            INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \
689                --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log"
690        fi
691
692        wsrep_log_info "Preparing the backup at ${DATA}"
693        timeit "Xtrabackup prepare stage" "$INNOAPPLY"
694
695        if [[ $incremental -eq 1 ]];then
696            wsrep_log_info "Cleaning up ${DATA} after incremental SST"
697            [[ -d ${DATA} ]] && rm -rf ${DATA}
698            DATA=$BDATA
699        fi
700
701        if [ $? -ne 0 ];
702        then
703            wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log"
704            exit 22
705        fi
706    else
707        wsrep_log_info "${IST_FILE} received from donor: Running IST"
708    fi
709
710    if [[ ! -r ${MAGIC_FILE} ]];then
711        wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable"
712        exit 2
713    fi
714
715    cat "${MAGIC_FILE}" # output UUID:seqno
716    wsrep_log_info "Total time on joiner: $totime seconds"
717fi
718
719exit 0
720