8 changed files with 1251 additions and 9 deletions
-
3.bzrignore
-
24cmake/install_macros.cmake
-
6cmake/os/FreeBSD.cmake
-
5scripts/mysqld_safe.sh
-
261scripts/wsrep_sst_rsync.sh.moved
-
481scripts/wsrep_sst_xtrabackup.sh.moved
-
12sql/sql_parse.cc
-
468sql/wsrep_utils.cc.moved
@ -0,0 +1,261 @@ |
|||
#!/bin/bash -ue |
|||
|
|||
# Copyright (C) 2010 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 |
|||
# 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-1301 USA. |
|||
|
|||
# This is a reference script for rsync-based state snapshot tansfer |
|||
|
|||
RSYNC_PID= |
|||
RSYNC_CONF= |
|||
OS=$(uname) |
|||
[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH |
|||
|
|||
. $(dirname $0)/wsrep_sst_common |
|||
|
|||
cleanup_joiner() |
|||
{ |
|||
wsrep_log_info "Joiner cleanup." |
|||
local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0) |
|||
[ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \ |
|||
|| : |
|||
rm -rf "$RSYNC_CONF" |
|||
rm -rf "$MAGIC_FILE" |
|||
rm -rf "$RSYNC_PID" |
|||
wsrep_log_info "Joiner cleanup done." |
|||
if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then |
|||
wsrep_cleanup_progress_file |
|||
fi |
|||
} |
|||
|
|||
check_pid() |
|||
{ |
|||
local pid_file=$1 |
|||
[ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1 |
|||
} |
|||
|
|||
check_pid_and_port() |
|||
{ |
|||
local pid_file=$1 |
|||
local rsync_pid=$(cat $pid_file) |
|||
local rsync_port=$2 |
|||
|
|||
if [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ]; then |
|||
# no netstat --program(-p) option in Darwin and FreeBSD |
|||
check_pid $pid_file && \ |
|||
lsof -i -Pn 2>/dev/null | \ |
|||
grep "(LISTEN)" | grep ":$rsync_port" | grep -w '^rsync[[:space:]]\+'"$rsync_pid" >/dev/null |
|||
else |
|||
check_pid $pid_file && \ |
|||
netstat -lnpt 2>/dev/null | \ |
|||
grep LISTEN | grep \:$rsync_port | grep $rsync_pid/rsync >/dev/null |
|||
fi |
|||
} |
|||
|
|||
MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" |
|||
rm -rf "$MAGIC_FILE" |
|||
|
|||
# Old filter - include everything except selected |
|||
# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \ |
|||
# --exclude '*.conf' --exclude core --exclude 'galera.*' \ |
|||
# --exclude grastate.txt --exclude '*.pem' \ |
|||
# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index') |
|||
|
|||
# New filter - exclude everything except dirs (schemas) and innodb files |
|||
FILTER=(-f '- lost+found' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /ib_logfile*' -f '+ */' -f '-! */*') |
|||
# Old versions of rsync have a bug transferring filter rules to daemon, so specify filter rules directly to daemon |
|||
FILTER_DAEMON="- lost+found + /ib_lru_dump + /ibdata* + ib_logfile* + */ -! */*" |
|||
|
|||
if [ "$WSREP_SST_OPT_ROLE" = "donor" ] |
|||
then |
|||
|
|||
if [ $WSREP_SST_OPT_BYPASS -eq 0 ] |
|||
then |
|||
|
|||
FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" |
|||
rm -rf "$FLUSHED" |
|||
|
|||
# Use deltaxfer only for WAN |
|||
inv=$(basename $0) |
|||
[ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ |
|||
|| WHOLE_FILE_OPT="--whole-file" |
|||
|
|||
echo "flush tables" |
|||
|
|||
# wait for tables flushed and state ID written to the file |
|||
while [ ! -r "$FLUSHED" ] && ! grep -q ':' "$FLUSHED" >/dev/null 2>&1 |
|||
do |
|||
sleep 0.2 |
|||
done |
|||
|
|||
STATE="$(cat $FLUSHED)" |
|||
rm -rf "$FLUSHED" |
|||
|
|||
sync |
|||
|
|||
# first, the normal directories, so that we can detect incompatible protocol |
|||
RC=0 |
|||
rsync --archive --no-times --ignore-times --inplace --delete --quiet \ |
|||
--no-recursive --dirs \ |
|||
$WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ |
|||
rsync://$WSREP_SST_OPT_ADDR-with_filter || RC=$? |
|||
|
|||
[ $RC -ne 0 ] && wsrep_log_error "rsync returned code $RC:" |
|||
|
|||
case $RC in |
|||
0) RC=0 # Success |
|||
;; |
|||
12) RC=71 # EPROTO |
|||
wsrep_log_error \ |
|||
"rsync server on the other end has incompatible protocol. " \ |
|||
"Make sure you have the same version of rsync on all nodes." |
|||
;; |
|||
22) RC=12 # ENOMEM |
|||
;; |
|||
*) RC=255 # unknown error |
|||
;; |
|||
esac |
|||
|
|||
[ $RC -ne 0 ] && exit $RC |
|||
|
|||
# then, we parallelize the transfer of database directories, use . so that pathconcatenation works |
|||
pushd "$WSREP_SST_OPT_DATA" 1>/dev/null |
|||
|
|||
count=1 |
|||
[ "$OS" == "Linux" ] && count=$(grep -c processor /proc/cpuinfo) |
|||
[ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ] && count=$(sysctl -n hw.ncpu) |
|||
|
|||
find . -maxdepth 1 -mindepth 1 -type d -print0 | xargs -I{} -0 -P $count \ |
|||
rsync --archive --no-times --ignore-times --inplace --delete --quiet \ |
|||
$WHOLE_FILE_OPT "$WSREP_SST_OPT_DATA"/{}/ \ |
|||
rsync://$WSREP_SST_OPT_ADDR/{} || RC=$? |
|||
|
|||
popd 1>/dev/null |
|||
|
|||
[ $RC -ne 0 ] && wsrep_log_error "find/rsync returned code $RC:" |
|||
|
|||
case $RC in |
|||
0) RC=0 # Success |
|||
;; |
|||
*) RC=255 # unknown error |
|||
;; |
|||
esac |
|||
|
|||
[ $RC -ne 0 ] && exit $RC |
|||
|
|||
|
|||
else # BYPASS |
|||
wsrep_log_info "Bypassing state dump." |
|||
STATE="$WSREP_SST_OPT_GTID" |
|||
fi |
|||
|
|||
echo "continue" # now server can resume updating data |
|||
|
|||
echo "$STATE" > "$MAGIC_FILE" |
|||
rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR |
|||
|
|||
echo "done $STATE" |
|||
|
|||
elif [ "$WSREP_SST_OPT_ROLE" = "joiner" ] |
|||
then |
|||
touch $SST_PROGRESS_FILE |
|||
MYSQLD_PID=$WSREP_SST_OPT_PARENT |
|||
|
|||
MODULE="rsync_sst" |
|||
|
|||
RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" |
|||
|
|||
if check_pid $RSYNC_PID |
|||
then |
|||
wsrep_log_error "rsync daemon already running." |
|||
exit 114 # EALREADY |
|||
fi |
|||
rm -rf "$RSYNC_PID" |
|||
|
|||
ADDR=$WSREP_SST_OPT_ADDR |
|||
RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }') |
|||
if [ -z "$RSYNC_PORT" ] |
|||
then |
|||
RSYNC_PORT=4444 |
|||
ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT" |
|||
fi |
|||
|
|||
trap "exit 32" HUP PIPE |
|||
trap "exit 3" INT TERM ABRT |
|||
trap cleanup_joiner EXIT |
|||
|
|||
MYUID=$(id -u) |
|||
MYGID=$(id -g) |
|||
RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" |
|||
|
|||
cat << EOF > "$RSYNC_CONF" |
|||
pid file = $RSYNC_PID |
|||
use chroot = no |
|||
[$MODULE-with_filter] |
|||
path = $WSREP_SST_OPT_DATA |
|||
read only = no |
|||
timeout = 300 |
|||
uid = $MYUID |
|||
gid = $MYGID |
|||
filter = $FILTER_DAEMON |
|||
[$MODULE] |
|||
path = $WSREP_SST_OPT_DATA |
|||
read only = no |
|||
timeout = 300 |
|||
uid = $MYUID |
|||
gid = $MYGID |
|||
EOF |
|||
|
|||
# rm -rf "$DATA"/ib_logfile* # we don't want old logs around |
|||
|
|||
# listen at all interfaces (for firewalled setups) |
|||
rsync --daemon --port $RSYNC_PORT --config "$RSYNC_CONF" |
|||
|
|||
until check_pid_and_port $RSYNC_PID $RSYNC_PORT |
|||
do |
|||
sleep 0.2 |
|||
done |
|||
|
|||
echo "ready $ADDR/$MODULE" |
|||
|
|||
# wait for SST to complete by monitoring magic file |
|||
while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ |
|||
ps -p $MYSQLD_PID >/dev/null |
|||
do |
|||
sleep 1 |
|||
done |
|||
|
|||
if ! ps -p $MYSQLD_PID >/dev/null |
|||
then |
|||
wsrep_log_error \ |
|||
"Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly." |
|||
exit 32 |
|||
fi |
|||
|
|||
if [ -r "$MAGIC_FILE" ] |
|||
then |
|||
cat "$MAGIC_FILE" # output UUID:seqno |
|||
else |
|||
# this message should cause joiner to abort |
|||
echo "rsync process ended without creating '$MAGIC_FILE'" |
|||
fi |
|||
wsrep_cleanup_progress_file |
|||
# cleanup_joiner |
|||
else |
|||
wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" |
|||
exit 22 # EINVAL |
|||
fi |
|||
|
|||
exit 0 |
@ -0,0 +1,481 @@ |
|||
#!/bin/bash -ue |
|||
# 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-1301 USA. |
|||
|
|||
############################################################################################################# |
|||
# This is a reference script for Percona XtraBackup-based state snapshot transfer # |
|||
# Dependencies: (depending on configuration) # |
|||
# xbcrypt for encryption/decryption. # |
|||
# qpress for decompression. Download from http://www.quicklz.com/qpress-11-linux-x64.tar till # |
|||
# https://blueprints.launchpad.net/percona-xtrabackup/+spec/package-qpress is fixed. # |
|||
# my_print_defaults to extract values from my.cnf. # |
|||
# netcat for transfer. # |
|||
# xbstream/tar for streaming. (and xtrabackup ofc) # |
|||
# # |
|||
# Currently only option in cnf is read specifically for SST # |
|||
# [sst] # |
|||
# streamfmt=tar|xbstream # |
|||
# # |
|||
# Default is tar till lp:1193240 is fixed # |
|||
# You need to use xbstream for encryption, compression etc., however, # |
|||
# lp:1193240 requires you to manually cleanup the directory prior to SST # |
|||
# # |
|||
############################################################################################################# |
|||
|
|||
. $(dirname $0)/wsrep_sst_common |
|||
|
|||
ealgo="" |
|||
ekey="" |
|||
ekeyfile="" |
|||
encrypt=0 |
|||
nproc=1 |
|||
ecode=0 |
|||
XTRABACKUP_PID="" |
|||
|
|||
sfmt="tar" |
|||
strmcmd="" |
|||
declare -a RC |
|||
|
|||
get_keys() |
|||
{ |
|||
# There is no metadata in the stream to indicate that it is encrypted |
|||
# So, if the cnf file on joiner contains 'encrypt' under [xtrabackup] section then |
|||
# it means encryption is being used |
|||
if ! my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt; then |
|||
return |
|||
fi |
|||
if [[ $sfmt == 'tar' ]];then |
|||
wsrep_log_info "NOTE: Encryption cannot be enabled with tar format" |
|||
return |
|||
fi |
|||
|
|||
wsrep_log_info "Encryption enabled in my.cnf - not supported at the moment - Bug in Xtrabackup - lp:1190343" |
|||
ealgo=$(my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -- '--encrypt=' | cut -d= -f2) |
|||
ekey=$(my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -- '--encrypt-key=' | cut -d= -f2) |
|||
ekeyfile=$(my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -- '--encrypt-key-file=' | cut -d= -f2) |
|||
|
|||
if [[ -z $ealgo ]];then |
|||
wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out" |
|||
exit 3 |
|||
fi |
|||
|
|||
if [[ -z $ekey && ! -r $ekeyfile ]];then |
|||
wsrep_log_error "FATAL: Either key or keyfile must be readable" |
|||
exit 3 |
|||
fi |
|||
encrypt=1 |
|||
} |
|||
|
|||
read_cnf() |
|||
{ |
|||
sfmt=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- '--streamfmt' | cut -d= -f2) |
|||
if [[ $sfmt == 'xbstream' ]];then |
|||
wsrep_log_info "Streaming with xbstream" |
|||
if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then |
|||
wsrep_log_info "xbstream requires manual cleanup of data directory before SST - lp:1193240" |
|||
strmcmd="xbstream -x -C ${DATA}" |
|||
elif [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then |
|||
strmcmd="xbstream -c ${INFO_FILE} ${IST_FILE}" |
|||
else |
|||
wsrep_log_error "Invalid role: $WSREP_SST_OPT_ROLE" |
|||
exit 22 |
|||
fi |
|||
else |
|||
sfmt="tar" |
|||
wsrep_log_info "Streaming with tar" |
|||
wsrep_log_info "Note: Advanced xtrabackup features - encryption,compression etc. not available with tar." |
|||
if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then |
|||
wsrep_log_info "However, xbstream requires manual cleanup of data directory before SST - lp:1193240." |
|||
strmcmd="tar xfi - -C ${DATA}" |
|||
elif [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then |
|||
strmcmd="tar cf - ${INFO_FILE} ${IST_FILE}" |
|||
else |
|||
wsrep_log_error "Invalid role: $WSREP_SST_OPT_ROLE" |
|||
exit 22 |
|||
fi |
|||
|
|||
fi |
|||
} |
|||
|
|||
get_proc() |
|||
{ |
|||
set +e |
|||
nproc=$(grep -c processor /proc/cpuinfo) |
|||
[[ -z $nproc || $nproc -eq 0 ]] && nproc=1 |
|||
set -e |
|||
} |
|||
|
|||
cleanup_joiner() |
|||
{ |
|||
# 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 |
|||
local PID=$(ps -aef |grep nc| grep $NC_PORT | awk '{ print $2 }') |
|||
if [[ $estatus -ne 0 ]];then |
|||
wsrep_log_error "Killing nc pid $PID" |
|||
else |
|||
wsrep_log_info "Killing nc pid $PID" |
|||
fi |
|||
[ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : |
|||
rm -f "$MAGIC_FILE" |
|||
if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then |
|||
wsrep_log_info "Removing the sst_in_progress file" |
|||
wsrep_cleanup_progress_file |
|||
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 |
|||
local estatus=$? |
|||
if [[ $estatus -ne 0 ]];then |
|||
wsrep_log_error "Cleanup after exit with status:$estatus" |
|||
fi |
|||
local pid=$XTRABACKUP_PID |
|||
if check_pid "$pid" |
|||
then |
|||
wsrep_log_error "xtrabackup process is still running. Killing... " |
|||
kill_xtrabackup |
|||
fi |
|||
|
|||
rm -f "$pid" |
|||
rm -f ${DATA}/${IST_FILE} |
|||
} |
|||
|
|||
kill_xtrabackup() |
|||
{ |
|||
#set -x |
|||
local PID=$(cat $XTRABACKUP_PID) |
|||
[ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : |
|||
rm -f "$XTRABACKUP_PID" |
|||
#set +x |
|||
} |
|||
|
|||
# waits ~10 seconds for nc to open the port and then reports ready |
|||
# (regardless of timeout) |
|||
wait_for_nc() |
|||
{ |
|||
local PORT=$1 |
|||
local ADDR=$2 |
|||
local MODULE=$3 |
|||
for i in $(seq 1 50) |
|||
do |
|||
netstat -nptl 2>/dev/null | grep '/nc\s*$' | awk '{ print $4 }' | \ |
|||
sed 's/.*://' | grep \^${PORT}\$ >/dev/null && break |
|||
sleep 0.2 |
|||
done |
|||
echo "ready ${ADDR}/${MODULE}" |
|||
} |
|||
|
|||
INNOBACKUPEX_BIN=innobackupex |
|||
INNOBACKUPEX_ARGS="" |
|||
NC_BIN=nc |
|||
|
|||
for TOOL_BIN in INNOBACKUPEX_BIN NC_BIN ; do |
|||
if ! which ${!TOOL_BIN} > /dev/null 2>&1 |
|||
then |
|||
echo "Can't find ${!TOOL_BIN} in the path" |
|||
exit 22 # EINVAL |
|||
fi |
|||
done |
|||
|
|||
#ROLE=$1 |
|||
#ADDR=$2 |
|||
readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ }) |
|||
readonly DATA="${WSREP_SST_OPT_DATA}" |
|||
#CONF=$5 |
|||
|
|||
INFO_FILE="xtrabackup_galera_info" |
|||
IST_FILE="xtrabackup_ist" |
|||
|
|||
MAGIC_FILE="${DATA}/${INFO_FILE}" |
|||
rm -f "${MAGIC_FILE}" |
|||
|
|||
read_cnf |
|||
|
|||
if [ "$WSREP_SST_OPT_ROLE" = "donor" ] |
|||
then |
|||
trap cleanup_donor EXIT |
|||
|
|||
NC_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }') |
|||
REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }') |
|||
|
|||
if [ $WSREP_SST_OPT_BYPASS -eq 0 ] |
|||
then |
|||
TMPDIR="/tmp" |
|||
|
|||
INNOBACKUPEX_ARGS="--galera-info --stream=$sfmt |
|||
--defaults-file=${WSREP_SST_OPT_CONF} |
|||
--socket=${WSREP_SST_OPT_SOCKET}" |
|||
|
|||
if [ "${AUTH[0]}" != "(null)" ]; then |
|||
INNOBACKUPEX_ARGS="${INNOBACKUPEX_ARGS} --user=${AUTH[0]}" |
|||
fi |
|||
|
|||
if [ ${#AUTH[*]} -eq 2 ]; then |
|||
INNOBACKUPEX_ARGS="${INNOBACKUPEX_ARGS} --password=${AUTH[1]}" |
|||
else |
|||
# Empty password, used for testing, debugging etc. |
|||
INNOBACKUPEX_ARGS="${INNOBACKUPEX_ARGS} --password=" |
|||
fi |
|||
|
|||
get_keys |
|||
if [[ $encrypt -eq 1 ]];then |
|||
if [[ -n $ekey ]];then |
|||
INNOBACKUPEX_ARGS="${INNOBACKUPEX_ARGS} --encrypt=$ealgo --encrypt-key=$ekey" |
|||
else |
|||
INNOBACKUPEX_ARGS="${INNOBACKUPEX_ARGS} --encrypt=$ealgo --encrypt-key-file=$ekeyfile" |
|||
fi |
|||
fi |
|||
|
|||
wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${NC_PORT}" |
|||
|
|||
set +e |
|||
${INNOBACKUPEX_BIN} ${INNOBACKUPEX_ARGS} ${TMPDIR} \ |
|||
2> ${DATA}/innobackup.backup.log | \ |
|||
${NC_BIN} ${REMOTEIP} ${NC_PORT} |
|||
|
|||
RC=( "${PIPESTATUS[@]}" ) |
|||
set -e |
|||
|
|||
if [ ${RC[0]} -ne 0 ]; then |
|||
wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \ |
|||
"Check ${DATA}/innobackup.backup.log" |
|||
exit 22 |
|||
elif [ ${RC[1]} -ne 0 ]; then |
|||
wsrep_log_error "${NC_BIN} finished with error: ${RC[1]}" |
|||
exit 22 |
|||
fi |
|||
|
|||
# innobackupex implicitly writes PID to fixed location in ${TMPDIR} |
|||
XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid" |
|||
|
|||
|
|||
else # BYPASS |
|||
wsrep_log_info "Bypassing the SST for IST" |
|||
STATE="${WSREP_SST_OPT_GTID}" |
|||
echo "continue" # now server can resume updating data |
|||
echo "${STATE}" > "${MAGIC_FILE}" |
|||
echo "1" > "${DATA}/${IST_FILE}" |
|||
get_keys |
|||
pushd ${DATA} 1>/dev/null |
|||
set +e |
|||
if [[ $encrypt -eq 1 ]];then |
|||
if [[ -n $ekey ]];then |
|||
xbstream -c ${INFO_FILE} ${IST_FILE} | xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey | ${NC_BIN} ${REMOTEIP} ${NC_PORT} |
|||
else |
|||
xbstream -c ${INFO_FILE} ${IST_FILE} | xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile | ${NC_BIN} ${REMOTEIP} ${NC_PORT} |
|||
fi |
|||
else |
|||
$strmcmd | ${NC_BIN} ${REMOTEIP} ${NC_PORT} |
|||
fi |
|||
RC=( "${PIPESTATUS[@]}" ) |
|||
set -e |
|||
popd 1>/dev/null |
|||
|
|||
for ecode in "${RC[@]}";do |
|||
if [[ $ecode -ne 0 ]];then |
|||
wsrep_log_error "Error while streaming data to joiner node: " \ |
|||
"exit codes: ${RC[@]}" |
|||
exit 1 |
|||
fi |
|||
done |
|||
#rm -f ${DATA}/${IST_FILE} |
|||
fi |
|||
|
|||
echo "done ${WSREP_SST_OPT_GTID}" |
|||
|
|||
elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ] |
|||
then |
|||
[[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE" |
|||
touch $SST_PROGRESS_FILE |
|||
|
|||
sencrypted=1 |
|||
nthreads=1 |
|||
|
|||
MODULE="xtrabackup_sst" |
|||
|
|||
rm -f ${DATA}/xtrabackup_* |
|||
|
|||
ADDR=${WSREP_SST_OPT_ADDR} |
|||
NC_PORT=$(echo ${ADDR} | awk -F ':' '{ print $2 }') |
|||
if [ -z "${NC_PORT}" ] |
|||
then |
|||
NC_PORT=4444 |
|||
ADDR="$(echo ${ADDR} | awk -F ':' '{ print $1 }'):${NC_PORT}" |
|||
fi |
|||
|
|||
wait_for_nc ${NC_PORT} ${ADDR} ${MODULE} & |
|||
|
|||
trap "exit 32" HUP PIPE |
|||
trap "exit 3" INT TERM |
|||
trap cleanup_joiner EXIT |
|||
|
|||
get_keys |
|||
set +e |
|||
if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then |
|||
if [[ -n $ekey ]];then |
|||
${NC_BIN} -dl ${NC_PORT} | xbcrypt -d --encrypt-algo=$ealgo --encrypt-key=$ekey | xbstream -x -C ${DATA} |
|||
else |
|||
${NC_BIN} -dl ${NC_PORT} | xbcrypt -d --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile | xbstream -x -C ${DATA} |
|||
fi |
|||
else |
|||
${NC_BIN} -dl ${NC_PORT} | $strmcmd |
|||
fi |
|||
RC=( "${PIPESTATUS[@]}" ) |
|||
set -e |
|||
|
|||
if [[ $sfmt == 'xbstream' ]];then |
|||
# Special handling till lp:1193240 is fixed" |
|||
if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then |
|||
wsrep_log_error "Xbstream failed" |
|||
wsrep_log_error "Data directory ${DATA} needs to be empty for SST: lp:1193240" \ |
|||
"Manual intervention required in that case" |
|||
exit 32 |
|||
fi |
|||
fi |
|||
|
|||
wait %% # join wait_for_nc thread |
|||
|
|||
for ecode in "${RC[@]}";do |
|||
if [[ $ecode -ne 0 ]];then |
|||
wsrep_log_error "Error while getting data from donor node: " \ |
|||
"exit codes: ${RC[@]}" |
|||
wsrep_log_error "Data directory ${DATA} needs to be empty for SST:" \ |
|||
"Manual intervention required in that case" |
|||
exit 32 |
|||
fi |
|||
done |
|||
|
|||
if [ ! -r "${MAGIC_FILE}" ] |
|||
then |
|||
# this message should cause joiner to abort |
|||
wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'" |
|||
exit 32 |
|||
fi |
|||
|
|||
if ! ps -p ${WSREP_SST_OPT_PARENT} >/dev/null |
|||
then |
|||
wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly." |
|||
exit 32 |
|||
fi |
|||
|
|||
if [ ! -r "${IST_FILE}" ] |
|||
then |
|||
wsrep_log_info "Proceeding with SST" |
|||
rebuild="" |
|||
wsrep_log_info "Removing existing ib_logfile files" |
|||
rm -f ${DATA}/ib_logfile* |
|||
|
|||
# Decrypt only if not encrypted in stream. |
|||
# NOT USED NOW. |
|||
# Till https://blueprints.launchpad.net/percona-xtrabackup/+spec/add-support-for-rsync-url |
|||
# is implemented |
|||
#get_keys |
|||
if [[ $encrypt -eq 1 && $sencrypted -eq 0 ]];then |
|||
# Decrypt the files if any |
|||
find ${DATA} -type f -name '*.xbcrypt' -printf '%p\n' | while read line;do |
|||
input=$line |
|||
output=${input%.xbcrypt} |
|||
|
|||
if [[ -n $ekey ]];then |
|||
xbcrypt -d --encrypt-algo=$ealgo --encrypt-key=$ekey -i $input > $output |
|||
else |
|||
xbcrypt -d --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile -i $input > $output |
|||
fi |
|||
done |
|||
|
|||
if [[ $? = 0 ]];then |
|||
find ${DATA} -type f -name '*.xbcrypt' -delete |
|||
fi |
|||
fi |
|||
|
|||
get_proc |
|||
|
|||
# Rebuild indexes for compact backups |
|||
if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then |
|||
wsrep_log_info "Index compaction detected" |
|||
nthreads=$(my_print_defaults -c $WSREP_SST_OPT_CONF xtrabackup | grep -- '--rebuild-threads' | cut -d= -f2) |
|||
[[ -z $nthreads ]] && nthreads=$nproc |
|||
wsrep_log_info "Rebuilding with $nthreads threads" |
|||
rebuild="--rebuild-indexes --rebuild-threads=$nthreads" |
|||
fi |
|||
|
|||
if test -n "$(find ${DATA} -maxdepth 1 -name '*.qp' -print -quit)";then |
|||
|
|||
wsrep_log_info "Compressed qpress files found" |
|||
|
|||
if [[ ! -x `which qpress` ]];then |
|||
wsrep_log_error "qpress not found in PATH" |
|||
exit 22 |
|||
fi |
|||
|
|||
set +e |
|||
|
|||
wsrep_log_info "Removing existing ibdata1 file" |
|||
rm -f ${DATA}/ibdata1 |
|||
|
|||
# Decompress the qpress files |
|||
wsrep_log_info "Decompression with $nproc threads" |
|||
find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | xargs -P $nproc -n 2 qpress -d |
|||
extcode=$? |
|||
|
|||
set -e |
|||
|
|||
if [[ $extcode -eq 0 ]];then |
|||
wsrep_log_info "Removing qpress files after decompression" |
|||
find ${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}" |
|||
|
|||
${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log $rebuild \ |
|||
${DATA} 1>&2 2> ${DATA}/innobackup.prepare.log |
|||
if [ $? -ne 0 ]; |
|||
then |
|||
wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log" |
|||
exit 22 |
|||
fi |
|||
else |
|||
wsrep_log_info "${IST_FILE} received from donor: Running IST" |
|||
fi |
|||
|
|||
cat "${MAGIC_FILE}" # output UUID:seqno |
|||
|
|||
#Cleanup not required here since EXIT trap should be called |
|||
#wsrep_cleanup_progress_file |
|||
|
|||
else |
|||
wsrep_log_error "Unrecognized role: ${WSREP_SST_OPT_ROLE}" |
|||
exit 22 # EINVAL |
|||
fi |
|||
|
|||
exit 0 |
@ -0,0 +1,468 @@ |
|||
/* Copyright 2010 Codership Oy <http://www.codership.com> |
|||
|
|||
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; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|||
*/ |
|||
|
|||
//! @file declares symbols private to wsrep integration layer |
|||
|
|||
#ifndef _GNU_SOURCE |
|||
#define _GNU_SOURCE // POSIX_SPAWN_USEVFORK flag |
|||
#endif |
|||
|
|||
#include <spawn.h> // posix_spawn() |
|||
#include <unistd.h> // pipe() |
|||
#include <errno.h> // errno |
|||
#include <string.h> // strerror() |
|||
#include <sys/wait.h> // waitpid() |
|||
|
|||
#include <sql_class.h> |
|||
#include "wsrep_priv.h" |
|||
|
|||
extern char** environ; // environment variables |
|||
|
|||
static wsp::string wsrep_PATH; |
|||
|
|||
void |
|||
wsrep_prepend_PATH (const char* path) |
|||
{ |
|||
int count = 0; |
|||
|
|||
while (environ[count]) |
|||
{ |
|||
if (strncmp (environ[count], "PATH=", 5)) |
|||
{ |
|||
count++; |
|||
continue; |
|||
} |
|||
|
|||
char* const old_path (environ[count]); |
|||
|
|||
if (strstr (old_path, path)) return; // path already there |
|||
|
|||
size_t const new_path_len(strlen(old_path) + strlen(":") + |
|||
strlen(path) + 1); |
|||
|
|||
char* const new_path (reinterpret_cast<char*>(malloc(new_path_len))); |
|||
|
|||
if (new_path) |
|||
{ |
|||
snprintf (new_path, new_path_len, "PATH=%s:%s", path, |
|||
old_path + strlen("PATH=")); |
|||
|
|||
wsrep_PATH.set (new_path); |
|||
environ[count] = new_path; |
|||
} |
|||
else |
|||
{ |
|||
WSREP_ERROR ("Failed to allocate 'PATH' environment variable " |
|||
"buffer of size %zu.", new_path_len); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
WSREP_ERROR ("Failed to find 'PATH' environment variable. " |
|||
"State snapshot transfer may not be working."); |
|||
} |
|||
|
|||
namespace wsp |
|||
{ |
|||
|
|||
#define PIPE_READ 0 |
|||
#define PIPE_WRITE 1 |
|||
#define STDIN_FD 0 |
|||
#define STDOUT_FD 1 |
|||
|
|||
#ifndef POSIX_SPAWN_USEVFORK |
|||
# define POSIX_SPAWN_USEVFORK 0 |
|||
#endif |
|||
|
|||
process::process (const char* cmd, const char* type) |
|||
: str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0) |
|||
{ |
|||
if (0 == str_) |
|||
{ |
|||
WSREP_ERROR ("Can't allocate command line of size: %zu", strlen(cmd)); |
|||
err_ = ENOMEM; |
|||
return; |
|||
} |
|||
|
|||
if (0 == strlen(str_)) |
|||
{ |
|||
WSREP_ERROR ("Can't start a process: null or empty command line."); |
|||
return; |
|||
} |
|||
|
|||
if (NULL == type || (strcmp (type, "w") && strcmp(type, "r"))) |
|||
{ |
|||
WSREP_ERROR ("type argument should be either \"r\" or \"w\"."); |
|||
return; |
|||
} |
|||
|
|||
int pipe_fds[2] = { -1, }; |
|||
if (::pipe(pipe_fds)) |
|||
{ |
|||
err_ = errno; |
|||
WSREP_ERROR ("pipe() failed: %d (%s)", err_, strerror(err_)); |
|||
return; |
|||
} |
|||
|
|||
// which end of pipe will be returned to parent |
|||
int const parent_end (strcmp(type,"w") ? PIPE_READ : PIPE_WRITE); |
|||
int const child_end (parent_end == PIPE_READ ? PIPE_WRITE : PIPE_READ); |
|||
int const close_fd (parent_end == PIPE_READ ? STDOUT_FD : STDIN_FD); |
|||
|
|||
char* const pargv[4] = { strdup("sh"), strdup("-c"), strdup(str_), NULL }; |
|||
if (!(pargv[0] && pargv[1] && pargv[2])) |
|||
{ |
|||
err_ = ENOMEM; |
|||
WSREP_ERROR ("Failed to allocate pargv[] array."); |
|||
goto cleanup_pipe; |
|||
} |
|||
|
|||
posix_spawnattr_t attr; |
|||
err_ = posix_spawnattr_init (&attr); |
|||
if (err_) |
|||
{ |
|||
WSREP_ERROR ("posix_spawnattr_init() failed: %d (%s)", |
|||
err_, strerror(err_)); |
|||
goto cleanup_pipe; |
|||
} |
|||
|
|||
err_ = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF | |
|||
POSIX_SPAWN_USEVFORK); |
|||
if (err_) |
|||
{ |
|||
WSREP_ERROR ("posix_spawnattr_setflags() failed: %d (%s)", |
|||
err_, strerror(err_)); |
|||
goto cleanup_attr; |
|||
} |
|||
|
|||
posix_spawn_file_actions_t fact; |
|||
err_ = posix_spawn_file_actions_init (&fact); |
|||
if (err_) |
|||
{ |
|||
WSREP_ERROR ("posix_spawn_file_actions_init() failed: %d (%s)", |
|||
err_, strerror(err_)); |
|||
goto cleanup_attr; |
|||
} |
|||
|
|||
// close child's stdout|stdin depending on what we returning |
|||
err_ = posix_spawn_file_actions_addclose (&fact, close_fd); |
|||
if (err_) |
|||
{ |
|||
WSREP_ERROR ("posix_spawn_file_actions_addclose() failed: %d (%s)", |
|||
err_, strerror(err_)); |
|||
goto cleanup_fact; |
|||
} |
|||
|
|||
// substitute our pipe descriptor in place of the closed one |
|||
err_ = posix_spawn_file_actions_adddup2 (&fact, |
|||
pipe_fds[child_end], close_fd); |
|||
if (err_) |
|||
{ |
|||
WSREP_ERROR ("posix_spawn_file_actions_addup2() failed: %d (%s)", |
|||
err_, strerror(err_)); |
|||
goto cleanup_fact; |
|||
} |
|||
|
|||
err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ); |
|||
if (err_) |
|||
{ |
|||
WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)", |
|||
pargv[2], err_, strerror(err_)); |
|||
pid_ = 0; // just to make sure it was not messed up in the call |
|||
goto cleanup_fact; |
|||
} |
|||
|
|||
io_ = fdopen (pipe_fds[parent_end], type); |
|||
|
|||
if (io_) |
|||
{ |
|||
pipe_fds[parent_end] = -1; // skip close on cleanup |
|||
} |
|||
else |
|||
{ |
|||
err_ = errno; |
|||
WSREP_ERROR ("fdopen() failed: %d (%s)", err_, strerror(err_)); |
|||
} |
|||
|
|||
cleanup_fact: |
|||
int err; // to preserve err_ code |
|||
err = posix_spawn_file_actions_destroy (&fact); |
|||
if (err) |
|||
{ |
|||
WSREP_ERROR ("posix_spawn_file_actions_destroy() failed: %d (%s)\n", |
|||
err, strerror(err)); |
|||
} |
|||
|
|||
cleanup_attr: |
|||
err = posix_spawnattr_destroy (&attr); |
|||
if (err) |
|||
{ |
|||
WSREP_ERROR ("posix_spawnattr_destroy() failed: %d (%s)", |
|||
err, strerror(err)); |
|||
} |
|||
|
|||
cleanup_pipe: |
|||
if (pipe_fds[0] >= 0) close (pipe_fds[0]); |
|||
if (pipe_fds[1] >= 0) close (pipe_fds[1]); |
|||
|
|||
free (pargv[0]); |
|||
free (pargv[1]); |
|||
free (pargv[2]); |
|||
} |
|||
|
|||
process::~process () |
|||
{ |
|||
if (io_) |
|||
{ |
|||
assert (pid_); |
|||
assert (str_); |
|||
|
|||
WSREP_WARN("Closing pipe to child process: %s, PID(%ld) " |
|||
"which might still be running.", str_, (long)pid_); |
|||
|
|||
if (fclose (io_) == -1) |
|||
{ |
|||
err_ = errno; |
|||
WSREP_ERROR("fclose() failed: %d (%s)", err_, strerror(err_)); |
|||
} |
|||
} |
|||
|
|||
if (str_) free (const_cast<char*>(str_)); |
|||
} |
|||
|
|||
int |
|||
process::wait () |
|||
{ |
|||
if (pid_) |
|||
{ |
|||
int status; |
|||
if (-1 == waitpid(pid_, &status, 0)) |
|||
{ |
|||
err_ = errno; assert (err_); |
|||
WSREP_ERROR("Waiting for process failed: %s, PID(%ld): %d (%s)", |
|||
str_, (long)pid_, err_, strerror (err_)); |
|||
} |
|||
else |
|||
{ // command completed, check exit status |
|||
if (WIFEXITED (status)) { |
|||
err_ = WEXITSTATUS (status); |
|||
} |
|||
else { // command didn't complete with exit() |
|||
WSREP_ERROR("Process was aborted."); |
|||
err_ = errno ? errno : ECHILD; |
|||
} |
|||
|
|||
if (err_) { |
|||
switch (err_) /* Translate error codes to more meaningful */ |
|||
{ |
|||
case 126: err_ = EACCES; break; /* Permission denied */ |
|||
case 127: err_ = ENOENT; break; /* No such file or directory */ |
|||
} |
|||
WSREP_ERROR("Process completed with error: %s: %d (%s)", |
|||
str_, err_, strerror(err_)); |
|||
} |
|||
|
|||
pid_ = 0; |
|||
if (io_) fclose (io_); |
|||
io_ = NULL; |
|||
} |
|||
} |
|||
else { |
|||
assert (NULL == io_); |
|||
WSREP_ERROR("Command did not run: %s", str_); |
|||
} |
|||
|
|||
return err_; |
|||
} |
|||
|
|||
thd::thd (my_bool won) : init(), ptr(new THD) |
|||
{ |
|||
if (ptr) |
|||
{ |
|||
ptr->thread_stack= (char*) &ptr; |
|||
ptr->store_globals(); |
|||
ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog |
|||
ptr->variables.wsrep_on = won; |
|||
ptr->security_ctx->master_access= ~(ulong)0; |
|||
lex_start(ptr); |
|||
} |
|||
} |
|||
|
|||
thd::~thd () |
|||
{ |
|||
if (ptr) |
|||
{ |
|||
delete ptr; |
|||
my_pthread_setspecific_ptr (THR_THD, 0); |
|||
} |
|||
} |
|||
|
|||
} // namespace wsp |
|||
|
|||
extern ulong my_bind_addr; |
|||
extern uint mysqld_port; |
|||
|
|||
size_t guess_ip (char* buf, size_t buf_len) |
|||
{ |
|||
size_t ip_len = 0; |
|||
|
|||
if (htonl(INADDR_NONE) == my_bind_addr) { |
|||
WSREP_ERROR("Networking not configured, cannot receive state transfer."); |
|||
return 0; |
|||
} |
|||
|
|||
if (htonl(INADDR_ANY) != my_bind_addr) { |
|||
uint8_t* b = (uint8_t*)&my_bind_addr; |
|||
ip_len = snprintf (buf, buf_len, |
|||
"%hhu.%hhu.%hhu.%hhu", b[0],b[1],b[2],b[3]); |
|||
return ip_len; |
|||
} |
|||
|
|||
// mysqld binds to all interfaces - try IP from wsrep_node_address |
|||
if (wsrep_node_address && wsrep_node_address[0] != '\0') { |
|||
const char* const colon_ptr = strchr(wsrep_node_address, ':'); |
|||
|
|||
if (colon_ptr) |
|||
ip_len = colon_ptr - wsrep_node_address; |
|||
else |
|||
ip_len = strlen(wsrep_node_address); |
|||
|
|||
if (ip_len >= buf_len) { |
|||
WSREP_WARN("default_ip(): buffer too short: %zu <= %zd", buf_len, ip_len); |
|||
return 0; |
|||
} |
|||
|
|||
memcpy (buf, wsrep_node_address, ip_len); |
|||
buf[ip_len] = '\0'; |
|||
return ip_len; |
|||
} |
|||
|
|||
// try to find the address of the first one |
|||
#if (TARGET_OS_LINUX == 1) |
|||
const char cmd[] = "ip addr show | grep -E '^\\s*inet' | grep -m1 global |" |
|||
" awk '{ print $2 }' | sed 's/\\/.*//'"; |
|||
#elif defined(__sun__) |
|||
const char cmd[] = "/sbin/ifconfig -a | " |
|||
"/usr/gnu/bin/grep -m1 -1 -E 'net[0-9]:' | tail -n 1 | awk '{ print $2 }'"; |
|||
#elif defined(__APPLE__) || defined(__FreeBSD__) |
|||
const char cmd[] = "route -nv get 8.8.8.8 | tail -n1 | awk '{print $5}'"; |
|||
#else |
|||
char *cmd; |
|||
#error "OS not supported" |
|||
#endif |
|||
wsp::process proc (cmd, "r"); |
|||
|
|||
if (NULL != proc.pipe()) { |
|||
char* ret; |
|||
|
|||
ret = fgets (buf, buf_len, proc.pipe()); |
|||
|
|||
if (proc.wait()) return 0; |
|||
|
|||
if (NULL == ret) { |
|||
WSREP_ERROR("Failed to read output of: '%s'", cmd); |
|||
return 0; |
|||
} |
|||
} |
|||
else { |
|||
WSREP_ERROR("Failed to execute: '%s'", cmd); |
|||
return 0; |
|||
} |
|||
|
|||
// clear possible \n at the end of ip string left by fgets() |
|||
ip_len = strlen (buf); |
|||
if (ip_len > 0 && '\n' == buf[ip_len - 1]) { |
|||
ip_len--; |
|||
buf[ip_len] = '\0'; |
|||
} |
|||
|
|||
if (INADDR_NONE == inet_addr(buf)) { |
|||
if (strlen(buf) != 0) { |
|||
WSREP_WARN("Shell command returned invalid address: '%s'", buf); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
return ip_len; |
|||
} |
|||
|
|||
size_t guess_address(char* buf, size_t buf_len) |
|||
{ |
|||
size_t addr_len = guess_ip (buf, buf_len); |
|||
|
|||
if (addr_len && addr_len < buf_len) { |
|||
addr_len += snprintf (buf + addr_len, buf_len - addr_len, |
|||
":%u", mysqld_port); |
|||
} |
|||
|
|||
return addr_len; |
|||
} |
|||
|
|||
/* |
|||
* WSREPXid |
|||
*/ |
|||
|
|||
#define WSREP_XID_PREFIX "WSREPXid" |
|||
#define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN |
|||
#define WSREP_XID_UUID_OFFSET 8 |
|||
#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t)) |
|||
#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t)) |
|||
|
|||
void wsrep_xid_init(XID* xid, const wsrep_uuid_t* uuid, wsrep_seqno_t seqno) |
|||
{ |
|||
xid->formatID= 1; |
|||
xid->gtrid_length= WSREP_XID_GTRID_LEN; |
|||
xid->bqual_length= 0; |
|||
memset(xid->data, 0, sizeof(xid->data)); |
|||
memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN); |
|||
memcpy(xid->data + WSREP_XID_UUID_OFFSET, uuid, sizeof(wsrep_uuid_t)); |
|||
memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t)); |
|||
} |
|||
|
|||
const wsrep_uuid_t* wsrep_xid_uuid(const XID* xid) |
|||
{ |
|||
if (wsrep_is_wsrep_xid(xid)) |
|||
return reinterpret_cast<const wsrep_uuid_t*>(xid->data |
|||
+ WSREP_XID_UUID_OFFSET); |
|||
else |
|||
return &WSREP_UUID_UNDEFINED; |
|||
} |
|||
|
|||
wsrep_seqno_t wsrep_xid_seqno(const XID* xid) |
|||
{ |
|||
|
|||
if (wsrep_is_wsrep_xid(xid)) |
|||
{ |
|||
wsrep_seqno_t seqno; |
|||
memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t)); |
|||
return seqno; |
|||
} |
|||
else |
|||
{ |
|||
return WSREP_SEQNO_UNDEFINED; |
|||
} |
|||
} |
|||
|
|||
extern "C" |
|||
int wsrep_is_wsrep_xid(const void* xid_ptr) |
|||
{ |
|||
const XID* xid= reinterpret_cast<const XID*>(xid_ptr); |
|||
return (xid->formatID == 1 && |
|||
xid->gtrid_length == WSREP_XID_GTRID_LEN && |
|||
xid->bqual_length == 0 && |
|||
!memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN)); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue