Merging revision 3839..3932 from codership-mysql/5.5.

This commit is contained in:
Nirbhay Choubey 2014-01-09 14:54:57 -05:00
parent 088c069462
commit 31eaa90a6e
53 changed files with 3238 additions and 2283 deletions

View File

@ -33,12 +33,5 @@ IF(EXECINFO)
SET(LIBEXECINFO ${EXECINFO})
ENDIF()
# Use atomic builtins
IF(CMAKE_SIZEOF_VOID_P EQUAL 4 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "i386")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -march=i686")
ENDIF()
SET(HAVE_SYS_TIMEB_H CACHE INTERNAL "")

View File

@ -18,7 +18,7 @@
# so WSREP_VERSION is produced regardless
# Set the patch version
SET(WSREP_PATCH_VERSION "7.6")
SET(WSREP_PATCH_VERSION "9")
# Obtain patch revision number:
# The script tries to probe the bzr revision number using $ENV{WSREP_REV}, and

View File

@ -91,34 +91,6 @@ static my_bool defaults_already_read= FALSE;
/* The only purpose of this global array is to hold full name of my.cnf
* which seems to be otherwise unavailable */
char wsrep_defaults_file[FN_REFLEN + 10]={0,};
/* Command-line only option to start a new wsrep service instance */
#define WSREP_NEW_CLUSTER1 "--wsrep-new-cluster"
#define WSREP_NEW_CLUSTER2 "--wsrep_new_cluster"
/* This one is set to true when --wsrep-new-cluster is found in the command
* line arguments */
my_bool wsrep_new_cluster= FALSE;
/* Finds and removes --wsrep-new-cluster from the arguments list.
* Returns true if found. */
static my_bool find_wsrep_new_cluster (int* argc, char* argv[])
{
my_bool ret= FALSE;
int i;
for (i= *argc - 1; i > 0; i--)
{
if (!strcmp(argv[i], WSREP_NEW_CLUSTER1) ||
!strcmp(argv[i], WSREP_NEW_CLUSTER2))
{
ret= TRUE;
*argc -= 1;
/* preserve the order of remaining arguments */
memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i]));
argv[*argc]= NULL;
}
}
return ret;
}
#endif /* WITH_WREP */
/* Which directories are searched for options (and in which order) */
@ -557,9 +529,6 @@ int my_load_defaults(const char *conf_file, const char **groups,
init_alloc_root(&alloc,512,0);
if ((dirs= init_default_directories(&alloc)) == NULL)
goto err;
#ifdef WITH_WSREP
wsrep_new_cluster= find_wsrep_new_cluster(argc, argv[0]);
#endif /* WITH_WSREP */
/*
Check if the user doesn't want any default option processing
--no-defaults is always the first option

View File

@ -224,18 +224,21 @@ wsrep_pick_url() {
wsrep_start_position_opt=""
wsrep_recover_position() {
local mysqld_cmd="$@"
local wr_logfile=$(mktemp)
local euid=$(id -u)
local ret=0
local wr_logfile=$(mktemp $DATADIR/wsrep_recovery.XXXXXX)
[ "$euid" = "0" ] && chown $user $wr_logfile
chmod 600 $wr_logfile
log_notice "WSREP: Running position recovery with --log_error=$wr_logfile \
--pid-file="$DATADIR/`@HOSTNAME@`-recover.pid""
local wr_pidfile="$DATADIR/"`@HOSTNAME@`"-recover.pid"
eval_log_error "$mysqld_cmd --log_error=$wr_logfile --wsrep-recover \
--pid-file="$DATADIR/`@HOSTNAME@`-recover.pid""
local wr_options="--log_error='$wr_logfile' --pid-file='$wr_pidfile'"
log_notice "WSREP: Running position recovery with $wr_options"
eval_log_error "$mysqld_cmd --wsrep_recover $wr_options"
local rp="$(grep 'WSREP: Recovered position:' $wr_logfile)"
if [ -z "$rp" ]; then
@ -926,31 +929,6 @@ then
exit 1
fi
#
# Set mysqld's memory interleave policy.
#
if @TARGET_LINUX@ && test $numa_interleave -eq 1
then
# Locate numactl, ensure it exists.
if ! my_which numactl > /dev/null 2>&1
then
log_error "numactl command not found, required for --numa-interleave"
exit 1
# Attempt to run a command, ensure it works.
elif ! numactl --interleave=all true
then
log_error "numactl failed, check if numactl is properly installed"
fi
# Launch mysqld with numactl.
cmd="$cmd numactl --interleave=all"
elif test $numa_interleave -eq 1
then
log_error "--numa-interleave is not supported on this platform"
exit 1
fi
for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \
"--datadir=$DATADIR" "--plugin-dir=$plugin_dir" "$USER_OPTION"
do
@ -975,7 +953,7 @@ max_wsrep_restarts=0
while true
do
rm -f "$pid_file" # Some extra safety
rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety
start_time=`date +%M%S`

View File

@ -24,7 +24,7 @@
# 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 #
@ -362,8 +362,6 @@ then
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

View File

@ -48,6 +48,9 @@ IF(WITH_WSREP)
wsrep_sst.cc
wsrep_utils.cc
wsrep_var.cc
wsrep_binlog.cc
wsrep_applier.cc
wsrep_thd.cc
)
SET(WSREP_LIB wsrep)
ENDIF()

View File

@ -1147,7 +1147,7 @@ end:
DBUG_RETURN(ret);
}
#ifdef WITH_WSREP
int wsrep_create_event_query(THD *thd, uchar** buf, uint* buf_len)
int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len)
{
String log_query;

View File

@ -1248,7 +1248,7 @@ int ha_commit_trans(THD *thd, bool all)
#ifdef WITH_WSREP
if (!WSREP(thd) &&
thd->mdl_context.acquire_lock(&mdl_request,
thd->mdl_context.acquire_lock(&mdl_request,
#else
if (thd->mdl_context.acquire_lock(&mdl_request,
#endif /* WITH_WSREP */
@ -1313,8 +1313,9 @@ int ha_commit_trans(THD *thd, bool all)
else
{
/* not wsrep hton, bail to native mysql behavior */
#endif
#endif /* WITH_WSREP */
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error= 1;
#ifdef WITH_WSREP
} /* End of else */
#endif
@ -1426,7 +1427,7 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
#ifdef WSREP_PROC_INFO
char info[64]= { 0, };
snprintf (info, sizeof(info) - 1, "ha_commit_one_phase(%lld)",
(long long)thd->wsrep_trx_seqno);
(long long)wsrep_thd_trx_seqno(thd));
#else
const char info[]="ha_commit_one_phase()";
#endif /* WSREP_PROC_INFO */
@ -1462,7 +1463,7 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
}
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
thd->transaction.cleanup();
thd->transaction.cleanup();
#ifdef WITH_WSREP
if (WSREP(thd)) thd_proc_info(thd, tmp_info);
#endif /* WITH_WSREP */
@ -1546,8 +1547,7 @@ int ha_rollback_trans(THD *thd, bool all)
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
thd->transaction.cleanup();
thd->transaction.cleanup();
if (all)
thd->transaction_rollback_request= FALSE;

View File

@ -490,24 +490,10 @@ private:
};
handlerton *binlog_hton;
#ifdef WITH_WSREP
extern handlerton *wsrep_hton;
#endif
bool LOGGER::is_log_table_enabled(uint log_table_type)
{
switch (log_table_type) {
case QUERY_LOG_SLOW:
return (table_log_handler != NULL) && opt_slow_log;
case QUERY_LOG_GENERAL:
return (table_log_handler != NULL) && opt_log ;
default:
DBUG_ASSERT(0);
return FALSE; /* make compiler happy */
}
}
#ifdef WITH_WSREP
#if WITH_WSREP
/* the functions below depend on the definition of binlog_cache_manager class,
* so have to stay in this unit. */
IO_CACHE * get_trans_log(THD * thd)
{
binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*)
@ -515,7 +501,7 @@ IO_CACHE * get_trans_log(THD * thd)
if (cache_mngr)
{
return cache_mngr->get_binlog_cache_log(true);
}
}
else
{
WSREP_DEBUG("binlog cache not initialized, conn :%ld", thd->thread_id);
@ -523,7 +509,6 @@ IO_CACHE * get_trans_log(THD * thd)
}
}
bool wsrep_trans_cache_is_empty(THD *thd)
{
binlog_cache_mngr *const cache_mngr=
@ -535,6 +520,7 @@ void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end)
{
thd->binlog_flush_pending_rows_event(stmt_end);
}
void thd_binlog_trx_reset(THD * thd)
{
/*
@ -556,74 +542,21 @@ void thd_binlog_rollback_stmt(THD * thd)
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
if (cache_mngr) cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
}
/*
Write the contents of a cache to memory buffer.
#endif /* WITH_WSREP */
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
*/
int wsrep_write_cache(IO_CACHE *cache, uchar **buf, uint *buf_len)
bool LOGGER::is_log_table_enabled(uint log_table_type)
{
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
return ER_ERROR_ON_WRITE;
uint length= my_b_bytes_in_cache(cache);
long long total_length = 0;
uchar *buf_ptr = NULL;
do
{
/* bail out if buffer grows too large
This is a temporary fix to avoid flooding replication
TODO: remove this check for 0.7.4 release
*/
if (total_length > wsrep_max_ws_size)
{
WSREP_WARN("transaction size limit (%lld) exceeded: %lld",
wsrep_max_ws_size, total_length);
if (reinit_io_cache(cache, WRITE_CACHE, 0, 0, 0))
{
WSREP_WARN("failed to initialize io-cache");
}
if (buf_ptr) my_free(*buf);
*buf_len = 0;
return ER_ERROR_ON_WRITE;
}
if (total_length > 0)
{
*buf_len += length;
*buf = (uchar *)my_realloc(*buf, total_length+length, MYF(0));
if (!*buf)
{
WSREP_ERROR("io cache write problem: %d %d", *buf_len, length);
return ER_ERROR_ON_WRITE;
}
buf_ptr = *buf+total_length;
}
else
{
if (buf_ptr != NULL)
{
WSREP_ERROR("io cache alloc error: %d %d", *buf_len, length);
my_free(*buf);
}
if (length > 0)
{
*buf = (uchar *) my_malloc(length, MYF(0));
buf_ptr = *buf;
*buf_len = length;
}
}
total_length += length;
memcpy(buf_ptr, cache->read_pos, length);
cache->read_pos=cache->read_end;
} while ((cache->file >= 0) && (length= my_b_fill(cache)));
return 0;
switch (log_table_type) {
case QUERY_LOG_SLOW:
return (table_log_handler != NULL) && opt_slow_log;
case QUERY_LOG_GENERAL:
return (table_log_handler != NULL) && opt_log ;
default:
DBUG_ASSERT(0);
return FALSE; /* make compiler happy */
}
}
#endif
/* Check if a given table is opened log table */
int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
@ -1817,13 +1750,6 @@ static inline int
binlog_commit_flush_stmt_cache(THD *thd, bool all,
binlog_cache_mngr *cache_mngr)
{
#ifdef WITH_WSREP
if (thd->wsrep_mysql_replicated > 0)
{
WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", thd->wsrep_mysql_replicated);
return 0;
}
#endif
Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
FALSE, TRUE, TRUE, 0);
return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE));
@ -1841,6 +1767,13 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all,
static inline int
binlog_commit_flush_trx_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr)
{
#ifdef WITH_WSREP
if (thd->wsrep_mysql_replicated > 0)
{
WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", thd->wsrep_mysql_replicated);
return 0;
}
#endif
Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
TRUE, TRUE, TRUE, 0);
return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE));
@ -2104,12 +2037,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
if (ending_trans(thd, all) &&
((thd->variables.option_bits & OPTION_KEEP_LOG) ||
(trans_has_updated_non_trans_table(thd) &&
WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) ||
WSREP_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) ||
(cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) ||
WSREP_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) ||
(trans_has_updated_non_trans_table(thd) &&
ending_single_stmt_trans(thd,all) &&
WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED)))
WSREP_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED)))
error= binlog_rollback_flush_trx_cache(thd, all, cache_mngr);
/*
Truncate the cache if:
@ -2123,9 +2056,9 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
else if (ending_trans(thd, all) ||
(!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
(!stmt_has_updated_non_trans_table(thd) ||
WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_STMT) &&
WSREP_BINLOG_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_STMT) &&
(!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_MIXED)))
WSREP_BINLOG_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_MIXED)))
error= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
@ -5439,35 +5372,6 @@ err:
}
}
#ifdef WITH_WSREP
if (WSREP(thd) && wsrep_incremental_data_collection &&
(wsrep_emulate_bin_log || mysql_bin_log.is_open()))
{
DBUG_ASSERT(thd->wsrep_trx_handle.trx_id != (unsigned long)-1);
if (!error)
{
IO_CACHE* cache= get_trans_log(thd);
uchar* buf= NULL;
uint buf_len= 0;
if (wsrep_emulate_bin_log)
thd->binlog_flush_pending_rows_event(false);
error= wsrep_write_cache(cache, &buf, &buf_len);
if (!error && buf_len > 0)
{
wsrep_status_t rc= wsrep->append_data(wsrep,
&thd->wsrep_trx_handle,
buf, buf_len);
if (rc != WSREP_OK)
{
sql_print_warning("WSREP: append_data() returned %d", rc);
error= 1;
}
}
if (buf_len) my_free(buf);
}
}
#endif /* WITH_WSREP */
DBUG_RETURN(error);
}

View File

@ -273,12 +273,6 @@ enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
(mmap+fsync is two times faster than write+fsync)
*/
#ifdef WITH_WSREP
extern my_bool wsrep_emulate_bin_log;
Log_event* wsrep_read_log_event(
char **arg_buf, size_t *arg_buf_len,
const Format_description_log_event *description_event);
#endif
class MYSQL_LOG
{
public:
@ -870,18 +864,17 @@ enum enum_binlog_format {
};
#ifdef WITH_WSREP
IO_CACHE * get_trans_log(THD * thd);
IO_CACHE* get_trans_log(THD * thd);
bool wsrep_trans_cache_is_empty(THD *thd);
void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end);
void thd_binlog_trx_reset(THD * thd);
void thd_binlog_rollback_stmt(THD * thd);
int wsrep_write_cache(IO_CACHE *cache, uchar **buf, uint *buf_len);
#define WSREP_FORMAT(my_format) \
((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
#define WSREP_BINLOG_FORMAT(my_format) \
((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
wsrep_forced_binlog_format : my_format)
#else
#define WSREP_FORMAT(my_format) my_format
#define WSREP_BINLOG_FORMAT(my_format) my_format
#endif
int query_error_code(THD *thd, bool not_killed);
uint purge_log_get_error_code(int res);

View File

@ -8406,7 +8406,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
thd->is_fatal_error,
thd->wsrep_exec_mode,
thd->wsrep_conflict_state,
(long long)thd->wsrep_trx_seqno);
(long long)wsrep_thd_trx_seqno(thd));
}
#endif
if (thd->is_slave_error || thd->is_fatal_error)
@ -10187,7 +10187,7 @@ Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
char info[64];
info[sizeof(info) - 1] = '\0';
snprintf(info, sizeof(info) - 1, "Write_rows_log_event::write_row(%lld)",
(long long) thd->wsrep_trx_seqno);
(long long) wsrep_thd_trx_seqno(thd));
const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL;
#else
const char* tmp = (WSREP(thd)) ?
@ -10864,7 +10864,7 @@ int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli)
char info[64];
info[sizeof(info) - 1] = '\0';
snprintf(info, sizeof(info) - 1, "Delete_rows_log_event::find_row(%lld)",
(long long) thd->wsrep_trx_seqno);
(long long) wsrep_thd_trx_seqno(thd));
const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL;
#else
const char* tmp = (WSREP(thd)) ?
@ -10880,7 +10880,7 @@ int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli)
#ifdef WSREP_PROC_INFO
snprintf(info, sizeof(info) - 1,
"Delete_rows_log_event::ha_delete_row(%lld)",
(long long) thd->wsrep_trx_seqno);
(long long) wsrep_thd_trx_seqno(thd));
if (WSREP(thd)) thd_proc_info(thd, info);
#else
if (WSREP(thd)) thd_proc_info(thd,"Delete_rows_log_event::ha_delete_row()");
@ -11016,7 +11016,7 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
char info[64];
info[sizeof(info) - 1] = '\0';
snprintf(info, sizeof(info) - 1, "Update_rows_log_event::find_row(%lld)",
(long long) thd->wsrep_trx_seqno);
(long long) wsrep_thd_trx_seqno(thd));
const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL;
#else
const char* tmp = (WSREP(thd)) ?
@ -11053,7 +11053,7 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
#ifdef WSREP_PROC_INFO
snprintf(info, sizeof(info) - 1,
"Update_rows_log_event::unpack_current_row(%lld)",
(long long) thd->wsrep_trx_seqno);
(long long) wsrep_thd_trx_seqno(thd));
if (WSREP(thd)) thd_proc_info(thd, info);
#else
if (WSREP(thd))
@ -11082,7 +11082,7 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
#ifdef WSREP_PROC_INFO
snprintf(info, sizeof(info) - 1,
"Update_rows_log_event::ha_update_row(%lld)",
(long long) thd->wsrep_trx_seqno);
(long long) wsrep_thd_trx_seqno(thd));
if (WSREP(thd)) thd_proc_info(thd, info);
#else
if (WSREP(thd)) thd_proc_info(thd,"Update_rows_log_event::ha_update_row()");
@ -11179,48 +11179,6 @@ void Incident_log_event::pack_info(THD *thd, Protocol *protocol)
protocol->store(buf, bytes, &my_charset_bin);
}
#endif
#if WITH_WSREP && !defined(MYSQL_CLIENT)
Format_description_log_event *wsrep_format_desc; // TODO: free them at the end
/*
read the first event from (*buf). The size of the (*buf) is (*buf_len).
At the end (*buf) is shitfed to point to the following event or NULL and
(*buf_len) will be changed to account just being read bytes of the 1st event.
*/
#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max
Log_event* wsrep_read_log_event(
char **arg_buf, size_t *arg_buf_len,
const Format_description_log_event *description_event)
{
DBUG_ENTER("wsrep_read_log_event");
char *head= (*arg_buf);
uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= (*arg_buf);
const char *error= 0;
Log_event *res= 0;
if (data_len > WSREP_MAX_ALLOWED_PACKET)
{
error = "Event too big";
goto err;
}
res= Log_event::read_log_event(buf, data_len, &error, description_event, FALSE);
err:
if (!res)
{
DBUG_ASSERT(error != 0);
sql_print_error("Error in Log_event::read_log_event(): "
"'%s', data_len: %d, event_type: %d",
error,data_len,head[EVENT_TYPE_OFFSET]);
}
(*arg_buf)+= data_len;
(*arg_buf_len)-= data_len;
DBUG_RETURN(res);
}
#endif
#ifdef MYSQL_CLIENT
@ -11310,6 +11268,7 @@ st_print_event_info::st_print_event_info()
}
#endif
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)

View File

@ -22,6 +22,7 @@
#include <mysql/service_thd_wait.h>
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
#include "wsrep_thd.h"
extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
extern "C" char *wsrep_thd_query(THD *thd);
void sql_print_information(const char *format, ...)
@ -3029,7 +3030,7 @@ void MDL_ticket::wsrep_report(bool debug)
{
if (debug)
{
WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s (%s)",
WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s",
(get_type() == MDL_INTENTION_EXCLUSIVE) ? "intention exclusive" :
((get_type() == MDL_SHARED) ? "shared" :
((get_type() == MDL_SHARED_HIGH_PRIO ? "shared high prio" :
@ -3049,7 +3050,7 @@ void MDL_ticket::wsrep_report(bool debug)
((m_lock->key.mdl_namespace() == MDL_key::COMMIT) ? "COMMIT" :
(char *)"UNKNOWN"))))))),
m_lock->key.db_name(),
m_lock->key.name(),
m_lock->key.name(),
m_lock->key.get_wait_state_name());
}
}

View File

@ -74,6 +74,9 @@
#include "debug_sync.h"
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
#include "wsrep_var.h"
#include "wsrep_thd.h"
#include "wsrep_sst.h"
ulong wsrep_running_threads = 0; // # of currently running wsrep threads
#endif
#include "sql_callback.h"
@ -354,7 +357,11 @@ static char *default_character_set_name;
static char *character_set_filesystem_name;
static char *lc_messages;
static char *lc_time_names_name;
#ifndef WITH_WSREP
static char *my_bind_addr_str;
#else
char *my_bind_addr_str;
#endif /* WITH_WSREP */
static char *default_collation_name;
char *default_storage_engine;
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
@ -716,7 +723,7 @@ mysql_mutex_t LOCK_wsrep_slave_threads;
mysql_mutex_t LOCK_wsrep_desync;
int wsrep_replaying= 0;
static void wsrep_close_threads(THD* thd);
#endif
#endif /* WITH_WSREP */
int mysqld_server_started= 0;
File_parser_dummy_hook file_parser_dummy_hook;
@ -1863,6 +1870,7 @@ extern "C" void unireg_abort(int exit_code)
WSREP_INFO("Some threads may fail to exit.");
}
#endif // WITH_WSREP
clean_up(!opt_abort && (exit_code || !opt_bootstrap)); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
mysqld_exit(exit_code);
@ -2389,7 +2397,7 @@ static my_socket activate_tcp_port(uint port)
socket_errno);
unireg_abort(1);
}
#if defined(WITH_WSREP) && defined(HAVE_FCNTL)
#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
(void) fcntl(ip_sock, F_SETFD, FD_CLOEXEC);
#endif /* WITH_WSREP */
DBUG_RETURN(ip_sock);
@ -2513,7 +2521,7 @@ static void network_init(void)
if (listen(unix_sock,(int) back_log) < 0)
sql_print_warning("listen() on Unix socket failed with error %d",
socket_errno);
#if defined(WITH_WSREP) && defined(HAVE_FCNTL)
#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
(void) fcntl(unix_sock, F_SETFD, FD_CLOEXEC);
#endif /* WITH_WSREP */
}
@ -4141,25 +4149,25 @@ static int init_thread_environment()
return 1;
}
#ifdef WITH_WSREP
mysql_mutex_init(key_LOCK_wsrep_ready,
&LOCK_wsrep_ready, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_ready,
&LOCK_wsrep_ready, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL);
mysql_mutex_init(key_LOCK_wsrep_sst,
&LOCK_wsrep_sst, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_sst,
&LOCK_wsrep_sst, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL);
mysql_mutex_init(key_LOCK_wsrep_sst_init,
&LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_sst_init,
&LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL);
mysql_mutex_init(key_LOCK_wsrep_rollback,
&LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_rollback,
&LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL);
mysql_mutex_init(key_LOCK_wsrep_replaying,
&LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_replaying,
&LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL);
mysql_mutex_init(key_LOCK_wsrep_slave_threads,
&LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_desync,
&LOCK_wsrep_desync, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_slave_threads,
&LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wsrep_desync,
&LOCK_wsrep_desync, MY_MUTEX_INIT_FAST);
#endif
return 0;
}
@ -4789,7 +4797,7 @@ pthread_handler_t start_wsrep_THD(void *arg)
THD *thd;
wsrep_thd_processor_fun processor= (wsrep_thd_processor_fun)arg;
if (my_thread_init())
if (my_thread_init())
{
WSREP_ERROR("Could not initialize thread");
return(NULL);
@ -4852,7 +4860,7 @@ pthread_handler_t start_wsrep_THD(void *arg)
statistic_increment(aborted_connects,&LOCK_status);
MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
delete thd;
return(NULL);
}
@ -4910,42 +4918,6 @@ pthread_handler_t start_wsrep_THD(void *arg)
return(NULL);
}
void wsrep_create_rollbacker()
{
if (WSREP_PROVIDER_EXISTS)
{
pthread_t hThread;
/* create rollbacker */
if (pthread_create( &hThread, &connection_attrib,
start_wsrep_THD, (void*)wsrep_rollback_process))
WSREP_WARN("Can't create thread to manage wsrep rollback");
}
}
void wsrep_create_appliers(long threads)
{
if (!wsrep_connected)
{
/* see wsrep_replication_start() for the logic */
if (wsrep_cluster_address && strlen(wsrep_cluster_address) &&
WSREP_PROVIDER_EXISTS)
{
WSREP_ERROR("Trying to launch slave threads before creating "
"connection at '%s'", wsrep_cluster_address);
assert(0);
}
return;
}
long wsrep_threads=0;
pthread_t hThread;
while (wsrep_threads++ < threads) {
if (pthread_create(
&hThread, &connection_attrib,
start_wsrep_THD, (void*)wsrep_replication_process))
WSREP_WARN("Can't create thread to manage wsrep replication");
}
}
/**/
static bool abort_replicated(THD *thd)
{
@ -4970,7 +4942,7 @@ WSREP_WARN("applier has wsrep_exec_mode = %d", thd->wsrep_exec_mode);
if ( thd->slave_thread || /* declared as mysql slave */
thd->system_thread || /* declared as system thread */
!thd->vio_ok() || /* server internal thread */
!thd->vio_ok() || /* server internal thread */
thd->wsrep_exec_mode==REPL_RECV || /* applier or replaying thread */
thd->wsrep_applier || /* wsrep slave applier */
!thd->variables.wsrep_on) /* client, but fenced outside wsrep */
@ -5452,6 +5424,9 @@ int mysqld_main(int argc, char **argv)
return 1;
}
#endif
#ifdef WITH_WSREP
wsrep_filter_new_cluster (&argc, argv);
#endif /* WITH_WSREP */
orig_argc= argc;
orig_argv= argv;
@ -5755,6 +5730,13 @@ int mysqld_main(int argc, char **argv)
unireg_abort(1);
#ifdef WITH_WSREP /* WSREP AFTER SE */
if (wsrep_recovery)
{
select_thread_in_use= 0;
wsrep_recover();
unireg_abort(0);
}
if (opt_bootstrap)
{
/*! bootstrap wsrep init was taken care of above */
@ -6484,7 +6466,7 @@ void handle_connections_sockets()
sleep(1); // Give other threads some time
continue;
}
#if defined(WITH_WSREP) && defined(HAVE_FCNTL)
#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
(void) fcntl(new_sock, F_SETFD, FD_CLOEXEC);
#endif /* WITH_WSREP */
@ -7984,6 +7966,7 @@ SHOW_VAR status_vars[]= {
{"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR},
{"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH},
{"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH},
{"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_FUNC},
{"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR},
{"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR},
{"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR},
@ -9220,6 +9203,9 @@ void refresh_status(THD *thd)
/* Reset some global variables */
reset_status_vars();
#ifdef WITH_WSREP
wsrep->stats_reset(wsrep);
#endif /* WITH_WSREP */
/* Reset the counters of all key caches (default and named). */
process_key_caches(reset_key_cache_counters, 0);
@ -9256,3 +9242,4 @@ template class I_List<i_string_pair>;
template class I_List<Statement>;
template class I_List_iterator<Statement>;
#endif

View File

@ -227,7 +227,7 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
#ifdef WITH_WSREP
extern PSI_mutex_key key_LOCK_wsrep_thd;
extern PSI_cond_key key_COND_wsrep_thd;
#endif /* HAVE_MMAP */
#endif /* HAVE_WSREP */
#ifdef HAVE_OPENSSL
extern PSI_mutex_key key_LOCK_des_key_file;
@ -423,7 +423,7 @@ enum options_mysqld
OPT_WSREP_START_POSITION,
OPT_WSREP_SST_AUTH,
OPT_WSREP_RECOVER,
#endif
#endif /* WITH_WSREP */
OPT_which_is_always_the_last
};
#endif
@ -572,5 +572,9 @@ extern uint internal_tmp_table_max_key_segments;
extern uint volatile global_disable_checkpoint;
extern my_bool opt_help;
#ifdef WITH_WSREP
#include "my_pthread.h"
pthread_handler_t start_wsrep_THD(void*);
#endif /* WITH_WSREP */
#endif /* MYSQLD_INCLUDED */

View File

@ -2289,7 +2289,7 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
return sp;
}
#ifdef WITH_WSREP
int wsrep_create_sp(THD *thd, uchar** buf, uint* buf_len)
int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
{
String log_query;
sp_head *sp = thd->lex->sphead;
@ -2315,10 +2315,10 @@ int wsrep_create_sp(THD *thd, uchar** buf, uint* buf_len)
sp->m_chistics, &(thd->lex->definer->user),
&(thd->lex->definer->host),
saved_mode))
{
WSREP_WARN("SP create string failed: %s", thd->query());
return 1;
}
{
WSREP_WARN("SP create string failed: %s", thd->query());
return 1;
}
return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
}
#endif /* WITH_WSREP */

View File

@ -59,9 +59,9 @@
#ifdef __WIN__
#include <io.h>
#endif
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
#include "wsrep_thd.h"
#endif // WITH_WSREP
bool
@ -4227,7 +4227,7 @@ thr_lock_type read_lock_type_for_table(THD *thd,
*/
bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
ulong binlog_format= thd->variables.binlog_format;
if ((log_on == FALSE) || (WSREP_FORMAT(binlog_format) == BINLOG_FORMAT_ROW) ||
if ((log_on == FALSE) || (WSREP_BINLOG_FORMAT(binlog_format) == BINLOG_FORMAT_ROW) ||
(table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
(table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
!(is_update_query(prelocking_ctx->sql_command) ||
@ -5894,7 +5894,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
We can solve these problems in mixed mode by switching to binlogging
if at least one updated table is used by sub-statement
*/
if (WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_ROW && tables &&
if (WSREP_BINLOG_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_ROW && tables &&
has_write_table_with_auto_increment(thd->lex->first_not_own_table()))
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
}
@ -9431,6 +9431,7 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
{
mysql_mutex_assert_owner(&LOCK_open);
}
#ifdef WITH_WSREP
/* if thd was BF aborted, exclusive locks were canceled */
#else
@ -9438,6 +9439,7 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
MDL_EXCLUSIVE));
#endif /* WITH_WSREP */
key_length= create_table_def_key(key, db, table_name);
if ((share= (TABLE_SHARE*) my_hash_search(&table_def_cache,(uchar*) key,
@ -9461,7 +9463,6 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
thus others can use table */
if (table->in_use != thd &&
table->in_use->wsrep_bf_thd != thd &&
table->in_use->wsrep_conflict_state != MUST_ABORT)
{
#endif

View File

@ -848,9 +848,9 @@ extern "C" const char *wsrep_thd_conflict_state_str(THD *thd)
(thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void";
}
extern "C" wsrep_trx_handle_t* wsrep_thd_trx_handle(THD *thd)
extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd)
{
return &thd->wsrep_trx_handle;
return &thd->wsrep_ws_handle;
}
extern "C"void wsrep_thd_LOCK(THD *thd)
@ -875,7 +875,7 @@ extern "C" my_thread_id wsrep_thd_thread_id(THD *thd)
}
extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd)
{
return (thd) ? thd->wsrep_trx_seqno : WSREP_SEQNO_UNDEFINED;
return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED;
}
extern "C" query_id_t wsrep_thd_query_id(THD *thd)
{
@ -913,16 +913,16 @@ extern "C" void wsrep_thd_awake(THD* bf_thd, THD *thd, my_bool signal)
extern "C" int
wsrep_trx_order_before(void *thd1, void *thd2)
{
if (((THD*)thd1)->wsrep_trx_seqno < ((THD*)thd2)->wsrep_trx_seqno) {
WSREP_DEBUG("BF conflict, order: %lld %lld\n",
(long long)((THD*)thd1)->wsrep_trx_seqno,
(long long)((THD*)thd2)->wsrep_trx_seqno);
return 1;
}
WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
(long long)((THD*)thd1)->wsrep_trx_seqno,
(long long)((THD*)thd2)->wsrep_trx_seqno);
return 0;
if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) {
WSREP_DEBUG("BF conflict, order: %lld %lld\n",
(long long)wsrep_thd_trx_seqno((THD*)thd1),
(long long)wsrep_thd_trx_seqno((THD*)thd2));
return 1;
}
WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
(long long)wsrep_thd_trx_seqno((THD*)thd1),
(long long)wsrep_thd_trx_seqno((THD*)thd2));
return 0;
}
extern "C" int
wsrep_trx_is_aborting(void *thd_ptr)
@ -1000,7 +1000,7 @@ THD::THD()
wsrep_applier(is_applier),
wsrep_applier_closing(FALSE),
wsrep_client_thread(0),
wsrep_trx_seqno(WSREP_SEQNO_UNDEFINED),
wsrep_apply_toi(false),
#endif
m_parser_state(NULL),
#if defined(ENABLED_DEBUG_SYNC)
@ -1104,9 +1104,8 @@ THD::THD()
#ifdef WITH_WSREP
mysql_mutex_init(key_LOCK_wsrep_thd, &LOCK_wsrep_thd, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL);
wsrep_trx_handle.trx_id = WSREP_UNDEFINED_TRX_ID;
wsrep_trx_handle.opaque = NULL;
//wsrep_retry_autocommit= ::wsrep_retry_autocommit;
wsrep_ws_handle.trx_id = WSREP_UNDEFINED_TRX_ID;
wsrep_ws_handle.opaque = NULL;
wsrep_retry_counter = 0;
wsrep_PA_safe = true;
wsrep_retry_query = NULL;
@ -1471,7 +1470,10 @@ void THD::init(void)
wsrep_conflict_state= NO_CONFLICT;
wsrep_query_state= QUERY_IDLE;
wsrep_last_query_id= 0;
wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
wsrep_converted_lock_session= false;
//wsrep_retry_autocommit= ::wsrep_retry_autocommit;
wsrep_retry_counter= 0;
wsrep_rli= NULL;
wsrep_PA_safe= true;
@ -2116,6 +2118,7 @@ void THD::cleanup_after_query()
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= FALSE;
/* reset replication info structure */
#ifndef EMBEDDED_LIBRARY
if (rli_slave)
@ -4279,7 +4282,7 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd)
#else
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
#endif
return (int) WSREP_FORMAT(thd->variables.binlog_format);
return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
else
return BINLOG_FORMAT_UNSPEC;
}
@ -4839,7 +4842,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
binlog by filtering rules.
*/
if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
!(WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT &&
!(WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT &&
!binlog_filter->db_ok(db)))
{
/*
@ -5003,7 +5006,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
}
else if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW &&
else if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW &&
sqlcom_can_generate_row_events(this))
{
/*
@ -5032,7 +5035,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
else
{
/* binlog_format = STATEMENT */
if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT)
if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT)
{
if (lex->is_stmt_row_injection())
{
@ -5144,7 +5147,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
"and binlog_filter->db_ok(db) = %d",
mysql_bin_log.is_open(),
(variables.option_bits & OPTION_BIN_LOG),
WSREP_FORMAT(variables.binlog_format),
WSREP_BINLOG_FORMAT(variables.binlog_format),
binlog_filter->db_ok(db)));
#endif

View File

@ -49,6 +49,7 @@
#include "wsrep_mysqld.h"
struct wsrep_thd_shadow {
ulonglong options;
uint server_status;
enum wsrep_exec_mode wsrep_exec_mode;
Vio *vio;
ulong tx_isolation;
@ -1807,7 +1808,8 @@ public:
int is_current_stmt_binlog_format_row() const {
DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT ||
current_stmt_binlog_format == BINLOG_FORMAT_ROW);
return (WSREP_FORMAT((ulong)current_stmt_binlog_format) == BINLOG_FORMAT_ROW);
return (WSREP_BINLOG_FORMAT((ulong)current_stmt_binlog_format) ==
BINLOG_FORMAT_ROW);
}
private:
@ -2353,11 +2355,13 @@ public:
enum wsrep_conflict_state wsrep_conflict_state;
mysql_mutex_t LOCK_wsrep_thd;
mysql_cond_t COND_wsrep_thd;
wsrep_seqno_t wsrep_trx_seqno;
// changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75
// wsrep_seqno_t wsrep_trx_seqno;
wsrep_trx_meta_t wsrep_trx_meta;
uint32 wsrep_rand;
Relay_log_info* wsrep_rli;
bool wsrep_converted_lock_session;
wsrep_trx_handle_t wsrep_trx_handle;
wsrep_ws_handle_t wsrep_ws_handle;
#ifdef WSREP_PROC_INFO
char wsrep_info[128]; /* string for dynamic proc info */
#endif /* WSREP_PROC_INFO */
@ -2374,6 +2378,7 @@ public:
const char* wsrep_TOI_pre_query; /* a query to apply before
the actual TOI query */
size_t wsrep_TOI_pre_query_len;
bool wsrep_apply_toi; /* applier processing in TOI */
#endif /* WITH_WSREP */
/**
Internal parser state.
@ -2819,7 +2824,7 @@ public:
tests fail and so force them to propagate the
lex->binlog_row_based_if_mixed upwards to the caller.
*/
if ((WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED) &&
if ((WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED)&&
(in_sub_stmt == 0))
set_current_stmt_binlog_format_row();
@ -2861,7 +2866,7 @@ public:
show_system_thread(system_thread)));
if (in_sub_stmt == 0)
{
if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW)
if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
else if (temporary_tables == NULL)
clear_current_stmt_binlog_format_row();

File diff suppressed because it is too large Load Diff

View File

@ -2453,7 +2453,7 @@ bool load_table_name_for_trigger(THD *thd,
DBUG_RETURN(FALSE);
}
#ifdef WITH_WSREP
int wsrep_create_trigger_query(THD *thd, uchar** buf, uint* buf_len)
int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len)
{
LEX *lex= thd->lex;
String stmt_query;
@ -2501,6 +2501,6 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, uint* buf_len)
stmt_query.append(stmt_definition.str, stmt_definition.length);
return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(),
buf, buf_len);
buf, buf_len);
}
#endif /* WITH_WSREP */

View File

@ -2571,7 +2571,9 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type)
{
thd->variables.option_bits&= ~OPTION_AUTOCOMMIT;
thd->mdl_context.release_transactional_locks();
#ifdef WITH_WSREP
WSREP_DEBUG("autocommit, MDL TRX lock released: %lu", thd->thread_id);
#endif /* WITH_WSREP */
return true;
}
/*
@ -3654,7 +3656,9 @@ static Sys_var_tz Sys_time_zone(
SESSION_VAR(time_zone), NO_CMD_LINE,
DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
#include "wsrep_var.h"
#include "wsrep_sst.h"
#include "wsrep_binlog.h"
static Sys_var_charptr Sys_wsrep_provider(
"wsrep_provider", "Path to replication provider library",
@ -3812,10 +3816,11 @@ static Sys_var_charptr Sys_wsrep_start_position (
ON_CHECK(wsrep_start_position_check),
ON_UPDATE(wsrep_start_position_update));
static Sys_var_ulonglong Sys_wsrep_max_ws_size (
static Sys_var_ulong Sys_wsrep_max_ws_size (
"wsrep_max_ws_size", "Max write set size (bytes)",
GLOBAL_VAR(wsrep_max_ws_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(1024, 4294967296ULL), DEFAULT(1073741824ULL), BLOCK_SIZE(1));
/* Upper limit is 65K short of 4G to avoid overlows on 32-bit systems */
VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(1073741824UL), BLOCK_SIZE(1));
static Sys_var_ulong Sys_wsrep_max_ws_rows (
"wsrep_max_ws_rows", "Max number of rows in write set",
@ -3835,8 +3840,7 @@ static Sys_var_mybool Sys_wsrep_certify_nonPK(
static Sys_var_mybool Sys_wsrep_causal_reads(
"wsrep_causal_reads", "Enable \"strictly synchronous\" semantics for read operations",
SESSION_VAR(wsrep_causal_reads),
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
// ON_UPDATE(wsrep_causal_reads_update));
CMD_LINE(OPT_ARG), DEFAULT(FALSE));
static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS };
static Sys_var_enum Sys_wsrep_OSU_method(

View File

@ -298,6 +298,7 @@ bool trans_rollback(THD *thd)
DBUG_RETURN(test(res));
}
/**
Implicitly rollback the current transaction, typically
after deadlock was discovered.
@ -329,7 +330,6 @@ bool trans_rollback_implicit(THD *thd)
#ifdef WITH_WSREP
wsrep_register_hton(thd, true);
#endif /* WITH_WSREP */
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= ha_rollback_trans(thd, true);
@ -433,7 +433,6 @@ bool trans_rollback_stmt(THD *thd)
wsrep_register_hton(thd, FALSE);
#endif /* WITH_WSREP */
ha_rollback_trans(thd, FALSE);
if (! thd->in_active_multi_stmt_transaction())
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
}

351
sql/wsrep_applier.cc Normal file
View File

@ -0,0 +1,351 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "wsrep_priv.h"
#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
#include "log_event.h" // EVENT_LEN_OFFSET, etc.
#include "wsrep_applier.h"
/*
read the first event from (*buf). The size of the (*buf) is (*buf_len).
At the end (*buf) is shitfed to point to the following event or NULL and
(*buf_len) will be changed to account just being read bytes of the 1st event.
*/
static Log_event* wsrep_read_log_event(
char **arg_buf, size_t *arg_buf_len,
const Format_description_log_event *description_event)
{
DBUG_ENTER("wsrep_read_log_event");
char *head= (*arg_buf);
uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= (*arg_buf);
const char *error= 0;
Log_event *res= 0;
if (data_len > wsrep_max_ws_size)
{
error = "Event too big";
goto err;
}
res= Log_event::read_log_event(buf, data_len, &error, description_event,
FALSE);
err:
if (!res)
{
DBUG_ASSERT(error != 0);
sql_print_error("Error in Log_event::read_log_event(): "
"'%s', data_len: %d, event_type: %d",
error,data_len,head[EVENT_TYPE_OFFSET]);
}
(*arg_buf)+= data_len;
(*arg_buf_len)-= data_len;
DBUG_RETURN(res);
}
#include "transaction.h" // trans_commit(), trans_rollback()
#include "rpl_rli.h" // class Relay_log_info;
#include "sql_base.h" // close_temporary_table()
extern const Format_description_log_event *wsrep_format_desc;
static wsrep_cb_status_t wsrep_apply_events(THD* thd,
const void* events_buf,
size_t buf_len)
{
char *buf= (char *)events_buf;
int rcode= 0;
int event= 1;
DBUG_ENTER("wsrep_apply_rbr");
if (thd->killed == KILL_CONNECTION)
{
WSREP_INFO("applier has been aborted, skipping apply_rbr: %lld",
(long long) wsrep_thd_trx_seqno(thd));
DBUG_RETURN(WSREP_CB_FAILURE);
}
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
thd->wsrep_query_state= QUERY_EXEC;
if (thd->wsrep_conflict_state!= REPLAYING)
thd->wsrep_conflict_state= NO_CONFLICT;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld",
(long long) wsrep_thd_trx_seqno(thd));
while(buf_len)
{
int exec_res;
int error = 0;
Log_event* ev= wsrep_read_log_event(&buf, &buf_len, wsrep_format_desc);
if (!ev)
{
WSREP_ERROR("applier could not read binlog event, seqno: %lld, len: %ld",
(long long)wsrep_thd_trx_seqno(thd), buf_len);
rcode= 1;
goto error;
}
switch (ev->get_type_code()) {
case WRITE_ROWS_EVENT:
case UPDATE_ROWS_EVENT:
case DELETE_ROWS_EVENT:
DBUG_ASSERT(buf_len != 0 ||
((Rows_log_event*)ev)->get_flags(Rows_log_event::STMT_END_F));
break;
default:
break;
}
thd->server_id = ev->server_id; // use the original server id for logging
thd->set_time(); // time the query
wsrep_xid_init(&thd->transaction.xid_state.xid,
&thd->wsrep_trx_meta.gtid.uuid,
thd->wsrep_trx_meta.gtid.seqno);
thd->lex->current_select= 0;
if (!ev->when)
ev->when = time(NULL);
ev->thd = thd;
exec_res = ev->apply_event(thd->wsrep_rli);
DBUG_PRINT("info", ("exec_event result: %d", exec_res));
if (exec_res)
{
WSREP_WARN("RBR event %d %s apply warning: %d, %lld",
event, ev->get_type_str(), exec_res,
(long long) wsrep_thd_trx_seqno(thd));
rcode= exec_res;
/* stop processing for the first error */
delete ev;
goto error;
}
event++;
if (thd->wsrep_conflict_state!= NO_CONFLICT &&
thd->wsrep_conflict_state!= REPLAYING)
WSREP_WARN("conflict state after RBR event applying: %d, %lld",
thd->wsrep_query_state, (long long)wsrep_thd_trx_seqno(thd));
if (thd->wsrep_conflict_state == MUST_ABORT) {
WSREP_WARN("RBR event apply failed, rolling back: %lld",
(long long) wsrep_thd_trx_seqno(thd));
trans_rollback(thd);
thd->locked_tables_list.unlock_locked_tables(thd);
/* Release transactional metadata locks. */
thd->mdl_context.release_transactional_locks();
thd->wsrep_conflict_state= NO_CONFLICT;
DBUG_RETURN(WSREP_CB_FAILURE);
}
if ((ev->get_type_code() == WRITE_ROWS_EVENT ||
ev->get_type_code() == UPDATE_ROWS_EVENT ||
ev->get_type_code() == DELETE_ROWS_EVENT) &&
((Rows_log_event *) ev)->get_flags(Rows_log_event::STMT_END_F))
{
thd->wsrep_rli->cleanup_context(thd, 0);
if (error == 0)
{
thd->clear_error();
}
else
WSREP_ERROR("Error in %s event: commit of row events failed: %lld",
ev->get_type_str(), (long long)wsrep_thd_trx_seqno(thd));
}
delete ev;
}
error:
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
thd->wsrep_query_state= QUERY_IDLE;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
assert(thd->wsrep_exec_mode== REPL_RECV);
if (thd->killed == KILL_CONNECTION)
WSREP_INFO("applier aborted: %lld", (long long)wsrep_thd_trx_seqno(thd));
if (rcode) DBUG_RETURN(WSREP_CB_FAILURE);
DBUG_RETURN(WSREP_CB_SUCCESS);
}
wsrep_cb_status_t wsrep_apply_cb(void* const ctx,
const void* const buf,
size_t const buf_len,
uint32_t const flags,
const wsrep_trx_meta_t* meta)
{
THD* const thd((THD*)ctx);
thd->wsrep_trx_meta = *meta;
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
"applying write set %lld: %p, %zu",
(long long)wsrep_thd_trx_seqno(thd), buf, buf_len);
thd_proc_info(thd, thd->wsrep_info);
#else
thd_proc_info(thd, "applying write set");
#endif /* WSREP_PROC_INFO */
if (flags & WSREP_FLAG_ISOLATION)
{
thd->wsrep_apply_toi= true;
/*
Don't run in transaction mode with TOI actions.
*/
thd->variables.option_bits&= ~OPTION_BEGIN;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
}
wsrep_cb_status_t rcode(wsrep_apply_events(thd, buf, buf_len));
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
"applied write set %lld", (long long)wsrep_thd_trx_seqno(thd));
thd_proc_info(thd, thd->wsrep_info);
#else
thd_proc_info(thd, "applied write set");
#endif /* WSREP_PROC_INFO */
if (WSREP_CB_SUCCESS != rcode)
{
wsrep_dump_rbr_buf(thd, buf, buf_len);
}
TABLE *tmp;
while ((tmp = thd->temporary_tables))
{
WSREP_DEBUG("Applier %lu, has temporary tables: %s.%s",
thd->thread_id,
(tmp->s) ? tmp->s->db.str : "void",
(tmp->s) ? tmp->s->table_name.str : "void");
close_temporary_table(thd, tmp, 1, 1);
}
return rcode;
}
static wsrep_cb_status_t wsrep_commit(THD* const thd,
wsrep_seqno_t const global_seqno)
{
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
"committing %lld", (long long)wsrep_thd_trx_seqno(thd));
thd_proc_info(thd, thd->wsrep_info);
#else
thd_proc_info(thd, "committing");
#endif /* WSREP_PROC_INFO */
wsrep_cb_status_t const rcode(trans_commit(thd) ?
WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
"committed %lld", (long long)wsrep_thd_trx_seqno(thd));
thd_proc_info(thd, thd->wsrep_info);
#else
thd_proc_info(thd, "committed");
#endif /* WSREP_PROC_INFO */
if (WSREP_CB_SUCCESS == rcode)
{
// TODO: mark snapshot with global_seqno.
}
return rcode;
}
static wsrep_cb_status_t wsrep_rollback(THD* const thd,
wsrep_seqno_t const global_seqno)
{
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
"rolling back %lld", (long long)wsrep_thd_trx_seqno(thd));
thd_proc_info(thd, thd->wsrep_info);
#else
thd_proc_info(thd, "rolling back");
#endif /* WSREP_PROC_INFO */
wsrep_cb_status_t const rcode(trans_rollback(thd) ?
WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
#ifdef WSREP_PROC_INFO
snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
"rolled back %lld", (long long)wsrep_thd_trx_seqno(thd));
thd_proc_info(thd, thd->wsrep_info);
#else
thd_proc_info(thd, "rolled back");
#endif /* WSREP_PROC_INFO */
return rcode;
}
wsrep_cb_status_t wsrep_commit_cb(void* const ctx,
uint32_t const flags,
const wsrep_trx_meta_t* meta,
wsrep_bool_t* const exit,
bool const commit)
{
THD* const thd((THD*)ctx);
assert(meta->gtid.seqno == wsrep_thd_trx_seqno(thd));
wsrep_cb_status_t rcode;
if (commit)
rcode = wsrep_commit(thd, meta->gtid.seqno);
else
rcode = wsrep_rollback(thd, meta->gtid.seqno);
thd->mdl_context.release_transactional_locks();
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
if (wsrep_slave_count_change < 0 && commit && WSREP_CB_SUCCESS == rcode)
{
mysql_mutex_lock(&LOCK_wsrep_slave_threads);
if (wsrep_slave_count_change < 0)
{
wsrep_slave_count_change++;
*exit = true;
}
mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
}
if (*exit == false && thd->wsrep_applier)
{
/* From trans_begin() */
thd->variables.option_bits|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
thd->wsrep_apply_toi= false;
}
return rcode;
}
wsrep_cb_status_t wsrep_unordered_cb(void* const ctx,
const void* const data,
size_t const size)
{
return WSREP_CB_SUCCESS;
}

38
sql/wsrep_applier.h Normal file
View File

@ -0,0 +1,38 @@
/* Copyright 2013 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 */
#ifndef WSREP_APPLIER_H
#define WSREP_APPLIER_H
#include <sys/types.h>
/* wsrep callback prototypes */
wsrep_cb_status_t wsrep_apply_cb(void *ctx,
const void* buf, size_t buf_len,
uint32_t flags,
const wsrep_trx_meta_t* meta);
wsrep_cb_status_t wsrep_commit_cb(void *ctx,
uint32_t flags,
const wsrep_trx_meta_t* meta,
wsrep_bool_t* exit,
bool commit);
wsrep_cb_status_t wsrep_unordered_cb(void* ctx,
const void* data,
size_t size);
#endif /* WSREP_APPLIER_H */

321
sql/wsrep_binlog.cc Normal file
View File

@ -0,0 +1,321 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "wsrep_binlog.h"
#include "wsrep_priv.h"
/*
Write the contents of a cache to a memory buffer.
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
*/
int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
{
*buf= NULL;
*buf_len= 0;
my_off_t const saved_pos(my_b_tell(cache));
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
{
WSREP_ERROR("failed to initialize io-cache");
return ER_ERROR_ON_WRITE;
}
uint length = my_b_bytes_in_cache(cache);
if (unlikely(0 == length)) length = my_b_fill(cache);
size_t total_length = 0;
if (likely(length > 0)) do
{
total_length += length;
/*
Bail out if buffer grows too large.
A temporary fix to avoid allocating indefinitely large buffer,
not a real limit on a writeset size which includes other things
like header and keys.
*/
if (total_length > wsrep_max_ws_size)
{
WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
wsrep_max_ws_size, total_length);
goto error;
}
uchar* tmp = (uchar *)my_realloc(*buf, total_length, MYF(0));
if (!tmp)
{
WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
*buf_len, length);
goto error;
}
*buf = tmp;
memcpy(*buf + *buf_len, cache->read_pos, length);
*buf_len = total_length;
cache->read_pos = cache->read_end;
} while ((cache->file >= 0) && (length = my_b_fill(cache)));
if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
{
WSREP_WARN("failed to initialize io-cache");
goto cleanup;
}
return 0;
error:
if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
{
WSREP_ERROR("failed to initialize io-cache");
}
cleanup:
my_free(*buf);
*buf= NULL;
*buf_len= 0;
return ER_ERROR_ON_WRITE;
}
#define STACK_SIZE 4096 /* 4K - for buffer preallocated on the stack:
* many transactions would fit in there
* so there is no need to reach for the heap */
/* Returns minimum multiple of HEAP_PAGE_SIZE that is >= length */
static inline size_t
heap_size(size_t length)
{
return (length + HEAP_PAGE_SIZE - 1)/HEAP_PAGE_SIZE*HEAP_PAGE_SIZE;
}
/* append data to writeset */
static inline wsrep_status_t
wsrep_append_data(wsrep_t* const wsrep,
wsrep_ws_handle_t* const ws,
const void* const data,
size_t const len)
{
struct wsrep_buf const buff = { data, len };
wsrep_status_t const rc(wsrep->append_data(wsrep, ws, &buff, 1,
WSREP_DATA_ORDERED, true));
if (rc != WSREP_OK)
{
WSREP_WARN("append_data() returned %d", rc);
}
return rc;
}
/*
Write the contents of a cache to wsrep provider.
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
This version reads all of cache into single buffer and then appends to a
writeset at once.
*/
static int wsrep_write_cache_once(wsrep_t* const wsrep,
THD* const thd,
IO_CACHE* const cache,
size_t* const len)
{
my_off_t const saved_pos(my_b_tell(cache));
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
{
WSREP_ERROR("failed to initialize io-cache");
return ER_ERROR_ON_WRITE;
}
int err(WSREP_OK);
size_t total_length(0);
uchar stack_buf[STACK_SIZE]; /* to avoid dynamic allocations for few data*/
uchar* heap_buf(NULL);
uchar* buf(stack_buf);
size_t allocated(sizeof(stack_buf));
size_t used(0);
uint length(my_b_bytes_in_cache(cache));
if (unlikely(0 == length)) length = my_b_fill(cache);
if (likely(length > 0)) do
{
total_length += length;
/*
Bail out if buffer grows too large.
A temporary fix to avoid allocating indefinitely large buffer,
not a real limit on a writeset size which includes other things
like header and keys.
*/
if (unlikely(total_length > wsrep_max_ws_size))
{
WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
wsrep_max_ws_size, total_length);
goto cleanup;
}
if (total_length > allocated)
{
size_t const new_size(heap_size(total_length));
uchar* tmp = (uchar *)my_realloc(heap_buf, new_size, MYF(0));
if (!tmp)
{
WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
allocated, length);
err = WSREP_SIZE_EXCEEDED;
goto cleanup;
}
heap_buf = tmp;
buf = heap_buf;
allocated = new_size;
if (used <= STACK_SIZE && used > 0) // there's data in stack_buf
{
DBUG_ASSERT(buf == stack_buf);
memcpy(heap_buf, stack_buf, used);
}
}
memcpy(buf + used, cache->read_pos, length);
used = total_length;
cache->read_pos = cache->read_end;
} while ((cache->file >= 0) && (length = my_b_fill(cache)));
if (used > 0)
err = wsrep_append_data(wsrep, &thd->wsrep_ws_handle, buf, used);
if (WSREP_OK == err) *len = total_length;
cleanup:
if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
{
WSREP_ERROR("failed to reinitialize io-cache");
}
if (unlikely(WSREP_OK != err)) wsrep_dump_rbr_buf(thd, buf, used);
my_free(heap_buf);
return err;
}
/*
Write the contents of a cache to wsrep provider.
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
This version uses incremental data appending as it reads it from cache.
*/
static int wsrep_write_cache_inc(wsrep_t* const wsrep,
THD* const thd,
IO_CACHE* const cache,
size_t* const len)
{
my_off_t const saved_pos(my_b_tell(cache));
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
{
WSREP_ERROR("failed to initialize io-cache");
return WSREP_TRX_ROLLBACK;
}
int err(WSREP_OK);
size_t total_length(0);
uint length(my_b_bytes_in_cache(cache));
if (unlikely(0 == length)) length = my_b_fill(cache);
if (likely(length > 0)) do
{
total_length += length;
/* bail out if buffer grows too large
not a real limit on a writeset size which includes other things
like header and keys.
*/
if (unlikely(total_length > wsrep_max_ws_size))
{
WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
wsrep_max_ws_size, total_length);
err = WSREP_SIZE_EXCEEDED;
goto cleanup;
}
if(WSREP_OK != (err=wsrep_append_data(wsrep, &thd->wsrep_ws_handle,
cache->read_pos, length)))
goto cleanup;
cache->read_pos = cache->read_end;
} while ((cache->file >= 0) && (length = my_b_fill(cache)));
if (WSREP_OK == err) *len = total_length;
cleanup:
if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
{
WSREP_ERROR("failed to reinitialize io-cache");
}
return err;
}
/*
Write the contents of a cache to wsrep provider.
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
*/
int wsrep_write_cache(wsrep_t* const wsrep,
THD* const thd,
IO_CACHE* const cache,
size_t* const len)
{
if (wsrep_incremental_data_collection) {
return wsrep_write_cache_inc(wsrep, thd, cache, len);
}
else {
return wsrep_write_cache_once(wsrep, thd, cache, len);
}
}
void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len)
{
char filename[PATH_MAX]= {0};
int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log",
wsrep_data_home_dir, thd->thread_id,
(long long)wsrep_thd_trx_seqno(thd));
if (len >= PATH_MAX)
{
WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
return;
}
FILE *of= fopen(filename, "wb");
if (of)
{
fwrite (rbr_buf, buf_len, 1, of);
fclose(of);
}
else
{
WSREP_ERROR("Failed to open file '%s': %d (%s)",
filename, errno, strerror(errno));
}
}

49
sql/wsrep_binlog.h Normal file
View File

@ -0,0 +1,49 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef WSREP_BINLOG_H
#define WSREP_BINLOG_H
#include "sql_class.h" // THD, IO_CACHE
#define HEAP_PAGE_SIZE 65536 /* 64K */
#define WSREP_MAX_WS_SIZE (0xFFFFFFFFUL - HEAP_PAGE_SIZE)
/*
Write the contents of a cache to a memory buffer.
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
*/
int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len);
/*
Write the contents of a cache to wsrep provider.
This function quite the same as MYSQL_BIN_LOG::write_cache(),
with the exception that here we write in buffer instead of log file.
@param len total amount of data written
@return wsrep error status
*/
int wsrep_write_cache (wsrep_t* wsrep,
THD* thd,
IO_CACHE* cache,
size_t* len);
/* Dump replication buffer to disk */
void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len);
#endif /* WSREP_BINLOG_H */

View File

@ -18,7 +18,7 @@
#include "rpl_filter.h"
#include <sql_class.h>
#include "wsrep_mysqld.h"
#include "wsrep_priv.h"
#include "wsrep_binlog.h"
#include <cstdio>
#include <cstdlib>
@ -26,10 +26,11 @@ extern handlerton *binlog_hton;
extern int binlog_close_connection(handlerton *hton, THD *thd);
extern ulonglong thd_to_trx_id(THD *thd);
extern "C" int thd_binlog_format(const MYSQL_THD thd);
// todo: share interface with ha_innodb.c
extern "C" int thd_binlog_format(const MYSQL_THD thd);
// todo: share interface with ha_innodb.c
enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all);
enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton,
bool all);
/*
Cleanup after local transaction commit/rollback, replay or TOI.
@ -37,8 +38,9 @@ enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool al
void wsrep_cleanup_transaction(THD *thd)
{
if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd);
thd->wsrep_trx_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
thd->wsrep_trx_seqno= WSREP_SEQNO_UNDEFINED;
thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
thd->wsrep_exec_mode= LOCAL_STATE;
return;
}
@ -66,7 +68,7 @@ handlerton *wsrep_hton;
*/
void wsrep_register_hton(THD* thd, bool all)
{
if (thd->wsrep_exec_mode != TOTAL_ORDER)
if (thd->wsrep_exec_mode != TOTAL_ORDER && !thd->wsrep_apply_toi)
{
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
for (Ha_trx_info *i= trans->ha_list; WSREP(thd) && i; i = i->next())
@ -94,8 +96,8 @@ void wsrep_post_commit(THD* thd, bool all)
{
if (thd->wsrep_exec_mode == LOCAL_COMMIT)
{
DBUG_ASSERT(thd->wsrep_trx_seqno != WSREP_SEQNO_UNDEFINED);
if (wsrep->post_commit(wsrep, &thd->wsrep_trx_handle))
DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
if (wsrep->post_commit(wsrep, &thd->wsrep_ws_handle))
{
DBUG_PRINT("wsrep", ("set committed fail"));
WSREP_WARN("set committed fail: %llu %d",
@ -106,7 +108,7 @@ void wsrep_post_commit(THD* thd, bool all)
}
/*
wsrep exploits binlog's caches even if binlogging itself is not
wsrep exploits binlog's caches even if binlogging itself is not
activated. In such case connection close needs calling
actual binlog's method.
Todo: split binlog hton from its caches to use ones by wsrep
@ -125,7 +127,7 @@ wsrep_close_connection(handlerton* hton, THD* thd)
if (wsrep_emulate_bin_log && thd_get_ha_data(thd, binlog_hton) != NULL)
binlog_hton->close_connection (binlog_hton, thd);
DBUG_RETURN(0);
}
}
/*
prepare/wsrep_run_wsrep_commit can fail in two ways
@ -147,18 +149,15 @@ static int wsrep_prepare(handlerton *hton, THD *thd, bool all)
DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
DBUG_ASSERT(thd->wsrep_trx_seqno == WSREP_SEQNO_UNDEFINED);
DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
if ((all ||
if ((all ||
!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
(thd->variables.wsrep_on && !wsrep_trans_cache_is_empty(thd)))
{
switch (wsrep_run_wsrep_commit(thd, hton, all))
{
case WSREP_TRX_OK:
// DBUG_ASSERT(thd->wsrep_trx_seqno > old ||
// thd->wsrep_exec_mode == REPL_RECV ||
// thd->wsrep_exec_mode == TOTAL_ORDER);
break;
case WSREP_TRX_ROLLBACK:
case WSREP_TRX_ERROR:
@ -208,10 +207,10 @@ static int wsrep_rollback(handlerton *hton, THD *thd, bool all)
if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
(thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
{
if (wsrep->post_rollback(wsrep, &thd->wsrep_trx_handle))
if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
{
DBUG_PRINT("wsrep", ("setting rollback fail"));
WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
(long long)thd->real_id, thd->query());
}
wsrep_cleanup_transaction(thd);
@ -249,12 +248,12 @@ int wsrep_commit(handlerton *hton, THD *thd, bool all)
possible changes to clean state.
*/
if (WSREP_PROVIDER_EXISTS) {
if (wsrep->post_rollback(wsrep, &thd->wsrep_trx_handle))
{
DBUG_PRINT("wsrep", ("setting rollback fail"));
WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
(long long)thd->real_id, thd->query());
}
if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
{
DBUG_PRINT("wsrep", ("setting rollback fail"));
WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
(long long)thd->real_id, thd->query());
}
}
wsrep_cleanup_transaction(thd);
}
@ -266,26 +265,24 @@ int wsrep_commit(handlerton *hton, THD *thd, bool all)
extern Rpl_filter* binlog_filter;
extern my_bool opt_log_slave_updates;
extern void wsrep_write_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len);
enum wsrep_trx_status
wsrep_run_wsrep_commit(
THD *thd, handlerton *hton, bool all)
wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all)
{
int rcode = -1;
uint data_len = 0;
uchar *rbr_data = NULL;
int rcode= -1;
size_t data_len= 0;
IO_CACHE *cache;
int replay_round= 0;
if (thd->stmt_da->is_error()) {
WSREP_ERROR("commit issue, error: %d %s",
WSREP_ERROR("commit issue, error: %d %s",
thd->stmt_da->sql_errno(), thd->stmt_da->message());
}
DBUG_ENTER("wsrep_run_wsrep_commit");
if (thd->slave_thread && !opt_log_slave_updates) {
DBUG_RETURN(WSREP_TRX_OK);
}
if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK);
if (thd->wsrep_exec_mode == REPL_RECV) {
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
@ -303,9 +300,9 @@ wsrep_run_wsrep_commit(
}
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
}
if (thd->wsrep_exec_mode != LOCAL_STATE) {
DBUG_RETURN(WSREP_TRX_OK);
}
if (thd->wsrep_exec_mode != LOCAL_STATE) DBUG_RETURN(WSREP_TRX_OK);
if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) {
WSREP_DEBUG("commit for consistency check: %s", thd->query());
DBUG_RETURN(WSREP_TRX_OK);
@ -327,10 +324,10 @@ wsrep_run_wsrep_commit(
mysql_mutex_lock(&LOCK_wsrep_replaying);
while (wsrep_replaying > 0 &&
while (wsrep_replaying > 0 &&
thd->wsrep_conflict_state == NO_CONFLICT &&
thd->killed == NOT_KILLED &&
!shutdown_in_progress)
!shutdown_in_progress)
{
mysql_mutex_unlock(&LOCK_wsrep_replaying);
@ -348,9 +345,12 @@ wsrep_run_wsrep_commit(
struct timespec wtime = {0, 1000000};
mysql_cond_timedwait(&COND_wsrep_replaying, &LOCK_wsrep_replaying,
&wtime);
if (replay_round++ % 100000 == 0)
WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: (%lu) conflict: %d (round: %d)",
wsrep_replaying, thd->thread_id, thd->wsrep_conflict_state, replay_round);
WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: (%lu) "
"conflict: %d (round: %d)",
wsrep_replaying, thd->thread_id,
thd->wsrep_conflict_state, replay_round);
mysql_mutex_unlock(&LOCK_wsrep_replaying);
@ -371,7 +371,8 @@ wsrep_run_wsrep_commit(
WSREP_DEBUG("innobase_commit abort after replaying wait %s",
(thd->query()) ? thd->query() : "void");
DBUG_RETURN(WSREP_TRX_ROLLBACK);
}
}
thd->wsrep_query_state = QUERY_COMMITTING;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
@ -379,28 +380,28 @@ wsrep_run_wsrep_commit(
rcode = 0;
if (cache) {
thd->binlog_flush_pending_rows_event(true);
rcode = wsrep_write_cache(cache, &rbr_data, &data_len);
if (rcode) {
WSREP_ERROR("rbr write fail, data_len: %d, %d", data_len, rcode);
if (data_len) my_free(rbr_data);
rcode = wsrep_write_cache(wsrep, thd, cache, &data_len);
if (WSREP_OK != rcode) {
WSREP_ERROR("rbr write fail, data_len: %zu, %d", data_len, rcode);
DBUG_RETURN(WSREP_TRX_ROLLBACK);
}
}
if (data_len == 0)
if (data_len == 0)
{
if (thd->stmt_da->is_ok() &&
if (thd->stmt_da->is_ok() &&
thd->stmt_da->affected_rows() > 0 &&
!binlog_filter->is_on())
{
WSREP_DEBUG("empty rbr buffer, query: %s, "
"affected rows: %llu, "
"changed tables: %d, "
"affected rows: %llu, "
"changed tables: %d, "
"sql_log_bin: %d, "
"wsrep status (%d %d %d)",
"wsrep status (%d %d %d)",
thd->query(), thd->stmt_da->affected_rows(),
stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin,
thd->wsrep_exec_mode, thd->wsrep_query_state,
thd->wsrep_conflict_state);
thd->wsrep_exec_mode, thd->wsrep_query_state,
thd->wsrep_conflict_state);
}
else
{
@ -409,38 +410,33 @@ wsrep_run_wsrep_commit(
thd->wsrep_query_state= QUERY_EXEC;
DBUG_RETURN(WSREP_TRX_OK);
}
if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_trx_handle.trx_id)
if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id)
{
WSREP_WARN("SQL statement was ineffective, THD: %lu, buf: %d\n"
"QUERY: %s\n"
" => Skipping replication",
thd->thread_id, data_len, thd->query());
if (wsrep_debug)
{
wsrep_write_rbr_buf(thd, rbr_data, data_len);
}
WSREP_WARN("SQL statement was ineffective, THD: %lu, buf: %zu\n"
"QUERY: %s\n"
" => Skipping replication",
thd->thread_id, data_len, thd->query());
rcode = WSREP_TRX_FAIL;
}
else if (!rcode)
{
rcode = wsrep->pre_commit(
wsrep,
(wsrep_conn_id_t)thd->thread_id,
&thd->wsrep_trx_handle,
rbr_data,
data_len,
(thd->wsrep_PA_safe) ? WSREP_FLAG_PA_SAFE : 0ULL,
&thd->wsrep_trx_seqno);
switch (rcode) {
case WSREP_TRX_MISSING:
if (WSREP_OK == rcode)
rcode = wsrep->pre_commit(wsrep,
(wsrep_conn_id_t)thd->thread_id,
&thd->wsrep_ws_handle,
WSREP_FLAG_COMMIT |
((thd->wsrep_PA_safe) ?
0ULL : WSREP_FLAG_PA_UNSAFE),
&thd->wsrep_trx_meta);
if (rcode == WSREP_TRX_MISSING) {
WSREP_WARN("Transaction missing in provider, thd: %ld, SQL: %s",
thd->thread_id, thd->query());
wsrep_write_rbr_buf(thd, rbr_data, data_len);
rcode = WSREP_TRX_FAIL;
break;
case WSREP_BF_ABORT:
} else if (rcode == WSREP_BF_ABORT) {
WSREP_DEBUG("thd %lu seqno %lld BF aborted by provider, will replay",
thd->thread_id, (long long)thd->wsrep_trx_seqno);
thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno);
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
thd->wsrep_conflict_state = MUST_REPLAY;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
@ -449,22 +445,14 @@ wsrep_run_wsrep_commit(
WSREP_DEBUG("replaying increased: %d, thd: %lu",
wsrep_replaying, thd->thread_id);
mysql_mutex_unlock(&LOCK_wsrep_replaying);
break;
default:
break;
}
} else {
WSREP_ERROR("I/O error reading from thd's binlog iocache: "
"errno=%d, io cache code=%d", my_errno, cache->error);
if (data_len) my_free(rbr_data);
DBUG_ASSERT(0); // failure like this can not normally happen
DBUG_RETURN(WSREP_TRX_ERROR);
}
if (data_len) {
my_free(rbr_data);
}
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
switch(rcode) {
case 0:
@ -481,22 +469,22 @@ wsrep_run_wsrep_commit(
{
WSREP_WARN("thd %lu seqno %lld: conflict state %d after post commit",
thd->thread_id,
(long long)thd->wsrep_trx_seqno,
(long long)thd->wsrep_trx_meta.gtid.seqno,
thd->wsrep_conflict_state);
}
thd->wsrep_exec_mode= LOCAL_COMMIT;
DBUG_ASSERT(thd->wsrep_trx_seqno != WSREP_SEQNO_UNDEFINED);
DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
/* Override XID iff it was generated by mysql */
if (thd->transaction.xid_state.xid.get_my_xid())
{
wsrep_xid_init(&thd->transaction.xid_state.xid,
wsrep_cluster_uuid(),
thd->wsrep_trx_seqno);
&thd->wsrep_trx_meta.gtid.uuid,
thd->wsrep_trx_meta.gtid.seqno);
}
DBUG_PRINT("wsrep", ("replicating commit success"));
break;
case WSREP_BF_ABORT:
DBUG_ASSERT(thd->wsrep_trx_seqno != WSREP_SEQNO_UNDEFINED);
DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
case WSREP_TRX_FAIL:
WSREP_DEBUG("commit failed for reason: %d", rcode);
DBUG_PRINT("wsrep", ("replicating commit fail"));
@ -505,7 +493,7 @@ wsrep_run_wsrep_commit(
if (thd->wsrep_conflict_state == MUST_ABORT) {
thd->wsrep_conflict_state= ABORTED;
}
}
else
{
WSREP_DEBUG("conflict state: %d", thd->wsrep_conflict_state);
@ -563,14 +551,15 @@ mysql_declare_plugin(wsrep)
&wsrep_storage_engine,
"wsrep",
"Codership Oy",
"A pseudo storage engine to represent transactions in multi-master synchornous replication",
"A pseudo storage engine to represent transactions in multi-master "
"synchornous replication",
PLUGIN_LICENSE_GPL,
wsrep_hton_init, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100 /* 1.0 */,
NULL, /* status variables */
NULL, /* system variables */
NULL, /* config options */
NULL, /* config options */
0, /* flags */
}
mysql_declare_plugin_end;

View File

@ -1,4 +1,4 @@
/* Copyright 2008 Codership Oy <http://www.codership.com>
/* Copyright 2008-2013 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
@ -17,11 +17,17 @@
#include <sql_class.h>
#include <sql_parse.h>
#include "wsrep_priv.h"
#include "wsrep_thd.h"
#include "wsrep_sst.h"
#include "wsrep_utils.h"
#include "wsrep_var.h"
#include "wsrep_binlog.h"
#include "wsrep_applier.h"
#include <cstdio>
#include <cstdlib>
#include "log_event.h"
extern Format_description_log_event *wsrep_format_desc;
Format_description_log_event *wsrep_format_desc = NULL;
wsrep_t *wsrep = NULL;
my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
@ -33,24 +39,26 @@ const char* wsrep_data_home_dir = NULL;
const char* wsrep_dbug_option = "";
long wsrep_slave_threads = 1; // # of slave action appliers wanted
int wsrep_slave_count_change = 0; // # of appliers to stop or start
my_bool wsrep_debug = 0; // enable debug level logging
my_bool wsrep_convert_LOCK_to_trx = 1; // convert locking sessions to trx
ulong wsrep_retry_autocommit = 5; // retry aborted autocommit trx
my_bool wsrep_auto_increment_control = 1; // control auto increment variables
my_bool wsrep_drupal_282555_workaround = 1; // retry autoinc insert after dupkey
my_bool wsrep_incremental_data_collection = 0; // incremental data collection
long long wsrep_max_ws_size = 1073741824LL; //max ws (RBR buffer) size
long wsrep_max_ws_rows = 65536; // max number of rows in ws
ulong wsrep_max_ws_size = 1073741824UL;//max ws (RBR buffer) size
ulong wsrep_max_ws_rows = 65536; // max number of rows in ws
int wsrep_to_isolation = 0; // # of active TO isolation threads
my_bool wsrep_certify_nonPK = 1; // certify, even when no primary key
long wsrep_max_protocol_version = 2; // maximum protocol version to use
ulong wsrep_forced_binlog_format = BINLOG_FORMAT_UNSPEC;
my_bool wsrep_recovery = 0; // recovery
my_bool wsrep_replicate_myisam = 0; // enable myisam replication
my_bool wsrep_log_conflicts = 0; //
my_bool wsrep_log_conflicts = 0;
ulong wsrep_mysql_replication_bundle = 0;
my_bool wsrep_desync = 0; // desynchronize the node from the
// cluster
my_bool wsrep_load_data_splitting = 1; // commit load data every 10K intervals
my_bool wsrep_desync = 0; // desynchronize the node from the cluster
/*
* End configuration options
@ -88,12 +96,12 @@ long long wsrep_cluster_conf_id = WSREP_SEQNO_UNDEFINED;
const char* wsrep_cluster_status = cluster_status_str[WSREP_VIEW_DISCONNECTED];
long wsrep_cluster_size = 0;
long wsrep_local_index = -1;
long long wsrep_local_bf_aborts = 0;
const char* wsrep_provider_name = provider_name;
const char* wsrep_provider_version = provider_version;
const char* wsrep_provider_vendor = provider_vendor;
/* End wsrep status variables */
wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED;
wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED;
wsp::node_status local_status;
@ -104,14 +112,6 @@ long wsrep_protocol_version = 2;
// if there was no state gap on receiving first view event.
static my_bool wsrep_startup = TRUE;
// action execute callback
extern wsrep_status_t wsrep_apply_cb(void *ctx,
const void* buf, size_t buf_len,
wsrep_seqno_t global_seqno);
extern wsrep_status_t wsrep_commit_cb (void *ctx,
wsrep_seqno_t global_seqno,
bool commit);
static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) {
switch (level) {
@ -195,19 +195,25 @@ void wsrep_get_SE_checkpoint(XID* xid)
plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid);
}
static void wsrep_view_handler_cb (void* app_ctx,
void* recv_ctx,
const wsrep_view_info_t* view,
const char* state,
size_t state_len,
void** sst_req,
ssize_t* sst_req_len)
static wsrep_cb_status_t
wsrep_view_handler_cb (void* app_ctx,
void* recv_ctx,
const wsrep_view_info_t* view,
const char* state,
size_t state_len,
void** sst_req,
size_t* sst_req_len)
{
*sst_req = NULL;
*sst_req_len = 0;
wsrep_member_status_t new_status= local_status.get();
if (memcmp(&cluster_uuid, &view->uuid, sizeof(wsrep_uuid_t)))
if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t)))
{
memcpy((wsrep_uuid_t*)&cluster_uuid, &view->uuid, sizeof(cluster_uuid));
memcpy((wsrep_uuid_t*)&cluster_uuid, &view->state_id.uuid,
sizeof(cluster_uuid));
wsrep_uuid_print (&cluster_uuid, cluster_uuid_str,
sizeof(cluster_uuid_str));
}
@ -219,7 +225,7 @@ static void wsrep_view_handler_cb (void* app_ctx,
WSREP_INFO("New cluster view: global state: %s:%lld, view# %lld: %s, "
"number of nodes: %ld, my index: %ld, protocol version %d",
wsrep_cluster_state_uuid, (long long)view->seqno,
wsrep_cluster_state_uuid, (long long)view->state_id.seqno,
(long long)wsrep_cluster_conf_id, wsrep_cluster_status,
wsrep_cluster_size, wsrep_local_index, view->proto_ver);
@ -274,16 +280,18 @@ static void wsrep_view_handler_cb (void* app_ctx,
WSREP_DEBUG("[debug]: closing client connections for PRIM");
wsrep_close_client_connections(TRUE);
*sst_req_len= wsrep_sst_prepare (sst_req);
ssize_t const req_len= wsrep_sst_prepare (sst_req);
if (*sst_req_len < 0)
if (req_len < 0)
{
int err = *sst_req_len;
WSREP_ERROR("SST preparation failed: %d (%s)", -err, strerror(-err));
WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len,
strerror(-req_len));
new_status= WSREP_MEMBER_UNDEFINED;
}
else
{
assert(sst_req != NULL);
*sst_req_len= req_len;
new_status= WSREP_MEMBER_JOINER;
}
}
@ -299,14 +307,14 @@ static void wsrep_view_handler_cb (void* app_ctx,
{
wsrep_SE_init_grab();
// Signal mysqld init thread to continue
wsrep_sst_complete (&cluster_uuid, view->seqno, false);
wsrep_sst_complete (&cluster_uuid, view->state_id.seqno, false);
// and wait for SE initialization
wsrep_SE_init_wait();
}
else
{
local_uuid= cluster_uuid;
local_seqno= view->seqno;
local_seqno= view->state_id.seqno;
}
/* Init storage engine XIDs from first view */
XID xid;
@ -319,7 +327,7 @@ static void wsrep_view_handler_cb (void* app_ctx,
if (memcmp (&local_uuid, &cluster_uuid, sizeof (wsrep_uuid_t)))
{
WSREP_ERROR("Undetected state gap. Can't continue.");
wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->seqno,
wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->state_id.seqno,
&local_uuid, -1);
unireg_abort(1);
}
@ -331,9 +339,23 @@ static void wsrep_view_handler_cb (void* app_ctx,
global_system_variables.auto_increment_increment= view->memb_num;
}
{ /* capabilities may be updated on new configuration */
uint64_t const caps(wsrep->capabilities (wsrep));
my_bool const idc((caps & WSREP_CAP_INCREMENTAL_WRITESET) != 0);
if (TRUE == wsrep_incremental_data_collection && FALSE == idc)
{
WSREP_WARN("Unsupported protocol downgrade: "
"incremental data collection disabled. Expect abort.");
}
wsrep_incremental_data_collection = idc;
}
out:
wsrep_startup= FALSE;
local_status.set(new_status, view);
return WSREP_CB_SUCCESS;
}
void wsrep_ready_set (my_bool x)
@ -364,14 +386,26 @@ void wsrep_ready_wait ()
static void wsrep_synced_cb(void* app_ctx)
{
WSREP_INFO("Synchronized with group, ready for connections");
bool signal_main= false;
if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
if (!wsrep_ready)
{
wsrep_ready= TRUE;
mysql_cond_signal (&COND_wsrep_ready);
signal_main= true;
}
local_status.set(WSREP_MEMBER_SYNCED);
mysql_mutex_unlock (&LOCK_wsrep_ready);
if (signal_main)
{
wsrep_SE_init_grab();
// Signal mysqld init thread to continue
wsrep_sst_complete (&local_uuid, local_seqno, false);
// and wait for SE initialization
wsrep_SE_init_wait();
}
}
static void wsrep_init_position()
@ -416,6 +450,8 @@ static void wsrep_init_position()
}
}
extern const char* my_bind_addr_str;
int wsrep_init()
{
int rcode= -1;
@ -470,7 +506,7 @@ int wsrep_init()
size_t const node_addr_max= sizeof(node_addr) - 1;
if (!wsrep_node_address || !strcmp(wsrep_node_address, ""))
{
size_t const ret= guess_ip(node_addr, node_addr_max);
size_t const ret= wsrep_guess_ip(node_addr, node_addr_max);
if (!(ret > 0 && ret < node_addr_max))
{
WSREP_WARN("Failed to guess base node address. Set it explicitly via "
@ -488,37 +524,56 @@ int wsrep_init()
if ((!wsrep_node_incoming_address ||
!strcmp (wsrep_node_incoming_address, WSREP_NODE_INCOMING_AUTO)))
{
size_t const node_addr_len= strlen(node_addr);
if (node_addr_len > 0)
unsigned int my_bind_ip= INADDR_ANY; // default if not set
if (my_bind_addr_str && strlen(my_bind_addr_str))
{
const char* const colon= strrchr(node_addr, ':');
if (strchr(node_addr, ':') == colon) // 1 or 0 ':'
my_bind_ip= wsrep_check_ip(my_bind_addr_str);
}
if (INADDR_ANY != my_bind_ip)
{
if (INADDR_NONE != my_bind_ip && INADDR_LOOPBACK != my_bind_ip)
{
size_t const ip_len= colon ? colon - node_addr : node_addr_len;
if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
snprintf(inc_addr, inc_addr_max, "%s:%u",
my_bind_addr_str, (int)mysqld_port);
} // else leave inc_addr an empty string - mysqld is not listening for
// client connections on network interfaces.
}
else // mysqld binds to 0.0.0.0, take IP from wsrep_node_address if possible
{
size_t const node_addr_len= strlen(node_addr);
if (node_addr_len > 0)
{
const char* const colon= strrchr(node_addr, ':');
if (strchr(node_addr, ':') == colon) // 1 or 0 ':'
{
memcpy (inc_addr, node_addr, ip_len);
snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",mysqld_port);
size_t const ip_len= colon ? colon - node_addr : node_addr_len;
if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
{
memcpy (inc_addr, node_addr, ip_len);
snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
(int)mysqld_port);
}
else
{
WSREP_WARN("Guessing address for incoming client connections: "
"address too long.");
inc_addr[0]= '\0';
}
}
else
{
WSREP_WARN("Guessing address for incoming client connections: "
"address too long.");
"too many colons :) .");
inc_addr[0]= '\0';
}
}
else
{
WSREP_WARN("Guessing address for incoming client connections: "
"too many colons :) .");
inc_addr[0]= '\0';
}
}
if (!strlen(inc_addr))
{
WSREP_WARN("Guessing address for incoming client connections failed. "
"Try setting wsrep_node_incoming_address explicitly.");
if (!strlen(inc_addr))
{
WSREP_WARN("Guessing address for incoming client connections failed. "
"Try setting wsrep_node_incoming_address explicitly.");
}
}
}
else if (!strchr(wsrep_node_incoming_address, ':')) // no port included
@ -546,6 +601,8 @@ int wsrep_init()
struct wsrep_init_args wsrep_args;
struct wsrep_gtid const state_id = { local_uuid, local_seqno };
wsrep_args.data_dir = wsrep_data_home_dir;
wsrep_args.node_name = (wsrep_node_name) ? wsrep_node_name : "";
wsrep_args.node_address = node_addr;
@ -554,13 +611,13 @@ int wsrep_init()
wsrep_provider_options : "";
wsrep_args.proto_ver = wsrep_max_protocol_version;
wsrep_args.state_uuid = &local_uuid;
wsrep_args.state_seqno = local_seqno;
wsrep_args.state_id = &state_id;
wsrep_args.logger_cb = wsrep_log_cb;
wsrep_args.view_handler_cb = wsrep_view_handler_cb;
wsrep_args.apply_cb = wsrep_apply_cb;
wsrep_args.commit_cb = wsrep_commit_cb;
wsrep_args.unordered_cb = wsrep_unordered_cb;
wsrep_args.sst_donate_cb = wsrep_sst_donate_cb;
wsrep_args.synced_cb = wsrep_synced_cb;
@ -661,8 +718,36 @@ void wsrep_stop_replication(THD *thd)
return;
}
/* This one is set to true when --wsrep-new-cluster is found in the command
* line arguments */
static my_bool wsrep_new_cluster= FALSE;
#define WSREP_NEW_CLUSTER "--wsrep-new-cluster"
/* Finds and hides --wsrep-new-cluster from the arguments list
* by moving it to the end of the list and decrementing argument count */
void wsrep_filter_new_cluster (int* argc, char* argv[])
{
int i;
for (i= *argc - 1; i > 0; i--)
{
/* make a copy of the argument to convert possible underscores to hyphens.
* the copy need not to be longer than WSREP_NEW_CLUSTER option */
char arg[sizeof(WSREP_NEW_CLUSTER) + 2]= { 0, };
strncpy(arg, argv[i], sizeof(arg) - 1);
char* underscore;
while (NULL != (underscore= strchr(arg, '_'))) *underscore= '-';
extern my_bool wsrep_new_cluster;
if (!strcmp(arg, WSREP_NEW_CLUSTER))
{
wsrep_new_cluster= TRUE;
*argc -= 1;
/* preserve the order of remaining arguments AND
* preserve the original argument pointers - just in case */
char* wnc= argv[i];
memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i]));
argv[*argc]= wnc; /* this will be invisible to the rest of the program */
}
}
}
bool wsrep_start_replication()
{
@ -686,20 +771,16 @@ bool wsrep_start_replication()
return true;
}
/* Note 'bootstrap' address is not officially supported in wsrep API #23
but it can be back ported from #24 provider to get sneak preview of
bootstrap command
*/
const char* cluster_address =
wsrep_new_cluster ? "bootstrap" : wsrep_cluster_address;
bool const bootstrap(TRUE == wsrep_new_cluster);
wsrep_new_cluster= FALSE;
WSREP_INFO("Start replication");
if ((rcode = wsrep->connect(wsrep,
wsrep_cluster_name,
cluster_address,
wsrep_sst_donor)))
wsrep_cluster_address,
wsrep_sst_donor,
bootstrap)))
{
if (-ESOCKTNOSUPPORT == rcode)
{
@ -720,11 +801,6 @@ bool wsrep_start_replication()
{
wsrep_connected= TRUE;
uint64_t caps = wsrep->capabilities (wsrep);
wsrep_incremental_data_collection =
!!(caps & WSREP_CAP_WRITE_SET_INCREMENTS);
char* opts= wsrep->options_get(wsrep);
if (opts)
{
@ -749,8 +825,8 @@ wsrep_causal_wait (THD* thd)
{
// This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0
// TODO: modify to check if thd has locked any rows.
wsrep_seqno_t seqno;
wsrep_status_t ret= wsrep->causal_read (wsrep, &seqno);
wsrep_gtid_t gtid;
wsrep_status_t ret= wsrep->causal_read (wsrep, &gtid);
if (unlikely(WSREP_OK != ret))
{
@ -798,7 +874,7 @@ static void wsrep_keys_free(wsrep_key_arr_t* key_arr)
{
for (size_t i= 0; i < key_arr->keys_len; ++i)
{
my_free((wsrep_key_part_t*)key_arr->keys[i].key_parts);
my_free((void*)key_arr->keys[i].key_parts);
}
my_free(key_arr->keys);
key_arr->keys= 0;
@ -818,7 +894,7 @@ static void wsrep_keys_free(wsrep_key_arr_t* key_arr)
static bool wsrep_prepare_key_for_isolation(const char* db,
const char* table,
wsrep_key_part_t* key,
wsrep_buf_t* key,
size_t* key_len)
{
if (*key_len < 2) return false;
@ -837,13 +913,13 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
// sql_print_information("%s.%s", db, table);
if (db)
{
key[*key_len].buf= db;
key[*key_len].buf_len= strlen(db);
key[*key_len].ptr= db;
key[*key_len].len= strlen(db);
++(*key_len);
if (table)
{
key[*key_len].buf= table;
key[*key_len].buf_len= strlen(table);
key[*key_len].ptr= table;
key[*key_len].len= strlen(table);
++(*key_len);
}
}
@ -879,23 +955,23 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
{
if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
{
sql_print_error("Can't allocate memory for key_array");
WSREP_ERROR("Can't allocate memory for key_array");
goto err;
}
ka->keys_len= 1;
if (!(ka->keys[0].key_parts= (wsrep_key_part_t*)
my_malloc(sizeof(wsrep_key_part_t)*2, MYF(0))))
if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
{
sql_print_error("Can't allocate memory for key_parts");
WSREP_ERROR("Can't allocate memory for key_parts");
goto err;
}
ka->keys[0].key_parts_len= 2;
ka->keys[0].key_parts_num= 2;
if (!wsrep_prepare_key_for_isolation(
db, table,
(wsrep_key_part_t*)ka->keys[0].key_parts,
&ka->keys[0].key_parts_len))
(wsrep_buf_t*)ka->keys[0].key_parts,
&ka->keys[0].key_parts_num))
{
sql_print_error("Preparing keys for isolation failed");
WSREP_ERROR("Preparing keys for isolation failed");
goto err;
}
}
@ -910,24 +986,24 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t), MYF(0));
if (!tmp)
{
sql_print_error("Can't allocate memory for key_array");
WSREP_ERROR("Can't allocate memory for key_array");
goto err;
}
ka->keys= tmp;
if (!(ka->keys[ka->keys_len].key_parts= (wsrep_key_part_t*)
my_malloc(sizeof(wsrep_key_part_t)*2, MYF(0))))
if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
{
sql_print_error("Can't allocate memory for key_parts");
WSREP_ERROR("Can't allocate memory for key_parts");
goto err;
}
ka->keys[ka->keys_len].key_parts_len= 2;
ka->keys[ka->keys_len].key_parts_num= 2;
++ka->keys_len;
if (!wsrep_prepare_key_for_isolation(
table->db, table->table_name,
(wsrep_key_part_t*)ka->keys[ka->keys_len - 1].key_parts,
&ka->keys[ka->keys_len - 1].key_parts_len))
(wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
&ka->keys[ka->keys_len - 1].key_parts_num))
{
sql_print_error("Preparing keys for isolation failed");
WSREP_ERROR("Preparing keys for isolation failed");
goto err;
}
}
@ -939,12 +1015,11 @@ err:
}
bool wsrep_prepare_key_for_innodb(const uchar* cache_key,
size_t cache_key_len,
size_t cache_key_len,
const uchar* row_id,
size_t row_id_len,
wsrep_key_part_t* key,
wsrep_buf_t* key,
size_t* key_len)
{
if (*key_len < 3) return false;
@ -954,33 +1029,36 @@ bool wsrep_prepare_key_for_innodb(const uchar* cache_key,
{
case 0:
{
key[*key_len].buf = cache_key;
key[*key_len].buf_len = cache_key_len;
++(*key_len);
key[0].ptr = cache_key;
key[0].len = cache_key_len;
*key_len = 1;
break;
}
case 1:
case 2:
{
key[*key_len].buf = cache_key;
key[*key_len].buf_len = strlen( (char*)cache_key );
++(*key_len);
key[*key_len].buf = cache_key + strlen( (char*)cache_key ) + 1;
key[*key_len].buf_len = strlen( (char*)(key[*key_len].buf) );
++(*key_len);
key[0].ptr = cache_key;
key[0].len = strlen( (char*)cache_key );
key[1].ptr = cache_key + strlen( (char*)cache_key ) + 1;
key[1].len = strlen( (char*)(key[1].ptr) );
*key_len = 2;
break;
}
default:
return false;
}
key[*key_len].buf = row_id;
key[*key_len].buf_len = row_id_len;
key[*key_len].ptr = row_id;
key[*key_len].len = row_id_len;
++(*key_len);
return true;
}
/*
* Construct Query_log_Event from thd query and serialize it
* into buffer.
@ -988,7 +1066,7 @@ bool wsrep_prepare_key_for_innodb(const uchar* cache_key,
* Return 0 in case of success, 1 in case of error.
*/
int wsrep_to_buf_helper(
THD* thd, const char *query, uint query_len, uchar** buf, uint* buf_len)
THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len)
{
IO_CACHE tmp_io_cache;
if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX,
@ -999,9 +1077,9 @@ int wsrep_to_buf_helper(
/* if there is prepare query, add event for it */
if (thd->wsrep_TOI_pre_query)
{
Query_log_event ev(thd, thd->wsrep_TOI_pre_query,
thd->wsrep_TOI_pre_query_len,
FALSE, FALSE, FALSE, 0);
Query_log_event ev(thd, thd->wsrep_TOI_pre_query,
thd->wsrep_TOI_pre_query_len,
FALSE, FALSE, FALSE, 0);
if (ev.write(&tmp_io_cache)) ret= 1;
}
@ -1009,7 +1087,7 @@ int wsrep_to_buf_helper(
Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0);
if (ev.write(&tmp_io_cache)) ret= 1;
if (!ret && wsrep_write_cache(&tmp_io_cache, buf, buf_len)) ret= 1;
if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1;
close_cached_file(&tmp_io_cache);
return ret;
@ -1017,7 +1095,7 @@ int wsrep_to_buf_helper(
#include "sql_show.h"
static int
create_view_query(THD *thd, uchar** buf, uint* buf_len)
create_view_query(THD *thd, uchar** buf, size_t* buf_len)
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= &lex->select_lex;
@ -1036,15 +1114,15 @@ create_view_query(THD *thd, uchar** buf, uint* buf_len)
if (!lex->definer)
{
/*
DEFINER-clause is missing; we have to create default definer in
persistent arena to be PS/SP friendly.
If this is an ALTER VIEW then the current user should be set as
the definer.
DEFINER-clause is missing; we have to create default definer in
persistent arena to be PS/SP friendly.
If this is an ALTER VIEW then the current user should be set as
the definer.
*/
if (!(lex->definer= create_default_definer(thd)))
{
WSREP_WARN("view default definer issue");
WSREP_WARN("view default definer issue");
}
}
@ -1071,7 +1149,7 @@ create_view_query(THD *thd, uchar** buf, uint* buf_len)
List_iterator_fast<LEX_STRING> names(lex->view_list);
LEX_STRING *name;
int i;
for (i= 0; (name= names++); i++)
{
buff.append(i ? ", " : "(");
@ -1082,7 +1160,7 @@ create_view_query(THD *thd, uchar** buf, uint* buf_len)
buff.append(STRING_WITH_LEN(" AS "));
//buff.append(views->source.str, views->source.length);
buff.append(thd->lex->create_view_select.str,
thd->lex->create_view_select.length);
thd->lex->create_view_select.length);
//int errcode= query_error_code(thd, TRUE);
//if (thd->binlog_query(THD::STMT_QUERY_TYPE,
// buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcod
@ -1094,11 +1172,11 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
{
wsrep_status_t ret(WSREP_WARNING);
uchar* buf(0);
uint buf_len(0);
size_t buf_len(0);
int buf_err;
WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)thd->wsrep_trx_seqno,
thd->wsrep_exec_mode, thd->query() );
WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
thd->wsrep_exec_mode, thd->query() );
switch (thd->lex->sql_command)
{
case SQLCOM_CREATE_VIEW:
@ -1121,19 +1199,20 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
}
wsrep_key_arr_t key_arr= {0, 0};
struct wsrep_buf buff = { buf, buf_len };
if (!buf_err &&
wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr)&&
WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
key_arr.keys, key_arr.keys_len,
buf, buf_len,
&thd->wsrep_trx_seqno)))
&buff, 1,
&thd->wsrep_trx_meta)))
{
thd->wsrep_exec_mode= TOTAL_ORDER;
wsrep_to_isolation++;
if (buf) my_free(buf);
wsrep_keys_free(&key_arr);
WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)thd->wsrep_trx_seqno,
thd->wsrep_exec_mode);
WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd),
thd->wsrep_exec_mode);
}
else {
/* jump to error handler in mysql_execute_command() */
@ -1152,10 +1231,11 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
static void wsrep_TOI_end(THD *thd) {
wsrep_status_t ret;
wsrep_to_isolation--;
WSREP_DEBUG("TO END: %lld, %d : %s", (long long)thd->wsrep_trx_seqno,
WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void");
if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) {
WSREP_DEBUG("TO END: %lld", (long long)thd->wsrep_trx_seqno);
WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd));
}
else {
WSREP_WARN("TO isolation end failed for: %d, sql: %s",
@ -1166,7 +1246,7 @@ static void wsrep_TOI_end(THD *thd) {
static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
{
wsrep_status_t ret(WSREP_WARNING);
WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)thd->wsrep_trx_seqno,
WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
thd->wsrep_exec_mode, thd->query() );
ret = wsrep->desync(wsrep);
@ -1211,7 +1291,7 @@ static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
static void wsrep_RSU_end(THD *thd)
{
wsrep_status_t ret(WSREP_WARNING);
WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)thd->wsrep_trx_seqno,
WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
thd->wsrep_exec_mode, thd->query() );
@ -1255,13 +1335,27 @@ int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
DBUG_ASSERT(thd->wsrep_trx_seqno == WSREP_SEQNO_UNDEFINED);
DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
if (wsrep_debug && thd->mdl_context.has_locks())
{
WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu",
thd->query(), thd->thread_id);
}
/*
It makes sense to set auto_increment_* to defaults in TOI operations.
Must be done before wsrep_TOI_begin() since Query_log_event encapsulating
TOI statement and auto inc variables for wsrep replication is constructed
there. Variables are reset back in THD::reset_for_next_command() before
processing of next command.
*/
if (wsrep_auto_increment_control)
{
thd->variables.auto_increment_offset = 1;
thd->variables.auto_increment_increment = 1;
}
if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE)
{
switch (wsrep_OSU_method_options) {
@ -1272,12 +1366,6 @@ int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
if (!ret)
{
thd->wsrep_exec_mode= TOTAL_ORDER;
/* It makes sense to set auto_increment_* to defaults in TOI operations */
if (wsrep_auto_increment_control)
{
thd->variables.auto_increment_offset = 1;
thd->variables.auto_increment_increment = 1;
}
}
}
return ret;
@ -1302,10 +1390,10 @@ void wsrep_to_isolation_end(THD *thd)
"request: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n" \
"granted: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)", \
msg, \
req->thread_id, (long long)req->wsrep_trx_seqno, \
req->thread_id, (long long)wsrep_thd_trx_seqno(req), \
req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \
req->command, req->lex->sql_command, req->query(), \
gra->thread_id, (long long)gra->wsrep_trx_seqno, \
gra->thread_id, (long long)wsrep_thd_trx_seqno(gra), \
gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \
gra->command, gra->lex->sql_command, gra->query());

View File

@ -1,4 +1,4 @@
/* Copyright 2008-2012 Codership Oy <http://www.codership.com>
/* Copyright 2008-2013 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
@ -26,23 +26,22 @@ typedef struct st_mysql_show_var SHOW_VAR;
class set_var;
class THD;
#ifdef WITH_WSREP
#include "../wsrep/wsrep_api.h"
//#include "wsrep_mysqld.h"
enum wsrep_exec_mode {
enum wsrep_exec_mode {
LOCAL_STATE,
REPL_RECV,
TOTAL_ORDER,
LOCAL_COMMIT
};
enum wsrep_query_state {
};
enum wsrep_query_state {
QUERY_IDLE,
QUERY_EXEC,
QUERY_COMMITTING,
QUERY_EXITING,
QUERY_ROLLINGBACK,
};
enum wsrep_conflict_state {
};
enum wsrep_conflict_state {
NO_CONFLICT,
MUST_ABORT,
ABORTING,
@ -51,13 +50,14 @@ class THD;
REPLAYING,
RETRY_AUTOCOMMIT,
CERT_FAILURE,
};
enum wsrep_consistency_check_mode {
};
enum wsrep_consistency_check_mode {
NO_CONSISTENCY_CHECK,
CONSISTENCY_CHECK_DECLARED,
CONSISTENCY_CHECK_RUNNING,
};
#endif
};
// Global wsrep parameters
extern wsrep_t* wsrep;
@ -73,20 +73,16 @@ extern const char* wsrep_node_incoming_address;
extern const char* wsrep_data_home_dir;
extern const char* wsrep_dbug_option;
extern long wsrep_slave_threads;
extern my_bool wsrep_debug;
extern int wsrep_slave_count_change;
extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug;
extern my_bool wsrep_convert_LOCK_to_trx;
extern ulong wsrep_retry_autocommit;
extern my_bool wsrep_auto_increment_control;
extern my_bool wsrep_drupal_282555_workaround;
extern my_bool wsrep_incremental_data_collection;
extern const char* wsrep_sst_method;
extern const char* wsrep_sst_receive_address;
extern char* wsrep_sst_auth;
extern const char* wsrep_sst_donor;
extern my_bool wsrep_sst_donor_rejects_queries;
extern const char* wsrep_start_position;
extern long long wsrep_max_ws_size;
extern long wsrep_max_ws_rows;
extern ulong wsrep_max_ws_size;
extern ulong wsrep_max_ws_rows;
extern const char* wsrep_notify_cmd;
extern my_bool wsrep_certify_nonPK;
extern long wsrep_max_protocol_version;
@ -98,7 +94,6 @@ extern my_bool wsrep_recovery;
extern my_bool wsrep_replicate_myisam;
extern my_bool wsrep_log_conflicts;
extern ulong wsrep_mysql_replication_bundle;
extern ulong wsrep_mysql_replication_bundle;
extern my_bool wsrep_load_data_splitting;
enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU };
@ -111,81 +106,29 @@ extern long long wsrep_cluster_conf_id;
extern const char* wsrep_cluster_status;
extern long wsrep_cluster_size;
extern long wsrep_local_index;
extern long long wsrep_local_bf_aborts;
extern const char* wsrep_provider_name;
extern const char* wsrep_provider_version;
extern const char* wsrep_provider_vendor;
extern int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
extern void wsrep_free_status(THD *thd);
// Other wsrep global variables
extern my_bool wsrep_inited; // whether wsrep is initialized ?
#define WSREP_SST_ADDRESS_AUTO "AUTO"
#define WSREP_NODE_INCOMING_AUTO "AUTO"
int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
void wsrep_free_status(THD *thd);
// MySQL variables funcs
#define CHECK_ARGS (sys_var *self, THD* thd, set_var *var)
#define UPDATE_ARGS (sys_var *self, THD* thd, enum_var_type type)
#define DEFAULT_ARGS (THD* thd, enum_var_type var_type)
#define INIT_ARGS (const char* opt)
extern int wsrep_init_vars();
extern bool wsrep_on_update UPDATE_ARGS;
extern void wsrep_causal_reads_update UPDATE_ARGS;
extern bool wsrep_start_position_check CHECK_ARGS;
extern bool wsrep_start_position_update UPDATE_ARGS;
extern void wsrep_start_position_init INIT_ARGS;
extern bool wsrep_provider_check CHECK_ARGS;
extern bool wsrep_provider_update UPDATE_ARGS;
extern void wsrep_provider_init INIT_ARGS;
extern bool wsrep_provider_options_check CHECK_ARGS;
extern bool wsrep_provider_options_update UPDATE_ARGS;
extern void wsrep_provider_options_init INIT_ARGS;
extern bool wsrep_cluster_address_check CHECK_ARGS;
extern bool wsrep_cluster_address_update UPDATE_ARGS;
extern void wsrep_cluster_address_init INIT_ARGS;
extern bool wsrep_cluster_name_check CHECK_ARGS;
extern bool wsrep_cluster_name_update UPDATE_ARGS;
extern bool wsrep_node_name_check CHECK_ARGS;
extern bool wsrep_node_name_update UPDATE_ARGS;
extern bool wsrep_node_address_check CHECK_ARGS;
extern bool wsrep_node_address_update UPDATE_ARGS;
extern void wsrep_node_address_init INIT_ARGS;
extern bool wsrep_sst_method_check CHECK_ARGS;
extern bool wsrep_sst_method_update UPDATE_ARGS;
extern void wsrep_sst_method_init INIT_ARGS;
extern bool wsrep_sst_receive_address_check CHECK_ARGS;
extern bool wsrep_sst_receive_address_update UPDATE_ARGS;
extern bool wsrep_sst_auth_check CHECK_ARGS;
extern bool wsrep_sst_auth_update UPDATE_ARGS;
extern void wsrep_sst_auth_init INIT_ARGS;
extern bool wsrep_sst_donor_check CHECK_ARGS;
extern bool wsrep_sst_donor_update UPDATE_ARGS;
extern bool wsrep_slave_threads_check CHECK_ARGS;
extern bool wsrep_slave_threads_update UPDATE_ARGS;
extern bool wsrep_desync_check CHECK_ARGS;
extern bool wsrep_desync_update UPDATE_ARGS;
extern bool wsrep_before_SE(); // initialize wsrep before storage
// engines (true) or after (false)
extern int wsrep_init();
extern void wsrep_deinit();
extern void wsrep_recover();
/* Filters out --wsrep-new-cluster oprtion from argv[]
* should be called in the very beginning of main() */
void wsrep_filter_new_cluster (int* argc, char* argv[]);
int wsrep_init();
void wsrep_deinit();
void wsrep_recover();
bool wsrep_before_SE(); // initialize wsrep before storage
// engines (true) or after (false)
/* wsrep initialization sequence at startup
* @param before wsrep_before_SE() value */
void wsrep_init_startup(bool before);
extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
@ -194,18 +137,18 @@ extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd);
extern "C" const char * wsrep_thd_exec_mode_str(THD *thd);
extern "C" const char * wsrep_thd_conflict_state_str(THD *thd);
extern "C" const char * wsrep_thd_query_state_str(THD *thd);
extern "C" wsrep_trx_handle_t* wsrep_thd_trx_handle(THD *thd);
extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd);
extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
extern "C" void wsrep_thd_set_query_state(
THD *thd, enum wsrep_query_state state);
THD *thd, enum wsrep_query_state state);
extern "C" void wsrep_thd_set_conflict_state(
THD *thd, enum wsrep_conflict_state state);
THD *thd, enum wsrep_conflict_state state);
extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id);
extern "C"void wsrep_thd_LOCK(THD *thd);
extern "C"void wsrep_thd_UNLOCK(THD *thd);
extern "C" void wsrep_thd_LOCK(THD *thd);
extern "C" void wsrep_thd_UNLOCK(THD *thd);
extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
extern "C" time_t wsrep_thd_query_start(THD *thd);
extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
@ -217,18 +160,11 @@ extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id);
extern "C" void wsrep_thd_awake(THD* bf_thd, THD *thd, my_bool signal);
/* wsrep initialization sequence at startup
* @param first wsrep_before_SE() value */
extern void wsrep_init_startup(bool before);
extern void wsrep_close_client_connections(my_bool wait_to_end);
extern int wsrep_wait_committing_connections_close(int wait_time);
extern void wsrep_close_applier(THD *thd);
extern void wsrep_wait_appliers_close(THD *thd);
extern void wsrep_close_applier_threads(int count);
extern void wsrep_create_appliers(long threads = wsrep_slave_threads);
extern void wsrep_create_rollbacker();
extern void wsrep_kill_mysql(THD *thd);
/* new defines */
@ -285,32 +221,20 @@ extern wsrep_seqno_t wsrep_locked_seqno;
WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:",\
(bf_abort) ? "high priority abort" : "certification failure" \
); \
if (bf_thd != NULL) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \
}
#define WSREP_PROVIDER_EXISTS \
(wsrep_provider && strncasecmp(wsrep_provider, WSREP_NONE, FN_REFLEN))
/*! Synchronizes applier thread start with init thread */
extern void wsrep_sst_grab();
/*! Init thread waits for SST completion */
extern bool wsrep_sst_wait();
/*! Signals wsrep that initialization is complete, writesets can be applied */
extern void wsrep_sst_continue();
extern void wsrep_SE_init_grab(); /*! grab init critical section */
extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */
extern void wsrep_SE_init_done(); /*! signal that SE init is complte */
extern void wsrep_SE_initialized(); /*! mark SE initialization complete */
extern void wsrep_ready_wait();
enum wsrep_trx_status {
WSREP_TRX_OK,
WSREP_TRX_ROLLBACK,
WSREP_TRX_ERROR,
};
};
extern enum wsrep_trx_status
wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all);
@ -318,17 +242,10 @@ class Ha_trx_info;
struct THD_TRANS;
void wsrep_register_hton(THD* thd, bool all);
void wsrep_post_commit(THD* thd, bool all);
void wsrep_replication_process(THD *thd);
void wsrep_rollback_process(THD *thd);
void wsrep_brute_force_killer(THD *thd);
int wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id);
extern "C" bool wsrep_consistency_check(void *thd_ptr);
extern "C" int wsrep_thd_is_brute_force(void *thd_ptr);
extern "C" int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
my_bool signal);
extern "C" int wsrep_thd_in_locking_session(void *thd_ptr);
void *wsrep_prepare_bf_thd(THD *thd);
void wsrep_return_from_bf_mode(void *shadow, THD *thd);
/* this is visible for client build so that innodb plugin gets this */
typedef struct wsrep_aborting_thd {
@ -337,29 +254,21 @@ typedef struct wsrep_aborting_thd {
} *wsrep_aborting_thd_t;
extern mysql_mutex_t LOCK_wsrep_ready;
extern mysql_cond_t COND_wsrep_ready;
extern mysql_cond_t COND_wsrep_ready;
extern mysql_mutex_t LOCK_wsrep_sst;
extern mysql_cond_t COND_wsrep_sst;
extern mysql_cond_t COND_wsrep_sst;
extern mysql_mutex_t LOCK_wsrep_sst_init;
extern mysql_cond_t COND_wsrep_sst_init;
extern mysql_cond_t COND_wsrep_sst_init;
extern mysql_mutex_t LOCK_wsrep_rollback;
extern mysql_cond_t COND_wsrep_rollback;
extern mysql_cond_t COND_wsrep_rollback;
extern int wsrep_replaying;
extern mysql_mutex_t LOCK_wsrep_replaying;
extern mysql_cond_t COND_wsrep_replaying;
extern wsrep_aborting_thd_t wsrep_aborting_thd;
extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug;
extern my_bool wsrep_convert_LOCK_to_trx;
extern ulong wsrep_retry_autocommit;
extern my_bool wsrep_emulate_bin_log;
extern my_bool wsrep_auto_increment_control;
extern my_bool wsrep_drupal_282555_workaround;
extern long long wsrep_max_ws_size;
extern long wsrep_max_ws_rows;
extern int wsrep_to_isolation;
extern my_bool wsrep_certify_nonPK;
extern mysql_cond_t COND_wsrep_replaying;
extern mysql_mutex_t LOCK_wsrep_slave_threads;
extern mysql_mutex_t LOCK_wsrep_desync;
extern wsrep_aborting_thd_t wsrep_aborting_thd;
extern my_bool wsrep_emulate_bin_log;
extern int wsrep_to_isolation;
extern PSI_mutex_key key_LOCK_wsrep_ready;
extern PSI_mutex_key key_COND_wsrep_ready;
@ -381,13 +290,11 @@ int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
const TABLE_LIST* table_list);
void wsrep_to_isolation_end(THD *thd);
void wsrep_cleanup_transaction(THD *thd);
void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow*);
void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow*);
int wsrep_to_buf_helper(
THD* thd, const char *query, uint query_len, uchar** buf, uint* buf_len);
int wsrep_create_sp(THD *thd, uchar** buf, uint* buf_len);
int wsrep_create_trigger_query(THD *thd, uchar** buf, uint* buf_len);
int wsrep_create_event_query(THD *thd, uchar** buf, uint* buf_len);
THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len);
int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len);
const wsrep_uuid_t* wsrep_cluster_uuid();
struct xid_t;

View File

@ -15,6 +15,7 @@
#include <mysqld.h>
#include "wsrep_priv.h"
#include "wsrep_utils.h"
const char* wsrep_notify_cmd="";
@ -64,7 +65,7 @@ void wsrep_notify_status (wsrep_member_status_t status,
{
char uuid_str[40];
wsrep_uuid_print (&view->uuid, uuid_str, sizeof(uuid_str));
wsrep_uuid_print (&view->state_id.uuid, uuid_str, sizeof(uuid_str));
cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
" --uuid %s", uuid_str);

View File

@ -26,208 +26,26 @@
#include <pthread.h>
#include <cstdio>
extern void wsrep_ready_set (my_bool x);
void wsrep_ready_set (my_bool x);
extern ssize_t wsrep_sst_prepare (void** msg);
extern int wsrep_sst_donate_cb (void* app_ctx,
void* recv_ctx,
const void* msg, size_t msg_len,
const wsrep_uuid_t* current_uuid,
wsrep_seqno_t current_seqno,
const char* state, size_t state_len,
bool bypass);
extern size_t guess_ip (char* buf, size_t buf_len);
extern size_t guess_address(char* buf, size_t buf_len);
ssize_t wsrep_sst_prepare (void** msg);
wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx,
void* recv_ctx,
const void* msg, size_t msg_len,
const wsrep_gtid_t* state_id,
const char* state, size_t state_len,
bool bypass);
extern wsrep_uuid_t local_uuid;
extern wsrep_seqno_t local_seqno;
// a helper function
void wsrep_sst_received(wsrep_t*, const wsrep_uuid_t*, wsrep_seqno_t,
const void*, size_t);
/*! SST thread signals init thread about sst completion */
extern void wsrep_sst_complete(const wsrep_uuid_t* uuid, wsrep_seqno_t, bool);
void wsrep_sst_complete(const wsrep_uuid_t*, wsrep_seqno_t, bool);
extern void wsrep_notify_status (wsrep_member_status_t new_status,
const wsrep_view_info_t* view = 0);
void wsrep_notify_status (wsrep_member_status_t new_status,
const wsrep_view_info_t* view = 0);
namespace wsp {
class node_status
{
public:
node_status() : status(WSREP_MEMBER_UNDEFINED) {}
void set(wsrep_member_status_t new_status,
const wsrep_view_info_t* view = 0)
{
if (status != new_status || 0 != view)
{
wsrep_notify_status(new_status, view);
status = new_status;
}
}
wsrep_member_status_t get() const { return status; }
private:
wsrep_member_status_t status;
};
} /* namespace wsp */
extern wsp::node_status local_status;
namespace wsp {
/* A small class to run external programs. */
class process
{
private:
const char* const str_;
FILE* io_;
int err_;
pid_t pid_;
public:
/*! @arg type is a pointer to a null-terminated string which must contain
either the letter 'r' for reading or the letter 'w' for writing.
*/
process (const char* cmd, const char* type);
~process ();
FILE* pipe () { return io_; }
int error() { return err_; }
int wait ();
const char* cmd() { return str_; }
};
#ifdef REMOVED
class lock
{
pthread_mutex_t* const mtx_;
public:
lock (pthread_mutex_t* mtx) : mtx_(mtx)
{
int err = pthread_mutex_lock (mtx_);
if (err)
{
WSREP_ERROR("Mutex lock failed: %s", strerror(err));
abort();
}
}
virtual ~lock ()
{
int err = pthread_mutex_unlock (mtx_);
if (err)
{
WSREP_ERROR("Mutex unlock failed: %s", strerror(err));
abort();
}
}
inline void wait (pthread_cond_t* cond)
{
pthread_cond_wait (cond, mtx_);
}
private:
lock (const lock&);
lock& operator=(const lock&);
};
class monitor
{
int mutable refcnt;
pthread_mutex_t mutable mtx;
pthread_cond_t mutable cond;
public:
monitor() : refcnt(0)
{
pthread_mutex_init (&mtx, NULL);
pthread_cond_init (&cond, NULL);
}
~monitor()
{
pthread_mutex_destroy (&mtx);
pthread_cond_destroy (&cond);
}
void enter() const
{
lock l(&mtx);
while (refcnt)
{
l.wait(&cond);
}
refcnt++;
}
void leave() const
{
lock l(&mtx);
refcnt--;
if (refcnt == 0)
{
pthread_cond_signal (&cond);
}
}
private:
monitor (const monitor&);
monitor& operator= (const monitor&);
};
class critical
{
const monitor& mon;
public:
critical(const monitor& m) : mon(m) { mon.enter(); }
~critical() { mon.leave(); }
private:
critical (const critical&);
critical& operator= (const critical&);
};
#endif
class thd
{
class thd_init
{
public:
thd_init() { my_thread_init(); }
~thd_init() { my_thread_end(); }
}
init;
thd (const thd&);
thd& operator= (const thd&);
public:
thd(my_bool wsrep_on);
~thd();
THD* const ptr;
};
class string
{
public:
string() : string_(0) {}
void set(char* str) { if (string_) free (string_); string_ = str; }
~string() { set (0); }
private:
char* string_;
};
} // namespace wsrep
#endif /* WSREP_PRIV_H */

View File

@ -13,6 +13,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "wsrep_sst.h"
#include <mysqld.h>
#include <m_ctype.h>
#include <my_sys.h>
@ -23,6 +25,7 @@
#include <sql_reload.h>
#include <sql_parse.h>
#include "wsrep_priv.h"
#include "wsrep_utils.h"
#include <cstdio>
#include <cstdlib>
@ -61,7 +64,6 @@ const char* wsrep_sst_donor = "";
// container for real auth string
static const char* sst_auth_real = NULL;
my_bool wsrep_sst_donor_rejects_queries = FALSE;
bool wsrep_sst_method_check (sys_var *self, THD* thd, set_var* var)
@ -214,8 +216,8 @@ bool wsrep_sst_wait ()
// Signal end of SST
void wsrep_sst_complete (const wsrep_uuid_t* sst_uuid,
wsrep_seqno_t sst_seqno,
bool needed)
wsrep_seqno_t sst_seqno,
bool needed)
{
if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort();
if (!sst_complete)
@ -228,18 +230,37 @@ void wsrep_sst_complete (const wsrep_uuid_t* sst_uuid,
}
else
{
WSREP_WARN("Nobody is waiting for SST.");
/* This can happen when called from wsrep_synced_cb().
At the moment there is no way to check there
if main thread is still waiting for signal,
so wsrep_sst_complete() is called from there
each time wsrep_ready changes from FALSE -> TRUE.
*/
WSREP_DEBUG("Nobody is waiting for SST.");
}
mysql_mutex_unlock (&LOCK_wsrep_sst);
}
void wsrep_sst_received (wsrep_t* const wsrep,
const wsrep_uuid_t* const uuid,
wsrep_seqno_t const seqno,
const void* const state,
size_t const state_len)
{
int const rcode(seqno < 0 ? seqno : 0);
wsrep_gtid_t const state_id = {
*uuid, (rcode ? WSREP_SEQNO_UNDEFINED : seqno)
};
wsrep->sst_received(wsrep, &state_id, state, state_len, rcode);
}
// Let applier threads to continue
void wsrep_sst_continue ()
{
if (sst_needed)
{
WSREP_INFO("Signalling provider to continue.");
wsrep->sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
}
}
@ -519,7 +540,7 @@ ssize_t wsrep_sst_prepare (void** msg)
}
else
{
ssize_t ret= guess_ip (ip_buf, ip_max);
ssize_t ret= wsrep_guess_ip (ip_buf, ip_max);
if (ret && ret < ip_max)
{
@ -707,7 +728,9 @@ static int sst_donate_mysqldump (const char* addr,
ret= sst_run_shell (cmd_str, 3);
}
wsrep->sst_sent (wsrep, uuid, ret ? ret : seqno);
wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)};
wsrep->sst_sent (wsrep, &state_id, ret);
return ret;
}
@ -927,7 +950,10 @@ wait_signal:
}
// signal to donor that SST is over
wsrep->sst_sent (wsrep, &ret_uuid, err ? -err : ret_seqno);
struct wsrep_gtid const state_id = {
ret_uuid, err ? WSREP_SEQNO_UNDEFINED : ret_seqno
};
wsrep->sst_sent (wsrep, &state_id, -err);
proc.wait();
return NULL;
@ -981,12 +1007,11 @@ static int sst_donate_other (const char* method,
return arg.err;
}
int wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
const void* msg, size_t msg_len,
const wsrep_uuid_t* current_uuid,
wsrep_seqno_t current_seqno,
const char* state, size_t state_len,
bool bypass)
wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
const void* msg, size_t msg_len,
const wsrep_gtid_t* current_gtid,
const char* state, size_t state_len,
bool bypass)
{
/* This will be reset when sync callback is called.
* Should we set wsrep_ready to FALSE here too? */
@ -998,20 +1023,20 @@ int wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
const char* data = method + method_len + 1;
char uuid_str[37];
wsrep_uuid_print (current_uuid, uuid_str, sizeof(uuid_str));
wsrep_uuid_print (&current_gtid->uuid, uuid_str, sizeof(uuid_str));
int ret;
if (!strcmp (WSREP_SST_MYSQLDUMP, method))
{
ret = sst_donate_mysqldump (data, current_uuid, uuid_str, current_seqno,
bypass);
ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str,
current_gtid->seqno, bypass);
}
else
{
ret = sst_donate_other (method, data, uuid_str, current_seqno, bypass);
ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass);
}
return (ret > 0 ? 0 : ret);
return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE);
}
void wsrep_SE_init_grab()
@ -1021,7 +1046,10 @@ void wsrep_SE_init_grab()
void wsrep_SE_init_wait()
{
mysql_cond_wait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init);
while (SE_initialized == false)
{
mysql_cond_wait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init);
}
mysql_mutex_unlock (&LOCK_wsrep_sst_init);
}

40
sql/wsrep_sst.h Normal file
View File

@ -0,0 +1,40 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef WSREP_SST_H
#define WSREP_SST_H
#include <mysql.h> // my_bool
/* system variables */
extern const char* wsrep_sst_method;
extern const char* wsrep_sst_receive_address;
extern const char* wsrep_sst_donor;
extern char* wsrep_sst_auth;
extern my_bool wsrep_sst_donor_rejects_queries;
/*! Synchronizes applier thread start with init thread */
extern void wsrep_sst_grab();
/*! Init thread waits for SST completion */
extern bool wsrep_sst_wait();
/*! Signals wsrep that initialization is complete, writesets can be applied */
extern void wsrep_sst_continue();
extern void wsrep_SE_init_grab(); /*! grab init critical section */
extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */
extern void wsrep_SE_init_done(); /*! signal that SE init is complte */
extern void wsrep_SE_initialized(); /*! mark SE initialization complete */
#endif /* WSREP_SST_H */

464
sql/wsrep_thd.cc Normal file
View File

@ -0,0 +1,464 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "wsrep_thd.h"
#include "transaction.h"
#include "rpl_rli.h"
#include "log_event.h"
#include "sql_parse.h"
#include "slave.h" // opt_log_slave_updates
#include "sql_base.h" // close_thread_tables()
#include "mysqld.h" // start_wsrep_THD();
static long long wsrep_bf_aborts_counter = 0;
int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff)
{
wsrep_local_bf_aborts = my_atomic_load64(&wsrep_bf_aborts_counter);
var->type = SHOW_LONGLONG;
var->value = (char*)&wsrep_local_bf_aborts;
return 0;
}
/* must have (&thd->LOCK_wsrep_thd) */
void wsrep_client_rollback(THD *thd)
{
WSREP_DEBUG("client rollback due to BF abort for (%ld), query: %s",
thd->thread_id, thd->query());
my_atomic_add64(&wsrep_bf_aborts_counter, 1);
thd->wsrep_conflict_state= ABORTING;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
trans_rollback(thd);
if (thd->locked_tables_mode && thd->lock)
{
WSREP_DEBUG("unlocking tables for BF abort (%ld)", thd->thread_id);
thd->locked_tables_list.unlock_locked_tables(thd);
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
if (thd->global_read_lock.is_acquired())
{
WSREP_DEBUG("unlocking GRL for BF abort (%ld)", thd->thread_id);
thd->global_read_lock.unlock_global_read_lock(thd);
}
/* Release transactional metadata locks. */
thd->mdl_context.release_transactional_locks();
/* release explicit MDL locks */
thd->mdl_context.release_explicit_locks();
if (thd->get_binlog_table_maps())
{
WSREP_DEBUG("clearing binlog table map for BF abort (%ld)", thd->thread_id);
thd->clear_binlog_table_maps();
}
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
thd->wsrep_conflict_state= ABORTED;
}
static Relay_log_info* wsrep_relay_log_init(const char* log_fname)
{
Relay_log_info* rli= new Relay_log_info(false);
rli->no_storage= true;
if (!rli->relay_log.description_event_for_exec)
{
rli->relay_log.description_event_for_exec=
new Format_description_log_event(4);
}
rli->sql_thd= current_thd;
return rli;
}
static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
{
shadow->options = thd->variables.option_bits;
shadow->server_status = thd->server_status;
shadow->wsrep_exec_mode = thd->wsrep_exec_mode;
shadow->vio = thd->net.vio;
if (opt_log_slave_updates)
thd->variables.option_bits|= OPTION_BIN_LOG;
else
thd->variables.option_bits&= ~(OPTION_BIN_LOG);
if (!thd->wsrep_rli) thd->wsrep_rli= wsrep_relay_log_init("wsrep_relay");
thd->wsrep_exec_mode= REPL_RECV;
thd->net.vio= 0;
thd->clear_error();
shadow->tx_isolation = thd->variables.tx_isolation;
thd->variables.tx_isolation = ISO_READ_COMMITTED;
thd->tx_isolation = ISO_READ_COMMITTED;
shadow->db = thd->db;
shadow->db_length = thd->db_length;
thd->reset_db(NULL, 0);
}
static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow)
{
thd->variables.option_bits = shadow->options;
thd->server_status = shadow->server_status;
thd->wsrep_exec_mode = shadow->wsrep_exec_mode;
thd->net.vio = shadow->vio;
thd->variables.tx_isolation = shadow->tx_isolation;
thd->reset_db(shadow->db, shadow->db_length);
}
void wsrep_replay_transaction(THD *thd)
{
/* checking if BF trx must be replayed */
if (thd->wsrep_conflict_state== MUST_REPLAY) {
if (thd->wsrep_exec_mode!= REPL_RECV) {
if (thd->stmt_da->is_sent)
{
WSREP_ERROR("replay issue, thd has reported status already");
}
thd->stmt_da->reset_diagnostics_area();
thd->wsrep_conflict_state= REPLAYING;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
mysql_reset_thd_for_next_command(thd);
thd->killed= NOT_KILLED;
close_thread_tables(thd);
if (thd->locked_tables_mode && thd->lock)
{
WSREP_DEBUG("releasing table lock for replaying (%ld)",
thd->thread_id);
thd->locked_tables_list.unlock_locked_tables(thd);
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
}
thd->mdl_context.release_transactional_locks();
thd_proc_info(thd, "wsrep replaying trx");
WSREP_DEBUG("replay trx: %s %lld",
thd->query() ? thd->query() : "void",
(long long)wsrep_thd_trx_seqno(thd));
struct wsrep_thd_shadow shadow;
wsrep_prepare_bf_thd(thd, &shadow);
/* From trans_begin() */
thd->variables.option_bits|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
int rcode = wsrep->replay_trx(wsrep,
&thd->wsrep_ws_handle,
(void *)thd);
wsrep_return_from_bf_mode(thd, &shadow);
if (thd->wsrep_conflict_state!= REPLAYING)
WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state );
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
switch (rcode)
{
case WSREP_OK:
thd->wsrep_conflict_state= NO_CONFLICT;
wsrep->post_commit(wsrep, &thd->wsrep_ws_handle);
WSREP_DEBUG("trx_replay successful for: %ld %llu",
thd->thread_id, (long long)thd->real_id);
if (thd->stmt_da->is_sent)
{
WSREP_WARN("replay ok, thd has reported status");
}
else if (thd->stmt_da->is_set())
{
if (thd->stmt_da->status() != Diagnostics_area::DA_OK)
{
WSREP_WARN("replay ok, thd has error status %d",
thd->stmt_da->status());
}
}
else
{
my_ok(thd);
}
break;
case WSREP_TRX_FAIL:
if (thd->stmt_da->is_sent)
{
WSREP_ERROR("replay failed, thd has reported status");
}
else
{
WSREP_DEBUG("replay failed, rolling back");
my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
}
thd->wsrep_conflict_state= ABORTED;
wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle);
break;
default:
WSREP_ERROR("trx_replay failed for: %d, query: %s",
rcode, thd->query() ? thd->query() : "void");
/* we're now in inconsistent state, must abort */
unireg_abort(1);
break;
}
wsrep_cleanup_transaction(thd);
mysql_mutex_lock(&LOCK_wsrep_replaying);
wsrep_replaying--;
WSREP_DEBUG("replaying decreased: %d, thd: %lu",
wsrep_replaying, thd->thread_id);
mysql_cond_broadcast(&COND_wsrep_replaying);
mysql_mutex_unlock(&LOCK_wsrep_replaying);
}
}
}
static void wsrep_replication_process(THD *thd)
{
int rcode;
DBUG_ENTER("wsrep_replication_process");
struct wsrep_thd_shadow shadow;
wsrep_prepare_bf_thd(thd, &shadow);
/* From trans_begin() */
thd->variables.option_bits|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
rcode = wsrep->recv(wsrep, (void *)thd);
DBUG_PRINT("wsrep",("wsrep_repl returned: %d", rcode));
WSREP_INFO("applier thread exiting (code:%d)", rcode);
switch (rcode) {
case WSREP_OK:
case WSREP_NOT_IMPLEMENTED:
case WSREP_CONN_FAIL:
/* provider does not support slave operations / disconnected from group,
* just close applier thread */
break;
case WSREP_NODE_FAIL:
/* data inconsistency => SST is needed */
/* Note: we cannot just blindly restart replication here,
* SST might require server restart if storage engines must be
* initialized after SST */
WSREP_ERROR("node consistency compromised, aborting");
wsrep_kill_mysql(thd);
break;
case WSREP_WARNING:
case WSREP_TRX_FAIL:
case WSREP_TRX_MISSING:
/* these suggests a bug in provider code */
WSREP_WARN("bad return from recv() call: %d", rcode);
/* fall through to node shutdown */
case WSREP_FATAL:
/* Cluster connectivity is lost.
*
* If applier was killed on purpose (KILL_CONNECTION), we
* avoid mysql shutdown. This is because the killer will then handle
* shutdown processing (or replication restarting)
*/
if (thd->killed != KILL_CONNECTION)
{
wsrep_kill_mysql(thd);
}
break;
}
mysql_mutex_lock(&LOCK_thread_count);
wsrep_close_applier(thd);
mysql_cond_broadcast(&COND_thread_count);
mysql_mutex_unlock(&LOCK_thread_count);
if (thd->temporary_tables)
{
WSREP_DEBUG("Applier %lu, has temporary tables at exit", thd->thread_id);
}
wsrep_return_from_bf_mode(thd, &shadow);
DBUG_VOID_RETURN;
}
void wsrep_create_appliers(long threads)
{
if (!wsrep_connected)
{
/* see wsrep_replication_start() for the logic */
if (wsrep_cluster_address && strlen(wsrep_cluster_address) &&
wsrep_provider && strcasecmp(wsrep_provider, "none"))
{
WSREP_ERROR("Trying to launch slave threads before creating "
"connection at '%s'", wsrep_cluster_address);
assert(0);
}
return;
}
long wsrep_threads=0;
pthread_t hThread;
while (wsrep_threads++ < threads) {
if (pthread_create(
&hThread, &connection_attrib,
start_wsrep_THD, (void*)wsrep_replication_process))
WSREP_WARN("Can't create thread to manage wsrep replication");
}
}
static void wsrep_rollback_process(THD *thd)
{
DBUG_ENTER("wsrep_rollback_process");
mysql_mutex_lock(&LOCK_wsrep_rollback);
wsrep_aborting_thd= NULL;
while (thd->killed == NOT_KILLED) {
thd_proc_info(thd, "wsrep aborter idle");
thd->mysys_var->current_mutex= &LOCK_wsrep_rollback;
thd->mysys_var->current_cond= &COND_wsrep_rollback;
mysql_cond_wait(&COND_wsrep_rollback,&LOCK_wsrep_rollback);
WSREP_DEBUG("WSREP rollback thread wakes for signal");
mysql_mutex_lock(&thd->mysys_var->mutex);
thd_proc_info(thd, "wsrep aborter active");
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
mysql_mutex_unlock(&thd->mysys_var->mutex);
/* check for false alarms */
if (!wsrep_aborting_thd)
{
WSREP_DEBUG("WSREP rollback thread has empty abort queue");
}
/* process all entries in the queue */
while (wsrep_aborting_thd) {
THD *aborting;
wsrep_aborting_thd_t next = wsrep_aborting_thd->next;
aborting = wsrep_aborting_thd->aborting_thd;
my_free(wsrep_aborting_thd);
wsrep_aborting_thd= next;
/*
* must release mutex, appliers my want to add more
* aborting thds in our work queue, while we rollback
*/
mysql_mutex_unlock(&LOCK_wsrep_rollback);
mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
if (aborting->wsrep_conflict_state== ABORTED)
{
WSREP_DEBUG("WSREP, thd already aborted: %llu state: %d",
(long long)aborting->real_id,
aborting->wsrep_conflict_state);
mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
mysql_mutex_lock(&LOCK_wsrep_rollback);
continue;
}
aborting->wsrep_conflict_state= ABORTING;
mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
aborting->store_globals();
mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
wsrep_client_rollback(aborting);
WSREP_DEBUG("WSREP rollbacker aborted thd: (%lu %llu)",
aborting->thread_id, (long long)aborting->real_id);
mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
mysql_mutex_lock(&LOCK_wsrep_rollback);
}
}
mysql_mutex_unlock(&LOCK_wsrep_rollback);
sql_print_information("WSREP: rollbacker thread exiting");
DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting"));
DBUG_VOID_RETURN;
}
void wsrep_create_rollbacker()
{
if (wsrep_provider && strcasecmp(wsrep_provider, "none"))
{
pthread_t hThread;
/* create rollbacker */
if (pthread_create( &hThread, &connection_attrib,
start_wsrep_THD, (void*)wsrep_rollback_process))
WSREP_WARN("Can't create thread to manage wsrep rollback");
}
}
extern "C"
int wsrep_thd_is_brute_force(void *thd_ptr)
{
/*
Brute force:
Appliers and replaying are running in REPL_RECV mode. TOI statements
in TOTAL_ORDER mode. Locally committing transaction that has got
past wsrep->pre_commit() without error is running in LOCAL_COMMIT mode.
Everything else is running in LOCAL_STATE and should not be considered
brute force.
*/
if (thd_ptr) {
switch (((THD *)thd_ptr)->wsrep_exec_mode) {
case LOCAL_STATE: return 0;
case REPL_RECV: return 1;
case TOTAL_ORDER: return 2;
case LOCAL_COMMIT: return 3;
}
}
DBUG_ASSERT(0);
return 0;
}
extern "C"
int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal)
{
THD *victim_thd = (THD *) victim_thd_ptr;
THD *bf_thd = (THD *) bf_thd_ptr;
DBUG_ENTER("wsrep_abort_thd");
if ( (WSREP(bf_thd) ||
( (WSREP_ON || wsrep_OSU_method_options == WSREP_OSU_RSU) &&
bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) &&
victim_thd)
{
WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ?
(long long)bf_thd->real_id : 0, (long long)victim_thd->real_id);
ha_wsrep_abort_transaction(bf_thd, victim_thd, signal);
}
else
{
WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd);
}
DBUG_RETURN(1);
}
extern "C"
int wsrep_thd_in_locking_session(void *thd_ptr)
{
if (thd_ptr && ((THD *)thd_ptr)->in_lock_tables) {
return 1;
}
return 0;
}

32
sql/wsrep_thd.h Normal file
View File

@ -0,0 +1,32 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef WSREP_THD_H
#define WSREP_THD_H
#include "sql_class.h"
int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff);
void wsrep_client_rollback(THD *thd);
void wsrep_replay_transaction(THD *thd);
void wsrep_create_appliers(long threads);
void wsrep_create_rollbacker();
extern "C" int wsrep_thd_is_brute_force(void *thd_ptr);
extern "C" int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
my_bool signal);
extern "C" int wsrep_thd_in_locking_session(void *thd_ptr);
#endif /* WSREP_THD_H */

View File

@ -14,20 +14,25 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//! @file declares symbols private to wsrep integration layer
//! @file some utility functions and classes not directly related to replication
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // POSIX_SPAWN_USEVFORK flag
#endif
#include "wsrep_utils.h"
#include "wsrep_mysqld.h"
#include <sql_class.h>
#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"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h> // getaddrinfo()
extern char** environ; // environment variables
@ -313,23 +318,69 @@ thd::~thd ()
} // namespace wsp
extern ulong my_bind_addr;
extern uint mysqld_port;
/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */
unsigned int wsrep_check_ip (const char* const addr)
{
unsigned int ret = INADDR_NONE;
struct addrinfo *res, hints;
size_t guess_ip (char* buf, size_t buf_len)
memset (&hints, 0, sizeof(hints));
hints.ai_flags= AI_PASSIVE/*|AI_ADDRCONFIG*/;
hints.ai_socktype= SOCK_STREAM;
hints.ai_family= AF_UNSPEC;
int gai_ret = getaddrinfo(addr, NULL, &hints, &res);
if (0 == gai_ret)
{
if (AF_INET == res->ai_family) /* IPv4 */
{
struct sockaddr_in* a= (struct sockaddr_in*)res->ai_addr;
ret= htonl(a->sin_addr.s_addr);
}
else /* IPv6 */
{
struct sockaddr_in6* a= (struct sockaddr_in6*)res->ai_addr;
if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
ret= INADDR_ANY;
else if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr))
ret= INADDR_LOOPBACK;
else
ret= 0xdeadbeef;
}
freeaddrinfo (res);
}
else {
WSREP_ERROR ("getaddrinfo() failed on '%s': %d (%s)",
addr, gai_ret, gai_strerror(gai_ret));
}
// uint8_t* b= (uint8_t*)&ret;
// fprintf (stderr, "########## wsrep_check_ip returning: %hhu.%hhu.%hhu.%hhu\n",
// b[0], b[1], b[2], b[3]);
return ret;
}
extern const char* my_bind_addr_str;
extern uint mysqld_port;
size_t wsrep_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 (my_bind_addr_str && strlen(my_bind_addr_str))
{
unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str);
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;
if (INADDR_NONE == ip_type) {
WSREP_ERROR("Networking not configured, cannot receive state transfer.");
return 0;
}
if (INADDR_ANY != ip_type) {;
strncpy (buf, my_bind_addr_str, buf_len);
return strlen(buf);
}
}
// mysqld binds to all interfaces - try IP from wsrep_node_address
@ -400,9 +451,9 @@ size_t guess_ip (char* buf, size_t buf_len)
return ip_len;
}
size_t guess_address(char* buf, size_t buf_len)
size_t wsrep_guess_address(char* buf, size_t buf_len)
{
size_t addr_len = guess_ip (buf, buf_len);
size_t addr_len = wsrep_guess_ip (buf, buf_len);
if (addr_len && addr_len < buf_len) {
addr_len += snprintf (buf + addr_len, buf_len - addr_len,

208
sql/wsrep_utils.h Normal file
View File

@ -0,0 +1,208 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef WSREP_UTILS_H
#define WSREP_UTILS_H
#include "wsrep_priv.h"
unsigned int wsrep_check_ip (const char* addr);
size_t wsrep_guess_ip (char* buf, size_t buf_len);
size_t wsrep_guess_address(char* buf, size_t buf_len);
namespace wsp {
class node_status
{
public:
node_status() : status(WSREP_MEMBER_UNDEFINED) {}
void set(wsrep_member_status_t new_status,
const wsrep_view_info_t* view = 0)
{
if (status != new_status || 0 != view)
{
wsrep_notify_status(new_status, view);
status = new_status;
}
}
wsrep_member_status_t get() const { return status; }
private:
wsrep_member_status_t status;
};
} /* namespace wsp */
extern wsp::node_status local_status;
namespace wsp {
/* A small class to run external programs. */
class process
{
private:
const char* const str_;
FILE* io_;
int err_;
pid_t pid_;
public:
/*! @arg type is a pointer to a null-terminated string which must contain
either the letter 'r' for reading or the letter 'w' for writing.
*/
process (const char* cmd, const char* type);
~process ();
FILE* pipe () { return io_; }
int error() { return err_; }
int wait ();
const char* cmd() { return str_; }
};
class thd
{
class thd_init
{
public:
thd_init() { my_thread_init(); }
~thd_init() { my_thread_end(); }
}
init;
thd (const thd&);
thd& operator= (const thd&);
public:
thd(my_bool wsrep_on);
~thd();
THD* const ptr;
};
class string
{
public:
string() : string_(0) {}
void set(char* str) { if (string_) free (string_); string_ = str; }
~string() { set (0); }
private:
char* string_;
};
#ifdef REMOVED
class lock
{
pthread_mutex_t* const mtx_;
public:
lock (pthread_mutex_t* mtx) : mtx_(mtx)
{
int err = pthread_mutex_lock (mtx_);
if (err)
{
WSREP_ERROR("Mutex lock failed: %s", strerror(err));
abort();
}
}
virtual ~lock ()
{
int err = pthread_mutex_unlock (mtx_);
if (err)
{
WSREP_ERROR("Mutex unlock failed: %s", strerror(err));
abort();
}
}
inline void wait (pthread_cond_t* cond)
{
pthread_cond_wait (cond, mtx_);
}
private:
lock (const lock&);
lock& operator=(const lock&);
};
class monitor
{
int mutable refcnt;
pthread_mutex_t mutable mtx;
pthread_cond_t mutable cond;
public:
monitor() : refcnt(0)
{
pthread_mutex_init (&mtx, NULL);
pthread_cond_init (&cond, NULL);
}
~monitor()
{
pthread_mutex_destroy (&mtx);
pthread_cond_destroy (&cond);
}
void enter() const
{
lock l(&mtx);
while (refcnt)
{
l.wait(&cond);
}
refcnt++;
}
void leave() const
{
lock l(&mtx);
refcnt--;
if (refcnt == 0)
{
pthread_cond_signal (&cond);
}
}
private:
monitor (const monitor&);
monitor& operator= (const monitor&);
};
class critical
{
const monitor& mon;
public:
critical(const monitor& m) : mon(m) { mon.enter(); }
~critical() { mon.leave(); }
private:
critical (const critical&);
critical& operator= (const critical&);
};
#endif
} // namespace wsrep
#endif /* WSREP_UTILS_H */

View File

@ -13,12 +13,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "wsrep_var.h"
#include <mysqld.h>
#include <sql_class.h>
#include <sql_plugin.h>
#include <set_var.h>
#include <sql_acl.h>
#include "wsrep_priv.h"
#include "wsrep_thd.h"
#include <my_dir.h>
#include <cstdio>
#include <cstdlib>
@ -34,8 +37,7 @@ const char* wsrep_node_name = 0;
const char* wsrep_node_address = 0;
const char* wsrep_node_incoming_address = 0;
const char* wsrep_start_position = 0;
ulong wsrep_OSU_method_options;
static int wsrep_thread_change = 0;
ulong wsrep_OSU_method_options;
int wsrep_init_vars()
{
@ -58,15 +60,6 @@ bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type)
// FIXME: this variable probably should be changed only per session
thd->variables.wsrep_on = global_system_variables.wsrep_on;
}
else {
}
#ifdef REMOVED
if (thd->variables.wsrep_on)
thd->variables.option_bits |= (OPTION_BIN_LOG);
else
thd->variables.option_bits &= ~(OPTION_BIN_LOG);
#endif
return false;
}
@ -75,8 +68,6 @@ void wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type)
if (var_type == OPT_GLOBAL) {
thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads;
}
else {
}
}
static int wsrep_start_position_verify (const char* start_str)
@ -146,7 +137,7 @@ bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type)
wsrep_set_local_position (wsrep_start_position);
if (wsrep) {
wsrep->sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
}
return 0;
@ -157,7 +148,7 @@ void wsrep_start_position_init (const char* val)
if (NULL == val || wsrep_start_position_verify (val))
{
WSREP_ERROR("Bad initial value for wsrep_start_position: %s",
(val ? val : ""));
(val ? val : ""));
return;
}
@ -173,7 +164,7 @@ static bool refresh_provider_options()
{
if (wsrep_provider_options) my_free((void *)wsrep_provider_options);
wsrep_provider_options = (char*)my_memdup(opts, strlen(opts) + 1,
MYF(MY_WME));
MYF(MY_WME));
}
else
{
@ -453,7 +444,7 @@ void wsrep_node_address_init (const char* value)
bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var)
{
mysql_mutex_lock(&LOCK_wsrep_slave_threads);
wsrep_thread_change = var->value->val_int() - wsrep_slave_threads;
wsrep_slave_count_change = var->value->val_int() - wsrep_slave_threads;
mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
return 0;
@ -461,13 +452,10 @@ bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var)
bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
{
if (wsrep_thread_change > 0)
if (wsrep_slave_count_change > 0)
{
wsrep_create_appliers(wsrep_thread_change);
}
else if (wsrep_thread_change < 0)
{
wsrep_close_applier_threads(-wsrep_thread_change);
wsrep_create_appliers(wsrep_slave_count_change);
wsrep_slave_count_change = 0;
}
return false;
}

83
sql/wsrep_var.h Normal file
View File

@ -0,0 +1,83 @@
/* Copyright (C) 2013 Codership Oy <info@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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef WSREP_VAR_H
#define WSREP_VAR_H
#define WSREP_NODE_INCOMING_AUTO "AUTO"
// MySQL variables funcs
#include "sql_priv.h"
class sys_var;
class set_var;
class THD;
int wsrep_init_vars();
#define CHECK_ARGS (sys_var *self, THD* thd, set_var *var)
#define UPDATE_ARGS (sys_var *self, THD* thd, enum_var_type type)
#define DEFAULT_ARGS (THD* thd, enum_var_type var_type)
#define INIT_ARGS (const char* opt)
extern bool wsrep_on_update UPDATE_ARGS;
extern void wsrep_causal_reads_update UPDATE_ARGS;
extern bool wsrep_start_position_check CHECK_ARGS;
extern bool wsrep_start_position_update UPDATE_ARGS;
extern void wsrep_start_position_init INIT_ARGS;
extern bool wsrep_provider_check CHECK_ARGS;
extern bool wsrep_provider_update UPDATE_ARGS;
extern void wsrep_provider_init INIT_ARGS;
extern bool wsrep_provider_options_check CHECK_ARGS;
extern bool wsrep_provider_options_update UPDATE_ARGS;
extern void wsrep_provider_options_init INIT_ARGS;
extern bool wsrep_cluster_address_check CHECK_ARGS;
extern bool wsrep_cluster_address_update UPDATE_ARGS;
extern void wsrep_cluster_address_init INIT_ARGS;
extern bool wsrep_cluster_name_check CHECK_ARGS;
extern bool wsrep_cluster_name_update UPDATE_ARGS;
extern bool wsrep_node_name_check CHECK_ARGS;
extern bool wsrep_node_name_update UPDATE_ARGS;
extern bool wsrep_node_address_check CHECK_ARGS;
extern bool wsrep_node_address_update UPDATE_ARGS;
extern void wsrep_node_address_init INIT_ARGS;
extern bool wsrep_sst_method_check CHECK_ARGS;
extern bool wsrep_sst_method_update UPDATE_ARGS;
extern void wsrep_sst_method_init INIT_ARGS;
extern bool wsrep_sst_receive_address_check CHECK_ARGS;
extern bool wsrep_sst_receive_address_update UPDATE_ARGS;
extern bool wsrep_sst_auth_check CHECK_ARGS;
extern bool wsrep_sst_auth_update UPDATE_ARGS;
extern void wsrep_sst_auth_init INIT_ARGS;
extern bool wsrep_sst_donor_check CHECK_ARGS;
extern bool wsrep_sst_donor_update UPDATE_ARGS;
extern bool wsrep_slave_threads_check CHECK_ARGS;
extern bool wsrep_slave_threads_update UPDATE_ARGS;
extern bool wsrep_desync_check CHECK_ARGS;
extern bool wsrep_desync_update UPDATE_ARGS;
#endif /* WSREP_VAR_H */

View File

@ -120,9 +120,9 @@ extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback;
extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback;
extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd;
static inline wsrep_trx_handle_t*
wsrep_trx_handle(THD* thd, const trx_t* trx) {
return wsrep_trx_handle_for_id(wsrep_thd_trx_handle(thd),
static inline wsrep_ws_handle_t*
wsrep_ws_handle(THD* thd, const trx_t* trx) {
return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd),
(wsrep_trx_id_t)trx->id);
}
@ -130,7 +130,7 @@ extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key,
size_t cache_key_len,
const uchar* row_id,
size_t row_id_len,
wsrep_key_part_t* key,
wsrep_buf_t* key,
size_t* key_len);
extern handlerton * wsrep_hton;
@ -7182,6 +7182,7 @@ wsrep_append_foreign_key(
ulint rcode = DB_SUCCESS;
char cache_key[513] = {'\0'};
int cache_key_len;
bool const copy = true;
if (!wsrep_on(trx->mysql_thd) ||
wsrep_thd_exec_mode(thd) != LOCAL_STATE)
@ -7308,30 +7309,31 @@ wsrep_append_foreign_key(
foreign->foreign_table->name);
}
wsrep_key_part_t wkey_part[3];
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
if (!wsrep_prepare_key_for_innodb(
(const uchar*)cache_key,
cache_key_len + 1,
(const uchar*)key, len+1,
wkey_part,
&wkey.key_parts_len)) {
WSREP_WARN("key prepare failed for cascaded FK: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
&wkey.key_parts_num)) {
WSREP_WARN("key prepare failed for cascaded FK: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
return DB_ERROR;
}
rcode = (int)wsrep->append_key(
wsrep,
wsrep_trx_handle(thd, trx),
wsrep_ws_handle(thd, trx),
&wkey,
1,
shared);
1,
shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
copy);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: %lu", rcode));
WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
return DB_ERROR;
}
@ -7352,6 +7354,7 @@ wsrep_append_key(
)
{
DBUG_ENTER("wsrep_append_key");
bool const copy = true;
#ifdef WSREP_DEBUG_PRINT
fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ",
(shared) ? "Shared" : "Exclusive",
@ -7362,52 +7365,37 @@ wsrep_append_key(
}
fprintf(stderr, "\n");
#endif
wsrep_key_part_t wkey_part[3];
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
if (!wsrep_prepare_key_for_innodb(
(const uchar*)table_share->table_cache_key.str,
table_share->table_cache_key.length,
(const uchar*)key, key_len,
wkey_part,
&wkey.key_parts_len)) {
WSREP_WARN("key prepare failed for: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
&wkey.key_parts_num)) {
WSREP_WARN("key prepare failed for: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
}
int rcode = (int)wsrep->append_key(
wsrep,
wsrep_trx_handle(thd, trx),
wsrep_ws_handle(thd, trx),
&wkey,
1,
shared);
shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
copy);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
WSREP_WARN("Appending row key failed: %s, %d",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
WSREP_WARN("Appending row key failed: %s, %d",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
DBUG_RETURN(rcode);
}
DBUG_RETURN(0);
}
ibool
wsrep_is_cascding_foreign_key_parent(
dict_table_t* table, /*!< in: InnoDB table */
dict_index_t* index /*!< in: InnoDB index */
) {
// return referenced_by_foreign_key();
dict_foreign_t* fk = dict_table_get_referenced_constraint(table, index);
if (fk &&
(fk->type & DICT_FOREIGN_ON_UPDATE_CASCADE ||
fk->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
) {
return TRUE;
}
return FALSE;
}
int
ha_innobase::wsrep_append_keys(
/*==================*/
@ -7455,19 +7443,30 @@ ha_innobase::wsrep_append_keys(
ut_a(table->s->keys <= 256);
uint i;
for (i=0; i<table->s->keys; ++i) {
uint len;
char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char *key0 = &keyval0[1];
char *key1 = &keyval1[1];
KEY *key_info = table->key_info + i;
ibool is_null;
uint len;
char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char* key0 = &keyval0[1];
char* key1 = &keyval1[1];
KEY* key_info = table->key_info + i;
ibool is_null;
dict_index_t* idx = innobase_get_index(i);
dict_table_t* tab = (idx) ? idx->table : NULL;
keyval0[0] = (char)i;
keyval1[0] = (char)i;
if (!tab) {
WSREP_WARN("MySQL-InnoDB key mismatch %s %s",
table->s->table_name.str,
key_info->name);
}
if (key_info->flags & HA_NOSAME ||
referenced_by_foreign_key()) {
((tab &&
dict_table_get_referenced_constraint(tab, idx)) ||
(!tab && referenced_by_foreign_key()))) {
if (key_info->flags & HA_NOSAME || shared)
key_appended = true;
@ -12822,7 +12821,7 @@ wsrep_fake_trx_id(
trx_id_t trx_id = trx_sys_get_new_trx_id();
mutex_exit(&kernel_mutex);
(void *)wsrep_trx_handle_for_id(wsrep_thd_trx_handle(thd), trx_id);
(void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
}
#endif /* WITH_WSREP */

View File

@ -308,7 +308,7 @@ extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd);
extern "C" const char * wsrep_thd_exec_mode_str(THD *thd);
extern "C" const char * wsrep_thd_conflict_state_str(THD *thd);
extern "C" const char * wsrep_thd_query_state_str(THD *thd);
extern "C" wsrep_trx_handle_t* wsrep_thd_trx_handle(THD *thd);
extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd);
extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
extern "C" void wsrep_thd_set_query_state(

View File

@ -1742,7 +1742,7 @@ lock_t*
lock_rec_create(
/*============*/
#ifdef WITH_WSREP
lock_t* c_lock, /* conflicting lock */
lock_t* c_lock, /* conflicting lock */
#endif
ulint type_mode,/*!< in: lock mode and wait
flag, type is ignored and
@ -1810,7 +1810,7 @@ lock_rec_create(
#ifdef WITH_WSREP
if (c_lock && wsrep_thd_is_brute_force(trx->mysql_thd)) {
lock_t *hash = c_lock->hash;
lock_t *hash = c_lock->hash;
lock_t *prev = NULL;
while (hash &&
@ -1829,7 +1829,7 @@ lock_rec_create(
* delayed conflict resolution '...kill_one_trx' was not called,
* if victim was waiting for some other lock
*/
if (c_lock && c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
if (c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
c_lock->trx->was_chosen_as_deadlock_victim = TRUE;
if (wsrep_debug && c_lock->trx->wait_lock != c_lock) {
@ -1851,8 +1851,8 @@ lock_rec_create(
}
if (wsrep_debug) fprintf(
stderr,
"WSREP: c_lock canceled %llu\n",
stderr,
"WSREP: c_lock canceled %llu\n",
(ulonglong) c_lock->trx->id);
/* have to bail out here to avoid lock_set_lock... */
@ -1865,7 +1865,7 @@ lock_rec_create(
#else
HASH_INSERT(lock_t, hash, lock_sys->rec_hash,
lock_rec_fold(space, page_no), lock);
#endif
#endif /* WITH_WSREP */
if (lock_is_wait_not_by_other(type_mode)) {
lock_set_lock_and_trx_wait(lock, trx);
@ -1886,7 +1886,7 @@ enum db_err
lock_rec_enqueue_waiting(
/*=====================*/
#ifdef WITH_WSREP
lock_t* c_lock, /* conflicting lock */
lock_t* c_lock, /* conflicting lock */
#endif
ulint type_mode,/*!< in: lock mode this
transaction is requesting:
@ -2231,7 +2231,7 @@ lock_rec_lock_slow(
{
trx_t* trx;
#ifdef WITH_WSREP
lock_t *c_lock= 0;
lock_t* c_lock = NULL;
#endif
lock_t* lock;
@ -2281,10 +2281,10 @@ lock_rec_lock_slow(
#ifdef WITH_WSREP
} else if ((c_lock = lock_rec_other_has_conflicting(
mode, block, heap_no, trx))) {
mode, block, heap_no, trx))) {
#else
} else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) {
#endif
#endif /* WITH_WSREP */
/* If another transaction has a non-gap conflicting request in
the queue, as this transaction does not have a lock strong
@ -2293,12 +2293,15 @@ lock_rec_lock_slow(
ut_ad(lock == NULL);
enqueue_waiting:
#ifdef WITH_WSREP
return(lock_rec_enqueue_waiting(c_lock,mode, block, heap_no,
/* c_lock is NULL here if jump to enqueue_waiting happened
but it's ok because lock is not NULL in that case and c_lock
is not used. */
return(lock_rec_enqueue_waiting(c_lock, mode, block, heap_no,
lock, index, thr));
#else
return(lock_rec_enqueue_waiting(mode, block, heap_no,
lock, index, thr));
#endif
#endif /* WITH_WSREP */
} else if (!impl) {
/* Set the requested lock on the record */
@ -3961,7 +3964,8 @@ lock_table_create(
if (c_lock && c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
if (wsrep_debug) {
fprintf(stderr, "WSREP: table c_lock in wait: %llu new loc: %llu\n",
fprintf(stderr,
"WSREP: table c_lock in wait: %llu new loc: %llu\n",
(ulonglong) c_lock->trx->id, lock->trx->id);
}
@ -5603,7 +5607,7 @@ lock_rec_insert_check_and_lock(
| LOCK_INSERT_INTENTION,
block, next_rec_heap_no,
NULL, index, thr);
#endif
#endif /* WITH_WSREP */
} else {
err = DB_SUCCESS;
}

View File

@ -137,9 +137,9 @@ extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_wsrep_rollback;
extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_wsrep_rollback;
extern MYSQL_PLUGIN_IMPORT wsrep_aborting_thd_t wsrep_aborting_thd;
static inline wsrep_trx_handle_t*
wsrep_trx_handle(THD* thd, const trx_t* trx) {
return wsrep_trx_handle_for_id(wsrep_thd_trx_handle(thd),
static inline wsrep_ws_handle_t*
wsrep_ws_handle(THD* thd, const trx_t* trx) {
return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd),
(wsrep_trx_id_t)trx->id);
}
@ -147,7 +147,7 @@ extern bool wsrep_prepare_key_for_innodb(const uchar *cache_key,
size_t cache_key_len,
const uchar* row_id,
size_t row_id_len,
wsrep_key_part_t* key,
wsrep_buf_t* key,
size_t* key_len);
extern handlerton * wsrep_hton;
@ -1187,6 +1187,8 @@ innobase_release_temporary_latches(
static int
wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
my_bool signal);
static void
wsrep_fake_trx_id(handlerton* hton, THD *thd);
static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
#endif
@ -2729,6 +2731,7 @@ innobase_init(
innobase_hton->wsrep_abort_transaction=wsrep_abort_transaction;
innobase_hton->wsrep_set_checkpoint=innobase_wsrep_set_checkpoint;
innobase_hton->wsrep_get_checkpoint=innobase_wsrep_get_checkpoint;
innobase_hton->wsrep_fake_trx_id=wsrep_fake_trx_id;
#endif /* WITH_WSREP */
innobase_hton->kill_query = innobase_kill_query;
@ -8222,6 +8225,7 @@ wsrep_append_foreign_key(
ulint rcode = DB_SUCCESS;
char cache_key[513] = {'\0'};
int cache_key_len;
bool const copy = true;
if (!wsrep_on(trx->mysql_thd) ||
wsrep_thd_exec_mode(thd) != LOCAL_STATE)
@ -8348,30 +8352,31 @@ wsrep_append_foreign_key(
foreign->foreign_table->name);
}
wsrep_key_part_t wkey_part[3];
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
if (!wsrep_prepare_key_for_innodb(
(const uchar*)cache_key,
cache_key_len + 1,
(const uchar*)key, len+1,
wkey_part,
&wkey.key_parts_len)) {
WSREP_WARN("key prepare failed for cascaded FK: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
&wkey.key_parts_num)) {
WSREP_WARN("key prepare failed for cascaded FK: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
return DB_ERROR;
}
rcode = (int)wsrep->append_key(
wsrep,
wsrep_trx_handle(thd, trx),
wsrep_ws_handle(thd, trx),
&wkey,
1,
shared);
1,
shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
copy);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: %lu", rcode));
WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
return DB_ERROR;
}
@ -8392,6 +8397,7 @@ wsrep_append_key(
)
{
DBUG_ENTER("wsrep_append_key");
bool const copy = true;
#ifdef WSREP_DEBUG_PRINT
fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ",
(shared) ? "Shared" : "Exclusive",
@ -8402,52 +8408,37 @@ wsrep_append_key(
}
fprintf(stderr, "\n");
#endif
wsrep_key_part_t wkey_part[3];
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
if (!wsrep_prepare_key_for_innodb(
(const uchar*)table_share->table_cache_key.str,
table_share->table_cache_key.length,
(const uchar*)key, key_len,
wkey_part,
&wkey.key_parts_len)) {
WSREP_WARN("key prepare failed for: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
&wkey.key_parts_num)) {
WSREP_WARN("key prepare failed for: %s",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void");
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
}
int rcode = (int)wsrep->append_key(
wsrep,
wsrep_trx_handle(thd, trx),
wsrep_ws_handle(thd, trx),
&wkey,
1,
shared);
shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
copy);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
WSREP_WARN("Appending row key failed: %s, %d",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
WSREP_WARN("Appending row key failed: %s, %d",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
DBUG_RETURN(rcode);
}
DBUG_RETURN(0);
}
ibool
wsrep_is_cascding_foreign_key_parent(
dict_table_t* table, /*!< in: InnoDB table */
dict_index_t* index /*!< in: InnoDB index */
) {
// return referenced_by_foreign_key();
dict_foreign_t* fk = dict_table_get_referenced_constraint(table, index);
if (fk &&
(fk->type & DICT_FOREIGN_ON_UPDATE_CASCADE ||
fk->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
) {
return TRUE;
}
return FALSE;
}
int
ha_innobase::wsrep_append_keys(
/*==================*/
@ -8495,19 +8486,30 @@ ha_innobase::wsrep_append_keys(
ut_a(table->s->keys <= 256);
uint i;
for (i=0; i<table->s->keys; ++i) {
uint len;
char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char *key0 = &keyval0[1];
char *key1 = &keyval1[1];
KEY *key_info = table->key_info + i;
ibool is_null;
uint len;
char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
char* key0 = &keyval0[1];
char* key1 = &keyval1[1];
KEY* key_info = table->key_info + i;
ibool is_null;
dict_index_t* idx = innobase_get_index(i);
dict_table_t* tab = (idx) ? idx->table : NULL;
keyval0[0] = (char)i;
keyval1[0] = (char)i;
if (!tab) {
WSREP_WARN("MySQL-InnoDB key mismatch %s %s",
table->s->table_name.str,
key_info->name);
}
if (key_info->flags & HA_NOSAME ||
referenced_by_foreign_key()) {
((tab &&
dict_table_get_referenced_constraint(tab, idx)) ||
(!tab && referenced_by_foreign_key()))) {
if (key_info->flags & HA_NOSAME || shared)
key_appended = true;
@ -13877,25 +13879,35 @@ wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno)
This function is used to kill one transaction in BF. */
int
wsrep_innobase_kill_one_trx(
void *bf_thd_ptr, /*!< in: BF thd */
trx_t *bf_trx, /*!< in: BF trx */
trx_t *victim_trx, /*!< in: victim trx */
ibool signal, /*!< in: signal to be used */
ibool have_kernel_mutex) /*!<in: do we own kernel mutex */
{
DBUG_ENTER("wsrep_innobase_kill_one_trx");
THD *bf_thd = (THD *)bf_thd_ptr;
THD *thd = (THD *) victim_trx->mysql_thd;
THD *bf_thd = (bf_trx) ? (THD *)bf_trx->mysql_thd : NULL;
int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0;
if (have_kernel_mutex) {
ut_ad(mutex_own(&kernel_mutex));
}
if (!bf_thd) bf_thd = (bf_trx) ? (THD *)bf_trx->mysql_thd : NULL;
if (!thd) {
DBUG_PRINT("wsrep", ("no thd for conflicting lock"));
WSREP_WARN("no THD for trx: %llu", victim_trx->id);
DBUG_RETURN(1);
}
if (!bf_thd) {
DBUG_PRINT("wsrep", ("no BF thd for conflicting lock"));
WSREP_WARN("no BF THD for trx: %llu", (bf_trx) ? bf_trx->id : 0);
DBUG_RETURN(1);
}
WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %llu",
signal, (long long)bf_seqno,
@ -14098,8 +14110,8 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
if (victim_trx)
{
int rcode = wsrep_innobase_kill_one_trx(bf_trx, victim_trx,
signal, FALSE);
int rcode = wsrep_innobase_kill_one_trx(
bf_thd, bf_trx, victim_trx, signal, FALSE);
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
@ -14134,6 +14146,19 @@ static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid)
return 0;
}
static void
wsrep_fake_trx_id(
/*==================*/
handlerton *hton,
THD *thd) /*!< in: user thread handle */
{
mutex_enter(&kernel_mutex);
trx_id_t trx_id = trx_sys_get_new_trx_id();
mutex_exit(&kernel_mutex);
(void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
}
#endif /* WITH_WSREP */
/* plugin options */
static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums,

View File

@ -385,7 +385,10 @@ extern "C" bool wsrep_thd_is_wsrep_on(THD *thd);
extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd);
extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd);
extern "C" wsrep_trx_handle_t* wsrep_thd_trx_handle(THD *thd);
extern "C" const char * wsrep_thd_exec_mode_str(THD *thd);
extern "C" const char * wsrep_thd_conflict_state_str(THD *thd);
extern "C" const char * wsrep_thd_query_state_str(THD *thd);
extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd);
extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode);
extern "C" void wsrep_thd_set_query_state(

View File

@ -301,7 +301,7 @@ thd_flush_log_at_trx_commit(
void* thd);
#ifdef WITH_WSREP
UNIV_INTERN int wsrep_innobase_kill_one_trx(trx_t *bf_trx, trx_t *victim_trx,
UNIV_INTERN int wsrep_innobase_kill_one_trx(void *thd, trx_t *bf_trx, trx_t *victim_trx,
ibool signal, ibool have_kernel_mutex);
int wsrep_thd_is_brute_force(void *thd_ptr);
int wsrep_trx_order_before(void *thd1, void *thd2);

View File

@ -42,6 +42,7 @@ Created 5/7/1996 Heikki Tuuri
#ifdef WITH_WSREP
extern my_bool wsrep_debug;
extern my_bool wsrep_log_conflicts;
#endif
/* Restricts the length of search we will do in the waits-for
graph of transactions */
@ -1533,7 +1534,34 @@ wsrep_kill_victim(trx_t *trx, lock_t *lock) {
/* cannot release lock, until our lock
is in the queue*/
} else if (lock->trx != trx) {
wsrep_innobase_kill_one_trx(trx, lock->trx, TRUE, TRUE);
if (wsrep_log_conflicts) {
if (bf_this)
fputs("\n*** Priority TRANSACTION:\n",
stderr);
else
fputs("\n*** Victim TRANSACTION:\n",
stderr);
trx_print(stderr, trx, 3000);
if (bf_other)
fputs("\n*** Priority TRANSACTION:\n",
stderr);
else
fputs("\n*** Victim TRANSACTION:\n",
stderr);
trx_print(stderr, lock->trx, 3000);
fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n",
stderr);
if (lock_get_type(lock) == LOCK_REC) {
lock_rec_print(stderr, lock);
} else {
lock_table_print(stderr, lock);
}
}
wsrep_innobase_kill_one_trx(
trx->mysql_thd, trx, lock->trx, TRUE, TRUE);
}
}
}
@ -1715,7 +1743,7 @@ lock_t*
lock_rec_create(
/*============*/
#ifdef WITH_WSREP
lock_t* c_lock, /* conflicting lock */
lock_t* c_lock, /* conflicting lock */
#endif
ulint type_mode,/*!< in: lock mode and wait
flag, type is ignored and
@ -1783,7 +1811,7 @@ lock_rec_create(
#ifdef WITH_WSREP
if (c_lock && wsrep_thd_is_brute_force(trx->mysql_thd)) {
lock_t *hash = c_lock->hash;
lock_t *hash = c_lock->hash;
lock_t *prev = NULL;
while (hash &&
@ -1802,7 +1830,7 @@ lock_rec_create(
* delayed conflict resolution '...kill_one_trx' was not called,
* if victim was waiting for some other lock
*/
if (c_lock && c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
if (c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
c_lock->trx->was_chosen_as_deadlock_victim = TRUE;
if (wsrep_debug && c_lock->trx->wait_lock != c_lock) {
@ -1824,8 +1852,8 @@ lock_rec_create(
}
if (wsrep_debug) fprintf(
stderr,
"WSREP: c_lock canceled %llu\n",
stderr,
"WSREP: c_lock canceled %llu\n",
(ulonglong) c_lock->trx->id);
/* have to bail out here to avoid lock_set_lock... */
@ -1838,8 +1866,7 @@ lock_rec_create(
#else
HASH_INSERT(lock_t, hash, lock_sys->rec_hash,
lock_rec_fold(space, page_no), lock);
#endif
#endif /* WITH_WSREP */
lock_sys->rec_num++;
if (lock_is_wait_not_by_other(type_mode)) {
lock_set_lock_and_trx_wait(lock, trx);
@ -1860,7 +1887,7 @@ enum db_err
lock_rec_enqueue_waiting(
/*=====================*/
#ifdef WITH_WSREP
lock_t* c_lock, /* conflicting lock */
lock_t* c_lock, /* conflicting lock */
#endif
ulint type_mode,/*!< in: lock mode this
transaction is requesting:
@ -2211,7 +2238,7 @@ lock_rec_lock_slow(
{
trx_t* trx;
#ifdef WITH_WSREP
lock_t *c_lock= 0;
lock_t* c_lock = NULL;
#endif
lock_t* lock;
@ -2261,10 +2288,10 @@ lock_rec_lock_slow(
#ifdef WITH_WSREP
} else if ((c_lock = lock_rec_other_has_conflicting(
mode, block, heap_no, trx))) {
mode, block, heap_no, trx))) {
#else
} else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) {
#endif
#endif /* WITH_WSREP */
/* If another transaction has a non-gap conflicting request in
the queue, as this transaction does not have a lock strong
@ -2273,12 +2300,15 @@ lock_rec_lock_slow(
ut_ad(lock == NULL);
enqueue_waiting:
#ifdef WITH_WSREP
return(lock_rec_enqueue_waiting(c_lock,mode, block, heap_no,
/* c_lock is NULL here if jump to enqueue_waiting happened
but it's ok because lock is not NULL in that case and c_lock
is not used. */
return(lock_rec_enqueue_waiting(c_lock, mode, block, heap_no,
lock, index, thr));
#else
return(lock_rec_enqueue_waiting(mode, block, heap_no,
lock, index, thr));
#endif
#endif /* WITH_WSREP */
} else if (!impl) {
/* Set the requested lock on the record */
@ -3944,7 +3974,8 @@ lock_table_create(
if (c_lock && c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
if (wsrep_debug) {
fprintf(stderr, "WSREP: table c_lock in wait: %llu new loc: %llu\n",
fprintf(stderr,
"WSREP: table c_lock in wait: %llu new loc: %llu\n",
(ulonglong) c_lock->trx->id, lock->trx->id);
}
@ -4227,33 +4258,12 @@ lock_table_other_has_incompatible(
if ((lock->trx != trx)
&& (!lock_mode_compatible(lock_get_mode(lock), mode))
&& (wait || !(lock_get_wait(lock)))) {
#ifdef WITH_WSREP
int bf_this = wsrep_thd_is_brute_force(trx->mysql_thd);
int bf_other = wsrep_thd_is_brute_force(
lock->trx->mysql_thd);
if ((bf_this && !bf_other) ||
(bf_this && bf_other &&
wsrep_trx_order_before(
trx->mysql_thd, lock->trx->mysql_thd)
)
) {
if (lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
if (wsrep_debug) fprintf(stderr,
"WSREP: BF victim waiting");
return(lock);
} else {
if (bf_this && bf_other)
wsrep_innobase_kill_one_trx(
(trx_t *)trx, lock->trx, TRUE, TRUE);
return(lock);
}
} else {
return(lock);
}
#else
return(lock);
if (wsrep_debug)
fprintf(stderr, "WSREP: table lock abort");
wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
#endif
return(lock);
}
lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);

View File

@ -397,33 +397,6 @@ case "$mode" in
fi
fi
;;
'configtest')
# Safeguard (relative paths, core dumps..)
cd $basedir
echo $echo_n "Testing MySQL configuration syntax"
daemon=$bindir/mysqld
if test -x $libexecdir/mysqld
then
daemon=$libexecdir/mysqld
elif test -x $sbindir/mysqld
then
daemon=$sbindir/mysqld
elif test -x `which mysqld`
then
daemon=`which mysqld`
else
log_failure_msg "Unable to locate the mysqld binary!"
exit 1
fi
help_out=`$daemon --help 2>&1`; r=$?
if test "$r" != 0 ; then
log_failure_msg "$help_out"
log_failure_msg "There are syntax errors in the server configuration. Please fix them!"
else
log_success_msg "Syntax OK"
fi
exit $r
;;
'bootstrap')
# Bootstrap the cluster, start the first node
# that initiate the cluster
@ -433,7 +406,7 @@ case "$mode" in
*)
# usage
basename=`basename "$0"`
echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest|bootstrap} [ MySQL server options ]"
echo "Usage: $basename {start|stop|restart|reload|force-reload|status|bootstrap} [ MySQL server options ]"
exit 1
;;
esac

View File

@ -1,2 +1,7 @@
noinst_LIBRARIES = libwsrep.a
libwsrep_a_SOURCES = wsrep_api.h wsrep_loader.c wsrep_dummy.c wsrep_uuid.c
libwsrep_a_SOURCES = wsrep_api.h wsrep_loader.c wsrep_dummy.c wsrep_uuid.c wsrep_gtid.c
noinst_PROGRAMS = wsrep_listener
wsrep_listener_SOURCES = wsrep_listener.c
wsrep_listener_LDADD = $(noinst_LIBRARIES)
wsrep_listener_LDFLAGS = -static -ldl

File diff suppressed because it is too large Load Diff

View File

@ -16,10 +16,11 @@
/*! @file Dummy wsrep API implementation. */
#include <errno.h>
#include "wsrep_api.h"
#include <errno.h>
#include <stdbool.h>
/*! Dummy backend context. */
typedef struct wsrep_dummy
{
@ -74,9 +75,10 @@ static char* dummy_options_get (wsrep_t* w)
static wsrep_status_t dummy_connect(
wsrep_t* w,
const char* name __attribute__((unused)),
const char* url __attribute__((unused)),
const char* donor __attribute__((unused)))
const char* name __attribute__((unused)),
const char* url __attribute__((unused)),
const char* donor __attribute__((unused)),
wsrep_bool_t bootstrap __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -97,12 +99,10 @@ static wsrep_status_t dummy_recv(wsrep_t* w,
static wsrep_status_t dummy_pre_commit(
wsrep_t* w,
const wsrep_conn_id_t conn_id __attribute__((unused)),
wsrep_trx_handle_t* trx_handle __attribute__((unused)),
const void* query __attribute__((unused)),
const size_t query_len __attribute__((unused)),
uint64_t flags __attribute__((unused)),
wsrep_seqno_t* seqno __attribute__((unused)))
const wsrep_conn_id_t conn_id __attribute__((unused)),
wsrep_ws_handle_t* ws_handle __attribute__((unused)),
uint32_t flags __attribute__((unused)),
wsrep_trx_meta_t* meta __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -110,7 +110,7 @@ static wsrep_status_t dummy_pre_commit(
static wsrep_status_t dummy_post_commit(
wsrep_t* w,
wsrep_trx_handle_t* trx_handle __attribute__((unused)))
wsrep_ws_handle_t* ws_handle __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -118,7 +118,7 @@ static wsrep_status_t dummy_post_commit(
static wsrep_status_t dummy_post_rollback(
wsrep_t* w,
wsrep_trx_handle_t* trx_handle __attribute__((unused)))
wsrep_ws_handle_t* ws_handle __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -126,7 +126,7 @@ static wsrep_status_t dummy_post_rollback(
static wsrep_status_t dummy_replay_trx(
wsrep_t* w,
wsrep_trx_handle_t* trx_handle __attribute__((unused)),
wsrep_ws_handle_t* ws_handle __attribute__((unused)),
void* trx_ctx __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
@ -142,23 +142,13 @@ static wsrep_status_t dummy_abort_pre_commit(
return WSREP_OK;
}
static wsrep_status_t dummy_append_query(
static wsrep_status_t dummy_append_key(
wsrep_t* w,
wsrep_trx_handle_t* trx_handle __attribute__((unused)),
const char* query __attribute__((unused)),
const time_t timeval __attribute__((unused)),
const uint32_t randseed __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
}
static wsrep_status_t dummy_append_row_key(
wsrep_t* w,
wsrep_trx_handle_t* trx_handle __attribute__((unused)),
const wsrep_key_t* key __attribute__((unused)),
const size_t key_len __attribute__((unused)),
const bool shared __attribute__((unused)))
wsrep_ws_handle_t* ws_handle __attribute__((unused)),
const wsrep_key_t* key __attribute__((unused)),
const size_t key_num __attribute__((unused)),
const wsrep_key_type_t key_type __attribute__((unused)),
const bool copy __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -166,9 +156,11 @@ static wsrep_status_t dummy_append_row_key(
static wsrep_status_t dummy_append_data(
wsrep_t* w,
wsrep_trx_handle_t* trx_handle __attribute__((unused)),
const void* data __attribute__((unused)),
size_t data_len __attribute__((unused)))
wsrep_ws_handle_t* ws_handle __attribute__((unused)),
const struct wsrep_buf* data __attribute__((unused)),
const size_t count __attribute__((unused)),
const wsrep_data_type_t type __attribute__((unused)),
const bool copy __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -176,7 +168,7 @@ static wsrep_status_t dummy_append_data(
static wsrep_status_t dummy_causal_read(
wsrep_t* w,
wsrep_seqno_t* seqno __attribute__((unused)))
wsrep_gtid_t* gtid __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -192,12 +184,12 @@ static wsrep_status_t dummy_free_connection(
static wsrep_status_t dummy_to_execute_start(
wsrep_t* w,
const wsrep_conn_id_t conn_id __attribute__((unused)),
const wsrep_key_t* key __attribute__((unused)),
const size_t key_len __attribute__((unused)),
const void* query __attribute__((unused)),
const size_t query_len __attribute__((unused)),
wsrep_seqno_t* seqno __attribute__((unused)))
const wsrep_conn_id_t conn_id __attribute__((unused)),
const wsrep_key_t* key __attribute__((unused)),
const size_t key_num __attribute__((unused)),
const struct wsrep_buf* data __attribute__((unused)),
const size_t count __attribute__((unused)),
wsrep_trx_meta_t* meta __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -211,10 +203,33 @@ static wsrep_status_t dummy_to_execute_end(
return WSREP_OK;
}
static wsrep_status_t dummy_preordered_collect(
wsrep_t* w,
wsrep_po_handle_t* handle __attribute__((unused)),
const struct wsrep_buf* data __attribute__((unused)),
size_t count __attribute__((unused)),
wsrep_bool_t copy __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
}
static wsrep_status_t dummy_preordered_commit(
wsrep_t* w,
wsrep_po_handle_t* handle __attribute__((unused)),
const wsrep_uuid_t* source_id __attribute__((unused)),
uint32_t flags __attribute__((unused)),
int pa_range __attribute__((unused)),
wsrep_bool_t commit __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
}
static wsrep_status_t dummy_sst_sent(
wsrep_t* w,
const wsrep_uuid_t* uuid __attribute__((unused)),
wsrep_seqno_t seqno __attribute__((unused)))
const wsrep_gtid_t* state_id __attribute__((unused)),
const int rcode __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -222,10 +237,10 @@ static wsrep_status_t dummy_sst_sent(
static wsrep_status_t dummy_sst_received(
wsrep_t* w,
const wsrep_uuid_t* uuid __attribute__((unused)),
const wsrep_seqno_t seqno __attribute__((unused)),
const char* state __attribute__((unused)),
const size_t state_len __attribute__((unused)))
const wsrep_gtid_t* state_id __attribute__((unused)),
const void* state __attribute__((unused)),
const size_t state_len __attribute__((unused)),
const int rcode __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -258,6 +273,11 @@ static void dummy_stats_free (
WSREP_DBUG_ENTER(w);
}
static void dummy_stats_reset (wsrep_t* w)
{
WSREP_DBUG_ENTER(w);
}
static wsrep_seqno_t dummy_pause (wsrep_t* w)
{
WSREP_DBUG_ENTER(w);
@ -284,7 +304,8 @@ static wsrep_status_t dummy_resync (wsrep_t* w)
static wsrep_status_t dummy_lock (wsrep_t* w,
const char* s __attribute__((unused)),
int64_t o __attribute__((unused)),
bool r __attribute__((unused)),
uint64_t o __attribute__((unused)),
int64_t t __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
@ -293,7 +314,7 @@ static wsrep_status_t dummy_lock (wsrep_t* w,
static wsrep_status_t dummy_unlock (wsrep_t* w,
const char* s __attribute__((unused)),
int64_t o __attribute__((unused)))
uint64_t o __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
return WSREP_OK;
@ -301,7 +322,7 @@ static wsrep_status_t dummy_unlock (wsrep_t* w,
static bool dummy_is_locked (wsrep_t* w,
const char* s __attribute__((unused)),
int64_t* o __attribute__((unused)),
uint64_t* o __attribute__((unused)),
wsrep_uuid_t* t __attribute__((unused)))
{
WSREP_DBUG_ENTER(w);
@ -322,18 +343,20 @@ static wsrep_t dummy_iface = {
&dummy_post_rollback,
&dummy_replay_trx,
&dummy_abort_pre_commit,
&dummy_append_query,
&dummy_append_row_key,
&dummy_append_key,
&dummy_append_data,
&dummy_causal_read,
&dummy_free_connection,
&dummy_to_execute_start,
&dummy_to_execute_end,
&dummy_preordered_collect,
&dummy_preordered_commit,
&dummy_sst_sent,
&dummy_sst_received,
&dummy_snapshot,
&dummy_stats_get,
&dummy_stats_free,
&dummy_stats_reset,
&dummy_pause,
&dummy_resume,
&dummy_desync,

74
wsrep/wsrep_gtid.c Normal file
View File

@ -0,0 +1,74 @@
/* Copyright (C) 2013 Codership Oy <info@codersihp.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 Helper functions to deal with GTID string representations */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "wsrep_api.h"
/*!
* Read GTID from string
* @return length of GTID string representation or -EINVAL in case of error
*/
int
wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid)
{
unsigned int offset;
char* endptr;
if ((offset = wsrep_uuid_scan(str, str_len, &gtid->uuid)) > 0 &&
offset < str_len && str[offset] == ':') {
++offset;
if (offset < str_len)
{
errno = 0;
gtid->seqno = strtoll(str + offset, &endptr, 0);
if (errno == 0) {
offset = endptr - str;
return offset;
}
}
}
*gtid = WSREP_GTID_UNDEFINED;
return -EINVAL;
}
/*!
* Write GTID to string
* @return length of GTID stirng representation of -EMSGSIZE if string is too
* short
*/
int
wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len)
{
unsigned int offset, ret;
if ((offset = wsrep_uuid_print(&gtid->uuid, str, str_len)) > 0)
{
ret = snprintf(str + offset, str_len - offset,
":%" PRId64, gtid->seqno);
if (ret <= str_len - offset) {
return (offset + ret);
}
}
return -EMSGSIZE;
}

View File

@ -70,15 +70,18 @@ static int verify(const wsrep_t *wh, const char *iface_ver)
VERIFY(wh->post_rollback);
VERIFY(wh->replay_trx);
VERIFY(wh->abort_pre_commit);
VERIFY(wh->append_query);
VERIFY(wh->append_key);
VERIFY(wh->append_data);
VERIFY(wh->free_connection);
VERIFY(wh->to_execute_start);
VERIFY(wh->to_execute_end);
VERIFY(wh->preordered_collect);
VERIFY(wh->preordered_commit);
VERIFY(wh->sst_sent);
VERIFY(wh->sst_received);
VERIFY(wh->stats_get);
VERIFY(wh->stats_free);
VERIFY(wh->stats_reset);
VERIFY(wh->pause);
VERIFY(wh->resume);
VERIFY(wh->desync);
@ -93,6 +96,7 @@ static int verify(const wsrep_t *wh, const char *iface_ver)
return 0;
}
typedef int (*wsrep_loader_fun)(wsrep_t*);
static wsrep_loader_fun wsrep_dlf(void *dlh, const char *sym)
{
@ -175,7 +179,7 @@ out:
*hptr = NULL;
} else {
snprintf (msg, msg_len,
"wsrep_load(): %s %s by %s loaded succesfully.",
"wsrep_load(): %s %s by %s loaded successfully.",
(*hptr)->provider_name, (*hptr)->provider_version,
(*hptr)->provider_vendor);
logger (WSREP_LOG_INFO, msg);

View File

@ -26,25 +26,31 @@
* Read UUID from string
* @return length of UUID string representation or -EINVAL in case of error
*/
ssize_t
int
wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid)
{
size_t uuid_len = 0;
size_t uuid_offt = 0;
unsigned int uuid_len = 0;
unsigned int uuid_offt = 0;
while (uuid_len + 1 < str_len) {
if ((4 == uuid_offt || 6 == uuid_offt || 8 == uuid_offt ||
10 == uuid_offt) && str[uuid_len] == '-') {
/* We are skipping potential '-' after uuid_offt == 4, 6, 8, 10
* which means
* (uuid_offt >> 1) == 2, 3, 4, 5,
* which in turn means
* (uuid_offt >> 1) - 2 <= 3
* since it is always >= 0, because uuid_offt is unsigned */
if (((uuid_offt >> 1) - 2) <= 3 && str[uuid_len] == '-') {
// skip dashes after 4th, 6th, 8th and 10th positions
uuid_len += 1;
continue;
}
if (isxdigit(str[uuid_len]) && isxdigit(str[uuid_len + 1])) {
// got hex digit
sscanf (str + uuid_len, "%2hhx", uuid->uuid + uuid_offt);
// got hex digit, scan another byte to uuid, increment uuid_offt
sscanf (str + uuid_len, "%2hhx", uuid->data + uuid_offt);
uuid_len += 2;
uuid_offt += 1;
if (sizeof (uuid->uuid) == uuid_offt)
if (sizeof (uuid->data) == uuid_offt)
return uuid_len;
}
else {
@ -61,11 +67,11 @@ wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid)
* @return length of UUID string representation or -EMSGSIZE if string is too
* short
*/
ssize_t
int
wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len)
{
if (str_len > 36) {
const unsigned char* u = uuid->uuid;
const unsigned char* u = uuid->data;
return snprintf(str, str_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x-%02x%02x%02x%02x%02x%02x",
u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7],
@ -75,4 +81,3 @@ wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len)
return -EMSGSIZE;
}
}