2015-03-23 22:27:28 +01:00
|
|
|
/* Copyright 2008-2015 Codership Oy <http://www.codership.com>
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
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
|
2017-02-20 22:29:25 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.x1
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
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 */
|
|
|
|
|
2017-06-19 12:23:02 +02:00
|
|
|
#include <sql_plugin.h> // SHOW_MY_BOOL
|
2013-09-03 16:50:36 +02:00
|
|
|
#include <mysqld.h>
|
|
|
|
#include <sql_class.h>
|
|
|
|
#include <sql_parse.h>
|
2017-02-20 22:29:25 +01:00
|
|
|
#include <sql_base.h> /* find_temporary_table() */
|
2013-09-03 16:50:36 +02:00
|
|
|
#include "wsrep_priv.h"
|
2013-11-05 23:29:37 +01:00
|
|
|
#include "wsrep_thd.h"
|
|
|
|
#include "wsrep_sst.h"
|
|
|
|
#include "wsrep_utils.h"
|
|
|
|
#include "wsrep_var.h"
|
2013-11-26 15:48:30 +01:00
|
|
|
#include "wsrep_binlog.h"
|
2013-11-26 23:18:44 +01:00
|
|
|
#include "wsrep_applier.h"
|
2015-03-23 22:27:28 +01:00
|
|
|
#include "wsrep_xid.h"
|
2013-09-03 16:50:36 +02:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "log_event.h"
|
2014-03-25 22:01:05 +01:00
|
|
|
#include <slave.h>
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
wsrep_t *wsrep = NULL;
|
|
|
|
my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
|
2013-12-04 09:32:43 +01:00
|
|
|
#ifdef GTID_SUPPORT
|
|
|
|
/* Sidno in global_sid_map corresponding to group uuid */
|
|
|
|
rpl_sidno wsrep_sidno= -1;
|
|
|
|
#endif /* GTID_SUPPORT */
|
|
|
|
my_bool wsrep_preordered_opt= FALSE;
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Begin configuration options and their default values
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char* wsrep_data_home_dir = NULL;
|
|
|
|
const char* wsrep_dbug_option = "";
|
|
|
|
|
|
|
|
long wsrep_slave_threads = 1; // # of slave action appliers wanted
|
2013-11-26 15:48:30 +01:00
|
|
|
int wsrep_slave_count_change = 0; // # of appliers to stop or start
|
2013-09-03 16:50:36 +02:00
|
|
|
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
|
2013-11-26 15:48:30 +01:00
|
|
|
ulong wsrep_max_ws_size = 1073741824UL;//max ws (RBR buffer) size
|
|
|
|
ulong wsrep_max_ws_rows = 65536; // max number of rows in ws
|
2013-09-03 16:50:36 +02:00
|
|
|
int wsrep_to_isolation = 0; // # of active TO isolation threads
|
|
|
|
my_bool wsrep_certify_nonPK = 1; // certify, even when no primary key
|
2014-06-20 00:48:20 +02:00
|
|
|
long wsrep_max_protocol_version = 3; // maximum protocol version to use
|
2013-09-03 16:50:36 +02:00
|
|
|
ulong wsrep_forced_binlog_format = BINLOG_FORMAT_UNSPEC;
|
|
|
|
my_bool wsrep_recovery = 0; // recovery
|
|
|
|
my_bool wsrep_replicate_myisam = 0; // enable myisam replication
|
2013-11-26 15:48:30 +01:00
|
|
|
my_bool wsrep_log_conflicts = 0;
|
2013-09-03 16:50:36 +02:00
|
|
|
ulong wsrep_mysql_replication_bundle = 0;
|
2013-11-26 15:48:30 +01:00
|
|
|
my_bool wsrep_desync = 0; // desynchronize the node from the
|
|
|
|
// cluster
|
2013-09-03 16:50:36 +02:00
|
|
|
my_bool wsrep_load_data_splitting = 1; // commit load data every 10K intervals
|
2014-05-21 20:32:57 +02:00
|
|
|
my_bool wsrep_restart_slave = 0; // should mysql slave thread be
|
2014-03-25 22:01:05 +01:00
|
|
|
// restarted, if node joins back
|
2014-05-21 20:32:57 +02:00
|
|
|
my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave
|
|
|
|
// restart will be needed
|
2014-06-20 00:48:20 +02:00
|
|
|
my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks
|
|
|
|
my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks
|
2016-12-14 10:52:04 +01:00
|
|
|
// Allow reads even if the node is not in the primary component.
|
|
|
|
bool wsrep_dirty_reads = false;
|
2015-09-17 05:20:57 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Set during the creation of first wsrep applier and rollback threads.
|
|
|
|
Since these threads are critical, abort if the thread creation fails.
|
|
|
|
*/
|
|
|
|
my_bool wsrep_creating_startup_threads = 0;
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
/*
|
|
|
|
* End configuration options
|
|
|
|
*/
|
|
|
|
|
2014-01-30 18:45:38 +01:00
|
|
|
/*
|
|
|
|
* Other wsrep global variables.
|
|
|
|
*/
|
|
|
|
my_bool wsrep_inited = 0; // initialized ?
|
|
|
|
|
2016-08-12 10:57:58 +02:00
|
|
|
static wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED;
|
2013-09-03 16:50:36 +02:00
|
|
|
static char cluster_uuid_str[40]= { 0, };
|
|
|
|
static const char* cluster_status_str[WSREP_VIEW_MAX] =
|
|
|
|
{
|
|
|
|
"Primary",
|
|
|
|
"non-Primary",
|
|
|
|
"Disconnected"
|
|
|
|
};
|
|
|
|
|
|
|
|
static char provider_name[256]= { 0, };
|
|
|
|
static char provider_version[256]= { 0, };
|
|
|
|
static char provider_vendor[256]= { 0, };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* wsrep status variables
|
|
|
|
*/
|
|
|
|
my_bool wsrep_connected = FALSE;
|
|
|
|
my_bool wsrep_ready = FALSE; // node can accept queries
|
|
|
|
const char* wsrep_cluster_state_uuid = cluster_uuid_str;
|
|
|
|
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;
|
2013-11-26 23:18:44 +01:00
|
|
|
long long wsrep_local_bf_aborts = 0;
|
2013-09-03 16:50:36 +02:00
|
|
|
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;
|
2014-06-20 00:48:20 +02:00
|
|
|
long wsrep_protocol_version = 3;
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
// Boolean denoting if server is in initial startup phase. This is needed
|
|
|
|
// to make sure that main thread waiting in wsrep_sst_wait() is signaled
|
|
|
|
// if there was no state gap on receiving first view event.
|
|
|
|
static my_bool wsrep_startup = TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) {
|
|
|
|
switch (level) {
|
|
|
|
case WSREP_LOG_INFO:
|
|
|
|
sql_print_information("WSREP: %s", msg);
|
|
|
|
break;
|
|
|
|
case WSREP_LOG_WARN:
|
|
|
|
sql_print_warning("WSREP: %s", msg);
|
|
|
|
break;
|
|
|
|
case WSREP_LOG_ERROR:
|
|
|
|
case WSREP_LOG_FATAL:
|
|
|
|
sql_print_error("WSREP: %s", msg);
|
|
|
|
break;
|
|
|
|
case WSREP_LOG_DEBUG:
|
2014-08-12 20:05:44 +02:00
|
|
|
if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
|
2013-09-03 16:50:36 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wsrep_log_states (wsrep_log_level_t const level,
|
|
|
|
const wsrep_uuid_t* const group_uuid,
|
|
|
|
wsrep_seqno_t const group_seqno,
|
|
|
|
const wsrep_uuid_t* const node_uuid,
|
|
|
|
wsrep_seqno_t const node_seqno)
|
|
|
|
{
|
|
|
|
char uuid_str[37];
|
|
|
|
char msg[256];
|
|
|
|
|
|
|
|
wsrep_uuid_print (group_uuid, uuid_str, sizeof(uuid_str));
|
|
|
|
snprintf (msg, 255, "WSREP: Group state: %s:%lld",
|
|
|
|
uuid_str, (long long)group_seqno);
|
|
|
|
wsrep_log_cb (level, msg);
|
|
|
|
|
|
|
|
wsrep_uuid_print (node_uuid, uuid_str, sizeof(uuid_str));
|
|
|
|
snprintf (msg, 255, "WSREP: Local state: %s:%lld",
|
|
|
|
uuid_str, (long long)node_seqno);
|
|
|
|
wsrep_log_cb (level, msg);
|
|
|
|
}
|
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
#ifdef GTID_SUPPORT
|
2015-03-23 22:27:28 +01:00
|
|
|
void wsrep_init_sidno(const wsrep_uuid_t& wsrep_uuid)
|
2013-12-04 09:32:43 +01:00
|
|
|
{
|
|
|
|
/* generate new Sid map entry from inverted uuid */
|
|
|
|
rpl_sid sid;
|
|
|
|
wsrep_uuid_t ltid_uuid;
|
2015-03-23 22:27:28 +01:00
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
for (size_t i= 0; i < sizeof(ltid_uuid.data); ++i)
|
|
|
|
{
|
2015-03-23 22:27:28 +01:00
|
|
|
ltid_uuid.data[i] = ~wsrep_uuid.data[i];
|
2013-12-04 09:32:43 +01:00
|
|
|
}
|
2015-03-23 22:27:28 +01:00
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
sid.copy_from(ltid_uuid.data);
|
|
|
|
global_sid_lock->wrlock();
|
|
|
|
wsrep_sidno= global_sid_map->add_sid(sid);
|
2015-03-23 22:27:28 +01:00
|
|
|
WSREP_INFO("Initialized wsrep sidno %d", wsrep_sidno);
|
2013-12-04 09:32:43 +01:00
|
|
|
global_sid_lock->unlock();
|
|
|
|
}
|
|
|
|
#endif /* GTID_SUPPORT */
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
static wsrep_cb_status_t
|
2013-12-04 09:32:43 +01:00
|
|
|
wsrep_view_handler_cb (void* app_ctx,
|
|
|
|
void* recv_ctx,
|
2013-11-26 15:48:30 +01:00
|
|
|
const wsrep_view_info_t* view,
|
2013-12-04 09:32:43 +01:00
|
|
|
const char* state,
|
|
|
|
size_t state_len,
|
|
|
|
void** sst_req,
|
|
|
|
size_t* sst_req_len)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-12-04 09:32:43 +01:00
|
|
|
*sst_req = NULL;
|
|
|
|
*sst_req_len = 0;
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_member_status_t new_status= local_status.get();
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t)))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2016-08-12 13:21:01 +02:00
|
|
|
memcpy(&cluster_uuid, &view->state_id.uuid, sizeof(cluster_uuid));
|
2013-11-26 15:48:30 +01:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_uuid_print (&cluster_uuid, cluster_uuid_str,
|
|
|
|
sizeof(cluster_uuid_str));
|
|
|
|
}
|
|
|
|
|
|
|
|
wsrep_cluster_conf_id= view->view;
|
|
|
|
wsrep_cluster_status= cluster_status_str[view->status];
|
|
|
|
wsrep_cluster_size= view->memb_num;
|
|
|
|
wsrep_local_index= view->my_idx;
|
|
|
|
|
|
|
|
WSREP_INFO("New cluster view: global state: %s:%lld, view# %lld: %s, "
|
|
|
|
"number of nodes: %ld, my index: %ld, protocol version %d",
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_cluster_state_uuid, (long long)view->state_id.seqno,
|
2013-09-03 16:50:36 +02:00
|
|
|
(long long)wsrep_cluster_conf_id, wsrep_cluster_status,
|
|
|
|
wsrep_cluster_size, wsrep_local_index, view->proto_ver);
|
|
|
|
|
|
|
|
/* Proceed further only if view is PRIMARY */
|
2014-09-17 20:59:39 +02:00
|
|
|
if (WSREP_VIEW_PRIMARY != view->status)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_QUERY_CACHE
|
|
|
|
// query cache must be initialised by now
|
|
|
|
query_cache.flush();
|
|
|
|
#endif /* HAVE_QUERY_CACHE */
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_ready_set(FALSE);
|
|
|
|
new_status= WSREP_MEMBER_UNDEFINED;
|
|
|
|
/* Always record local_uuid and local_seqno in non-prim since this
|
|
|
|
* may lead to re-initializing provider and start position is
|
|
|
|
* determined according to these variables */
|
|
|
|
// WRONG! local_uuid should be the last primary configuration uuid we were
|
|
|
|
// a member of. local_seqno should be updated in commit calls.
|
|
|
|
// local_uuid= cluster_uuid;
|
|
|
|
// local_seqno= view->first - 1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (view->proto_ver)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2014-06-20 00:48:20 +02:00
|
|
|
case 3:
|
2013-09-03 16:50:36 +02:00
|
|
|
// version change
|
|
|
|
if (view->proto_ver != wsrep_protocol_version)
|
|
|
|
{
|
2017-06-19 12:23:02 +02:00
|
|
|
my_bool wsrep_ready_saved= wsrep_ready_get();
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_ready_set(FALSE);
|
|
|
|
WSREP_INFO("closing client connections for "
|
|
|
|
"protocol change %ld -> %d",
|
|
|
|
wsrep_protocol_version, view->proto_ver);
|
|
|
|
wsrep_close_client_connections(TRUE);
|
|
|
|
wsrep_protocol_version= view->proto_ver;
|
|
|
|
wsrep_ready_set(wsrep_ready_saved);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WSREP_ERROR("Unsupported application protocol version: %d",
|
|
|
|
view->proto_ver);
|
|
|
|
unireg_abort(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (view->state_gap)
|
|
|
|
{
|
|
|
|
WSREP_WARN("Gap in state sequence. Need state transfer.");
|
|
|
|
|
|
|
|
/* After that wsrep will call wsrep_sst_prepare. */
|
|
|
|
/* keep ready flag 0 until we receive the snapshot */
|
|
|
|
wsrep_ready_set(FALSE);
|
|
|
|
|
|
|
|
/* Close client connections to ensure that they don't interfere
|
2014-10-01 00:06:15 +02:00
|
|
|
* with SST. Necessary only if storage engines are initialized
|
|
|
|
* before SST.
|
|
|
|
* TODO: Just killing all ongoing transactions should be enough
|
|
|
|
* since wsrep_ready is OFF and no new transactions can start.
|
|
|
|
*/
|
|
|
|
if (!wsrep_before_SE())
|
|
|
|
{
|
|
|
|
WSREP_DEBUG("[debug]: closing client connections for PRIM");
|
|
|
|
wsrep_close_client_connections(TRUE);
|
|
|
|
}
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
ssize_t const req_len= wsrep_sst_prepare (sst_req);
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
if (req_len < 0)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-12-04 09:32:43 +01:00
|
|
|
WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len,
|
|
|
|
strerror(-req_len));
|
2013-09-03 16:50:36 +02:00
|
|
|
new_status= WSREP_MEMBER_UNDEFINED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-12-04 09:32:43 +01:00
|
|
|
assert(sst_req != NULL);
|
|
|
|
*sst_req_len= req_len;
|
2013-09-03 16:50:36 +02:00
|
|
|
new_status= WSREP_MEMBER_JOINER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* NOTE: Initialize wsrep_group_uuid here only if it wasn't initialized
|
|
|
|
* before - OR - it was reinitilized on startup (lp:992840)
|
|
|
|
*/
|
|
|
|
if (wsrep_startup)
|
|
|
|
{
|
|
|
|
if (wsrep_before_SE())
|
|
|
|
{
|
|
|
|
wsrep_SE_init_grab();
|
|
|
|
// Signal mysqld init thread to continue
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_sst_complete (&cluster_uuid, view->state_id.seqno, false);
|
2013-09-03 16:50:36 +02:00
|
|
|
// and wait for SE initialization
|
|
|
|
wsrep_SE_init_wait();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
local_uuid= cluster_uuid;
|
2013-11-26 15:48:30 +01:00
|
|
|
local_seqno= view->state_id.seqno;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
/* Init storage engine XIDs from first view */
|
2015-03-23 22:27:28 +01:00
|
|
|
wsrep_set_SE_checkpoint(local_uuid, local_seqno);
|
2013-12-04 09:32:43 +01:00
|
|
|
#ifdef GTID_SUPPORT
|
|
|
|
wsrep_init_sidno(local_uuid);
|
|
|
|
#endif /* GTID_SUPPORT */
|
2015-03-23 22:27:28 +01:00
|
|
|
new_status= WSREP_MEMBER_JOINED;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// just some sanity check
|
|
|
|
if (memcmp (&local_uuid, &cluster_uuid, sizeof (wsrep_uuid_t)))
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Undetected state gap. Can't continue.");
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->state_id.seqno,
|
2013-09-03 16:50:36 +02:00
|
|
|
&local_uuid, -1);
|
|
|
|
unireg_abort(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wsrep_auto_increment_control)
|
|
|
|
{
|
|
|
|
global_system_variables.auto_increment_offset= view->my_idx + 1;
|
|
|
|
global_system_variables.auto_increment_increment= view->memb_num;
|
|
|
|
}
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
{ /* 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;
|
|
|
|
}
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
out:
|
2014-07-04 10:41:09 +02:00
|
|
|
if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE;
|
2013-09-03 16:50:36 +02:00
|
|
|
local_status.set(new_status, view);
|
2013-11-26 15:48:30 +01:00
|
|
|
|
|
|
|
return WSREP_CB_SUCCESS;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
2017-06-19 12:23:02 +02:00
|
|
|
my_bool wsrep_ready_set (my_bool x)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
WSREP_DEBUG("Setting wsrep_ready to %d", x);
|
|
|
|
if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
|
2017-06-19 12:23:02 +02:00
|
|
|
my_bool ret= (wsrep_ready != x);
|
|
|
|
if (ret)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
wsrep_ready= x;
|
|
|
|
mysql_cond_signal (&COND_wsrep_ready);
|
|
|
|
}
|
|
|
|
mysql_mutex_unlock (&LOCK_wsrep_ready);
|
2017-06-19 12:23:02 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool wsrep_ready_get (void)
|
|
|
|
{
|
|
|
|
if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
|
|
|
|
my_bool ret= wsrep_ready;
|
|
|
|
mysql_mutex_unlock (&LOCK_wsrep_ready);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff)
|
|
|
|
{
|
|
|
|
var->type= SHOW_MY_BOOL;
|
|
|
|
var->value= buff;
|
|
|
|
*((my_bool *)buff)= wsrep_ready_get();
|
|
|
|
return 0;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait until wsrep has reached ready state
|
|
|
|
void wsrep_ready_wait ()
|
|
|
|
{
|
|
|
|
if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
|
|
|
|
while (!wsrep_ready)
|
|
|
|
{
|
|
|
|
WSREP_INFO("Waiting to reach ready state");
|
|
|
|
mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready);
|
|
|
|
}
|
|
|
|
WSREP_INFO("ready state reached");
|
|
|
|
mysql_mutex_unlock (&LOCK_wsrep_ready);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wsrep_synced_cb(void* app_ctx)
|
|
|
|
{
|
|
|
|
WSREP_INFO("Synchronized with group, ready for connections");
|
2017-06-19 12:23:02 +02:00
|
|
|
my_bool signal_main= wsrep_ready_set(TRUE);
|
2013-09-03 16:50:36 +02:00
|
|
|
local_status.set(WSREP_MEMBER_SYNCED);
|
2014-03-25 18:39:12 +01:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2014-03-25 22:01:05 +01:00
|
|
|
if (wsrep_restart_slave_activated)
|
|
|
|
{
|
2014-05-21 20:32:57 +02:00
|
|
|
int rcode;
|
2014-03-25 22:01:05 +01:00
|
|
|
WSREP_INFO("MySQL slave restart");
|
|
|
|
wsrep_restart_slave_activated= FALSE;
|
2014-05-21 20:32:57 +02:00
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_active_mi);
|
|
|
|
if ((rcode = start_slave_threads(1 /* need mutex */,
|
|
|
|
0 /* no wait for start*/,
|
|
|
|
active_mi,
|
|
|
|
master_info_file,
|
|
|
|
relay_log_info_file,
|
2014-05-21 23:07:17 +02:00
|
|
|
SLAVE_SQL)))
|
2014-05-21 20:32:57 +02:00
|
|
|
{
|
|
|
|
WSREP_WARN("Failed to create slave threads: %d", rcode);
|
|
|
|
}
|
|
|
|
mysql_mutex_unlock(&LOCK_active_mi);
|
|
|
|
|
2014-03-25 22:01:05 +01:00
|
|
|
}
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void wsrep_init_position()
|
|
|
|
{
|
|
|
|
/* read XIDs from storage engines */
|
2015-03-23 22:27:28 +01:00
|
|
|
wsrep_uuid_t uuid;
|
|
|
|
wsrep_seqno_t seqno;
|
|
|
|
wsrep_get_SE_checkpoint(uuid, seqno);
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2015-03-23 22:27:28 +01:00
|
|
|
if (!memcmp(&uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
WSREP_INFO("Read nil XID from storage engines, skipping position init");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char uuid_str[40] = {0, };
|
2015-03-23 22:27:28 +01:00
|
|
|
wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str));
|
2013-09-03 16:50:36 +02:00
|
|
|
WSREP_INFO("Initial position: %s:%lld", uuid_str, (long long)seqno);
|
|
|
|
|
|
|
|
if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(local_uuid)) &&
|
|
|
|
local_seqno == WSREP_SEQNO_UNDEFINED)
|
|
|
|
{
|
|
|
|
// Initial state
|
2015-03-23 22:27:28 +01:00
|
|
|
local_uuid= uuid;
|
2013-09-03 16:50:36 +02:00
|
|
|
local_seqno= seqno;
|
|
|
|
}
|
2015-03-23 22:27:28 +01:00
|
|
|
else if (memcmp(&local_uuid, &uuid, sizeof(local_uuid)) ||
|
2013-09-03 16:50:36 +02:00
|
|
|
local_seqno != seqno)
|
|
|
|
{
|
|
|
|
WSREP_WARN("Initial position was provided by configuration or SST, "
|
|
|
|
"avoiding override");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
extern char* my_bind_addr_str;
|
2013-11-26 15:48:30 +01:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
int wsrep_init()
|
|
|
|
{
|
|
|
|
int rcode= -1;
|
2014-01-30 18:45:38 +01:00
|
|
|
DBUG_ASSERT(wsrep_inited == 0);
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
wsrep_ready_set(FALSE);
|
|
|
|
assert(wsrep_provider);
|
2013-12-04 09:32:43 +01:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_init_position();
|
|
|
|
|
|
|
|
if ((rcode= wsrep_load(wsrep_provider, &wsrep, wsrep_log_cb)) != WSREP_OK)
|
|
|
|
{
|
|
|
|
if (strcasecmp(wsrep_provider, WSREP_NONE))
|
|
|
|
{
|
|
|
|
WSREP_ERROR("wsrep_load(%s) failed: %s (%d). Reverting to no provider.",
|
|
|
|
wsrep_provider, strerror(rcode), rcode);
|
|
|
|
strcpy((char*)wsrep_provider, WSREP_NONE); // damn it's a dirty hack
|
2016-06-09 09:21:43 +02:00
|
|
|
return wsrep_init();
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
else /* this is for recursive call above */
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Could not revert to no provider: %s (%d). Need to abort.",
|
|
|
|
strerror(rcode), rcode);
|
|
|
|
unireg_abort(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-30 18:45:38 +01:00
|
|
|
if (!WSREP_PROVIDER_EXISTS)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
// enable normal operation in case no provider is specified
|
|
|
|
wsrep_ready_set(TRUE);
|
2014-01-30 18:45:38 +01:00
|
|
|
wsrep_inited= 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
global_system_variables.wsrep_on = 0;
|
2014-03-25 22:01:05 +01:00
|
|
|
wsrep_init_args args;
|
2014-05-21 21:04:13 +02:00
|
|
|
args.logger_cb = wsrep_log_cb;
|
2014-03-25 22:01:05 +01:00
|
|
|
args.options = (wsrep_provider_options) ?
|
|
|
|
wsrep_provider_options : "";
|
|
|
|
rcode = wsrep->init(wsrep, &args);
|
|
|
|
if (rcode)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode));
|
|
|
|
WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode);
|
2014-05-21 20:32:57 +02:00
|
|
|
wsrep->free(wsrep);
|
2014-03-25 22:01:05 +01:00
|
|
|
free(wsrep);
|
|
|
|
wsrep = NULL;
|
|
|
|
}
|
|
|
|
return rcode;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
global_system_variables.wsrep_on = 1;
|
|
|
|
strncpy(provider_name,
|
|
|
|
wsrep->provider_name, sizeof(provider_name) - 1);
|
|
|
|
strncpy(provider_version,
|
|
|
|
wsrep->provider_version, sizeof(provider_version) - 1);
|
|
|
|
strncpy(provider_vendor,
|
|
|
|
wsrep->provider_vendor, sizeof(provider_vendor) - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
char node_addr[512]= { 0, };
|
|
|
|
size_t const node_addr_max= sizeof(node_addr) - 1;
|
|
|
|
if (!wsrep_node_address || !strcmp(wsrep_node_address, ""))
|
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
size_t const ret= wsrep_guess_ip(node_addr, node_addr_max);
|
2013-09-03 16:50:36 +02:00
|
|
|
if (!(ret > 0 && ret < node_addr_max))
|
|
|
|
{
|
|
|
|
WSREP_WARN("Failed to guess base node address. Set it explicitly via "
|
|
|
|
"wsrep_node_address.");
|
|
|
|
node_addr[0]= '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncpy(node_addr, wsrep_node_address, node_addr_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
char inc_addr[512]= { 0, };
|
|
|
|
size_t const inc_addr_max= sizeof (inc_addr);
|
|
|
|
if ((!wsrep_node_incoming_address ||
|
|
|
|
!strcmp (wsrep_node_incoming_address, WSREP_NODE_INCOMING_AUTO)))
|
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
unsigned int my_bind_ip= INADDR_ANY; // default if not set
|
|
|
|
if (my_bind_addr_str && strlen(my_bind_addr_str))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
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)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
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)
|
|
|
|
{
|
2017-03-03 21:28:27 +01:00
|
|
|
size_t const ip_len= wsrep_host_len(node_addr, node_addr_len);
|
|
|
|
if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2017-03-03 21:28:27 +01:00
|
|
|
memcpy (inc_addr, node_addr, ip_len);
|
|
|
|
snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
|
|
|
|
(int)mysqld_port);
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WSREP_WARN("Guessing address for incoming client connections: "
|
2017-03-03 21:28:27 +01:00
|
|
|
"address too long.");
|
2013-09-03 16:50:36 +02:00
|
|
|
inc_addr[0]= '\0';
|
|
|
|
}
|
|
|
|
}
|
2013-11-26 15:48:30 +01:00
|
|
|
|
|
|
|
if (!strlen(inc_addr))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
WSREP_WARN("Guessing address for incoming client connections failed. "
|
|
|
|
"Try setting wsrep_node_incoming_address explicitly.");
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strchr(wsrep_node_incoming_address, ':')) // no port included
|
|
|
|
{
|
|
|
|
if ((int)inc_addr_max <=
|
|
|
|
snprintf(inc_addr, inc_addr_max, "%s:%u",
|
|
|
|
wsrep_node_incoming_address,(int)mysqld_port))
|
|
|
|
{
|
|
|
|
WSREP_WARN("Guessing address for incoming client connections: "
|
|
|
|
"address too long.");
|
|
|
|
inc_addr[0]= '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t const need = strlen (wsrep_node_incoming_address);
|
|
|
|
if (need >= inc_addr_max) {
|
|
|
|
WSREP_WARN("wsrep_node_incoming_address too long: %zu", need);
|
|
|
|
inc_addr[0]= '\0';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy (inc_addr, wsrep_node_incoming_address, need);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wsrep_init_args wsrep_args;
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
struct wsrep_gtid const state_id = { local_uuid, local_seqno };
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_args.data_dir = wsrep_data_home_dir;
|
|
|
|
wsrep_args.node_name = (wsrep_node_name) ? wsrep_node_name : "";
|
|
|
|
wsrep_args.node_address = node_addr;
|
|
|
|
wsrep_args.node_incoming = inc_addr;
|
|
|
|
wsrep_args.options = (wsrep_provider_options) ?
|
|
|
|
wsrep_provider_options : "";
|
|
|
|
wsrep_args.proto_ver = wsrep_max_protocol_version;
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_args.state_id = &state_id;
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
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;
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_args.unordered_cb = wsrep_unordered_cb;
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_args.sst_donate_cb = wsrep_sst_donate_cb;
|
|
|
|
wsrep_args.synced_cb = wsrep_synced_cb;
|
|
|
|
|
|
|
|
rcode = wsrep->init(wsrep, &wsrep_args);
|
|
|
|
|
|
|
|
if (rcode)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode));
|
|
|
|
WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode);
|
2014-05-21 20:32:57 +02:00
|
|
|
wsrep->free(wsrep);
|
2013-09-03 16:50:36 +02:00
|
|
|
free(wsrep);
|
|
|
|
wsrep = NULL;
|
2014-01-30 18:45:38 +01:00
|
|
|
} else {
|
|
|
|
wsrep_inited= 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return rcode;
|
|
|
|
}
|
|
|
|
|
2013-10-07 10:35:19 +02:00
|
|
|
extern int wsrep_on(void *);
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
void wsrep_init_startup (bool first)
|
|
|
|
{
|
|
|
|
if (wsrep_init()) unireg_abort(1);
|
|
|
|
|
2014-03-25 19:42:15 +01:00
|
|
|
wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd,
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on);
|
|
|
|
|
2016-06-09 09:21:43 +02:00
|
|
|
/* Skip replication start if dummy wsrep provider is loaded */
|
|
|
|
if (!strcmp(wsrep_provider, WSREP_NONE)) return;
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
/* Skip replication start if no cluster address */
|
|
|
|
if (!wsrep_cluster_address || strlen(wsrep_cluster_address) == 0) return;
|
|
|
|
|
|
|
|
if (first) wsrep_sst_grab(); // do it so we can wait for SST below
|
|
|
|
|
|
|
|
if (!wsrep_start_replication()) unireg_abort(1);
|
|
|
|
|
2015-09-17 05:20:57 +02:00
|
|
|
wsrep_creating_startup_threads= 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_create_rollbacker();
|
|
|
|
wsrep_create_appliers(1);
|
|
|
|
|
|
|
|
if (first && !wsrep_sst_wait()) unireg_abort(1);// wait until SST is completed
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-09 17:07:23 +02:00
|
|
|
void wsrep_deinit(bool free_options)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2014-01-30 18:45:38 +01:00
|
|
|
DBUG_ASSERT(wsrep_inited == 1);
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_unload(wsrep);
|
|
|
|
wsrep= 0;
|
|
|
|
provider_name[0]= '\0';
|
|
|
|
provider_version[0]= '\0';
|
|
|
|
provider_vendor[0]= '\0';
|
2013-02-05 16:54:42 +01:00
|
|
|
|
2014-01-30 18:45:38 +01:00
|
|
|
wsrep_inited= 0;
|
2014-07-09 17:07:23 +02:00
|
|
|
|
|
|
|
if (free_options)
|
|
|
|
{
|
|
|
|
wsrep_sst_auth_free();
|
|
|
|
}
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void wsrep_recover()
|
|
|
|
{
|
|
|
|
if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)) &&
|
|
|
|
local_seqno == -2)
|
|
|
|
{
|
|
|
|
char uuid_str[40];
|
|
|
|
wsrep_uuid_print(&local_uuid, uuid_str, sizeof(uuid_str));
|
|
|
|
WSREP_INFO("Position %s:%lld given at startup, skipping position recovery",
|
|
|
|
uuid_str, (long long)local_seqno);
|
|
|
|
return;
|
|
|
|
}
|
2015-03-23 22:27:28 +01:00
|
|
|
wsrep_uuid_t uuid;
|
|
|
|
wsrep_seqno_t seqno;
|
|
|
|
wsrep_get_SE_checkpoint(uuid, seqno);
|
2013-09-03 16:50:36 +02:00
|
|
|
char uuid_str[40];
|
2015-03-23 22:27:28 +01:00
|
|
|
wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str));
|
|
|
|
WSREP_INFO("Recovered position: %s:%lld", uuid_str, (long long)seqno);
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void wsrep_stop_replication(THD *thd)
|
|
|
|
{
|
|
|
|
WSREP_INFO("Stop replication");
|
|
|
|
if (!wsrep)
|
|
|
|
{
|
|
|
|
WSREP_INFO("Provider was not loaded, in stop replication");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect from group first to get wsrep_ready == FALSE */
|
|
|
|
WSREP_DEBUG("Provider disconnect");
|
|
|
|
wsrep->disconnect(wsrep);
|
|
|
|
|
|
|
|
wsrep_connected= FALSE;
|
|
|
|
|
|
|
|
wsrep_close_client_connections(TRUE);
|
|
|
|
|
|
|
|
/* wait until appliers have stopped */
|
|
|
|
wsrep_wait_appliers_close(thd);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool wsrep_start_replication()
|
|
|
|
{
|
|
|
|
wsrep_status_t rcode;
|
|
|
|
|
|
|
|
/*
|
|
|
|
if provider is trivial, don't even try to connect,
|
|
|
|
but resume local node operation
|
|
|
|
*/
|
2014-01-30 18:45:38 +01:00
|
|
|
if (!WSREP_PROVIDER_EXISTS)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
// enable normal operation in case no provider is specified
|
|
|
|
wsrep_ready_set(TRUE);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wsrep_cluster_address || strlen(wsrep_cluster_address)== 0)
|
|
|
|
{
|
|
|
|
// if provider is non-trivial, but no address is specified, wait for address
|
|
|
|
wsrep_ready_set(FALSE);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-09 03:21:37 +02:00
|
|
|
bool const bootstrap= wsrep_new_cluster;
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
WSREP_INFO("Start replication");
|
|
|
|
|
2014-09-09 03:21:37 +02:00
|
|
|
if (wsrep_new_cluster)
|
|
|
|
{
|
|
|
|
WSREP_INFO("'wsrep-new-cluster' option used, bootstrapping the cluster");
|
|
|
|
wsrep_new_cluster= false;
|
|
|
|
}
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
if ((rcode = wsrep->connect(wsrep,
|
|
|
|
wsrep_cluster_name,
|
2013-12-04 09:32:43 +01:00
|
|
|
wsrep_cluster_address,
|
|
|
|
wsrep_sst_donor,
|
2013-11-26 15:48:30 +01:00
|
|
|
bootstrap)))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2015-05-02 21:25:39 +02:00
|
|
|
DBUG_PRINT("wsrep",("wsrep->connect(%s) failed: %d",
|
|
|
|
wsrep_cluster_address, rcode));
|
|
|
|
WSREP_ERROR("wsrep::connect(%s) failed: %d",
|
|
|
|
wsrep_cluster_address, rcode);
|
2013-09-03 16:50:36 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wsrep_connected= TRUE;
|
|
|
|
|
|
|
|
char* opts= wsrep->options_get(wsrep);
|
|
|
|
if (opts)
|
|
|
|
{
|
|
|
|
wsrep_provider_options_init(opts);
|
|
|
|
free(opts);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WSREP_WARN("Failed to get wsrep options");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-10-20 17:54:14 +02:00
|
|
|
bool wsrep_must_sync_wait (THD* thd, uint mask)
|
|
|
|
{
|
|
|
|
return (thd->variables.wsrep_sync_wait & mask) &&
|
|
|
|
thd->variables.wsrep_on &&
|
2016-12-14 12:44:42 +01:00
|
|
|
!(thd->variables.wsrep_dirty_reads &&
|
|
|
|
!is_update_query(thd->lex->sql_command)) &&
|
2015-10-20 17:54:14 +02:00
|
|
|
!thd->in_active_multi_stmt_transaction() &&
|
|
|
|
thd->wsrep_conflict_state != REPLAYING &&
|
|
|
|
thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
2014-08-12 20:50:26 +02:00
|
|
|
bool wsrep_sync_wait (THD* thd, uint mask)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2015-10-20 17:54:14 +02:00
|
|
|
if (wsrep_must_sync_wait(thd, mask))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2014-08-12 20:50:26 +02:00
|
|
|
WSREP_DEBUG("wsrep_sync_wait: thd->variables.wsrep_sync_wait = %u, mask = %u",
|
|
|
|
thd->variables.wsrep_sync_wait, mask);
|
2013-09-03 16:50:36 +02:00
|
|
|
// This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0
|
|
|
|
// TODO: modify to check if thd has locked any rows.
|
2015-10-20 17:54:14 +02:00
|
|
|
wsrep_status_t ret= wsrep->causal_read (wsrep, &thd->wsrep_sync_wait_gtid);
|
2013-09-03 16:50:36 +02:00
|
|
|
|
|
|
|
if (unlikely(WSREP_OK != ret))
|
|
|
|
{
|
|
|
|
const char* msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
// Possibly relevant error codes:
|
|
|
|
// ER_CHECKREAD, ER_ERROR_ON_READ, ER_INVALID_DEFAULT, ER_EMPTY_QUERY,
|
|
|
|
// ER_FUNCTION_NOT_DEFINED, ER_NOT_ALLOWED_COMMAND, ER_NOT_SUPPORTED_YET,
|
|
|
|
// ER_FEATURE_DISABLED, ER_QUERY_INTERRUPTED
|
|
|
|
|
|
|
|
switch (ret)
|
|
|
|
{
|
|
|
|
case WSREP_NOT_IMPLEMENTED:
|
2014-08-12 20:05:44 +02:00
|
|
|
msg= "synchronous reads by wsrep backend. "
|
2013-09-03 16:50:36 +02:00
|
|
|
"Please unset wsrep_causal_reads variable.";
|
|
|
|
err= ER_NOT_SUPPORTED_YET;
|
|
|
|
break;
|
|
|
|
default:
|
2014-08-12 20:50:26 +02:00
|
|
|
msg= "Synchronous wait failed.";
|
2013-09-03 16:50:36 +02:00
|
|
|
err= ER_LOCK_WAIT_TIMEOUT; // NOTE: the above msg won't be displayed
|
|
|
|
// with ER_LOCK_WAIT_TIMEOUT
|
|
|
|
}
|
|
|
|
|
|
|
|
my_error(err, MYF(0), msg);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-27 18:51:18 +02:00
|
|
|
void wsrep_keys_free(wsrep_key_arr_t* key_arr)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
for (size_t i= 0; i < key_arr->keys_len; ++i)
|
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
my_free((void*)key_arr->keys[i].key_parts);
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
my_free(key_arr->keys);
|
|
|
|
key_arr->keys= 0;
|
|
|
|
key_arr->keys_len= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @param db Database string
|
|
|
|
* @param table Table string
|
|
|
|
* @param key Array of wsrep_key_t
|
|
|
|
* @param key_len In: number of elements in key array, Out: number of
|
|
|
|
* elements populated
|
|
|
|
*
|
|
|
|
* @return true if preparation was successful, otherwise false.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static bool wsrep_prepare_key_for_isolation(const char* db,
|
|
|
|
const char* table,
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_buf_t* key,
|
2013-09-03 16:50:36 +02:00
|
|
|
size_t* key_len)
|
|
|
|
{
|
|
|
|
if (*key_len < 2) return false;
|
|
|
|
|
|
|
|
switch (wsrep_protocol_version)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
*key_len= 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2014-06-20 00:48:20 +02:00
|
|
|
case 3:
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
*key_len= 0;
|
|
|
|
if (db)
|
|
|
|
{
|
|
|
|
// sql_print_information("%s.%s", db, table);
|
|
|
|
if (db)
|
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
key[*key_len].ptr= db;
|
|
|
|
key[*key_len].len= strlen(db);
|
2013-09-03 16:50:36 +02:00
|
|
|
++(*key_len);
|
|
|
|
if (table)
|
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
key[*key_len].ptr= table;
|
|
|
|
key[*key_len].len= strlen(table);
|
2013-09-03 16:50:36 +02:00
|
|
|
++(*key_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepare key list from db/table and table_list */
|
2017-04-27 18:51:18 +02:00
|
|
|
bool wsrep_prepare_keys_for_isolation(THD* thd,
|
|
|
|
const char* db,
|
|
|
|
const char* table,
|
|
|
|
const TABLE_LIST* table_list,
|
|
|
|
wsrep_key_arr_t* ka)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2017-02-20 22:29:25 +01:00
|
|
|
ka->keys= 0;
|
|
|
|
ka->keys_len= 0;
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2017-02-20 22:29:25 +01:00
|
|
|
if (db || table)
|
|
|
|
{
|
|
|
|
if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2017-02-20 22:29:25 +01:00
|
|
|
WSREP_ERROR("Can't allocate memory for key_array");
|
|
|
|
goto err;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2017-02-20 22:29:25 +01:00
|
|
|
ka->keys_len= 1;
|
|
|
|
if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
|
|
|
|
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2017-02-20 22:29:25 +01:00
|
|
|
WSREP_ERROR("Can't allocate memory for key_parts");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
ka->keys[0].key_parts_num= 2;
|
|
|
|
if (!wsrep_prepare_key_for_isolation(
|
|
|
|
db, table,
|
|
|
|
(wsrep_buf_t*)ka->keys[0].key_parts,
|
|
|
|
&ka->keys[0].key_parts_num))
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Preparing keys for isolation failed (1)");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2013-12-04 09:32:43 +01:00
|
|
|
|
2017-02-20 22:29:25 +01:00
|
|
|
for (const TABLE_LIST* table= table_list; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
wsrep_key_t* tmp;
|
2017-03-08 13:11:57 +01:00
|
|
|
if (ka->keys)
|
|
|
|
tmp= (wsrep_key_t*)my_realloc(ka->keys,
|
2017-02-20 22:29:25 +01:00
|
|
|
(ka->keys_len + 1) * sizeof(wsrep_key_t),
|
|
|
|
MYF(0));
|
2017-03-08 13:11:57 +01:00
|
|
|
else
|
|
|
|
tmp= (wsrep_key_t*)my_malloc((ka->keys_len + 1) * sizeof(wsrep_key_t), MYF(0));
|
|
|
|
|
2017-02-20 22:29:25 +01:00
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Can't allocate memory for key_array");
|
|
|
|
goto err;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2017-02-20 22:29:25 +01:00
|
|
|
ka->keys= tmp;
|
|
|
|
if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
|
|
|
|
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Can't allocate memory for key_parts");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
ka->keys[ka->keys_len].key_parts_num= 2;
|
|
|
|
++ka->keys_len;
|
|
|
|
if (!wsrep_prepare_key_for_isolation(table->db, table->table_name,
|
|
|
|
(wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
|
|
|
|
&ka->keys[ka->keys_len - 1].key_parts_num))
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Preparing keys for isolation failed (2)");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2013-09-03 16:50:36 +02:00
|
|
|
err:
|
|
|
|
wsrep_keys_free(ka);
|
2017-02-20 22:29:25 +01:00
|
|
|
return 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool wsrep_prepare_key_for_innodb(const uchar* cache_key,
|
2013-12-04 09:32:43 +01:00
|
|
|
size_t cache_key_len,
|
2013-09-03 16:50:36 +02:00
|
|
|
const uchar* row_id,
|
|
|
|
size_t row_id_len,
|
2013-11-26 15:48:30 +01:00
|
|
|
wsrep_buf_t* key,
|
2013-09-03 16:50:36 +02:00
|
|
|
size_t* key_len)
|
|
|
|
{
|
|
|
|
if (*key_len < 3) return false;
|
|
|
|
|
|
|
|
*key_len= 0;
|
|
|
|
switch (wsrep_protocol_version)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
key[0].ptr = cache_key;
|
|
|
|
key[0].len = cache_key_len;
|
|
|
|
|
|
|
|
*key_len = 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2014-06-20 00:48:20 +02:00
|
|
|
case 3:
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-11-26 15:48:30 +01:00
|
|
|
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;
|
2013-09-03 16:50:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
key[*key_len].ptr = row_id;
|
|
|
|
key[*key_len].len = row_id_len;
|
2013-09-03 16:50:36 +02:00
|
|
|
++(*key_len);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
/*
|
|
|
|
* Construct Query_log_Event from thd query and serialize it
|
|
|
|
* into buffer.
|
|
|
|
*
|
|
|
|
* Return 0 in case of success, 1 in case of error.
|
|
|
|
*/
|
|
|
|
int wsrep_to_buf_helper(
|
2013-12-04 09:32:43 +01:00
|
|
|
THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
IO_CACHE tmp_io_cache;
|
|
|
|
if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX,
|
|
|
|
65536, MYF(MY_WME)))
|
|
|
|
return 1;
|
|
|
|
int ret(0);
|
2013-12-04 09:32:43 +01:00
|
|
|
|
2015-03-28 01:35:37 +01:00
|
|
|
Format_description_log_event *tmp_fd= new Format_description_log_event(4);
|
|
|
|
tmp_fd->checksum_alg= binlog_checksum_options;
|
|
|
|
tmp_fd->write(&tmp_io_cache);
|
|
|
|
delete tmp_fd;
|
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
#ifdef GTID_SUPPORT
|
|
|
|
if (thd->variables.gtid_next.type == GTID_GROUP)
|
|
|
|
{
|
|
|
|
Gtid_log_event gtid_ev(thd, FALSE, &thd->variables.gtid_next);
|
|
|
|
if (!gtid_ev.is_valid()) ret= 0;
|
|
|
|
if (!ret && gtid_ev.write(&tmp_io_cache)) ret= 1;
|
|
|
|
}
|
|
|
|
#endif /* GTID_SUPPORT */
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
/* if there is prepare query, add event for it */
|
2013-12-04 09:32:43 +01:00
|
|
|
if (!ret && thd->wsrep_TOI_pre_query)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2014-05-21 23:07:17 +02:00
|
|
|
Query_log_event ev(thd, thd->wsrep_TOI_pre_query,
|
|
|
|
thd->wsrep_TOI_pre_query_len,
|
2013-12-04 09:32:43 +01:00
|
|
|
FALSE, FALSE, FALSE, 0);
|
2013-09-03 16:50:36 +02:00
|
|
|
if (ev.write(&tmp_io_cache)) ret= 1;
|
|
|
|
}
|
|
|
|
|
2013-12-04 09:32:43 +01:00
|
|
|
/* continue to append the actual query */
|
2013-09-03 16:50:36 +02:00
|
|
|
Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0);
|
2013-12-04 09:32:43 +01:00
|
|
|
if (!ret && ev.write(&tmp_io_cache)) ret= 1;
|
|
|
|
if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
close_cached_file(&tmp_io_cache);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "sql_show.h"
|
|
|
|
static int
|
2013-12-04 09:32:43 +01:00
|
|
|
create_view_query(THD *thd, uchar** buf, size_t* buf_len)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
LEX *lex= thd->lex;
|
|
|
|
SELECT_LEX *select_lex= &lex->select_lex;
|
|
|
|
TABLE_LIST *first_table= select_lex->table_list.first;
|
|
|
|
TABLE_LIST *views = first_table;
|
|
|
|
|
|
|
|
String buff;
|
|
|
|
const LEX_STRING command[3]=
|
|
|
|
{{ C_STRING_WITH_LEN("CREATE ") },
|
|
|
|
{ C_STRING_WITH_LEN("ALTER ") },
|
|
|
|
{ C_STRING_WITH_LEN("CREATE OR REPLACE ") }};
|
|
|
|
|
|
|
|
buff.append(command[thd->lex->create_view_mode].str,
|
|
|
|
command[thd->lex->create_view_mode].length);
|
|
|
|
|
2015-08-14 08:46:32 +02:00
|
|
|
LEX_USER *definer;
|
|
|
|
|
|
|
|
if (lex->definer)
|
|
|
|
{
|
|
|
|
definer= get_current_user(thd, lex->definer);
|
|
|
|
}
|
|
|
|
else
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
/*
|
2013-11-26 15:48:30 +01:00
|
|
|
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.
|
2013-09-03 16:50:36 +02:00
|
|
|
*/
|
2015-08-14 08:46:32 +02:00
|
|
|
definer= create_default_definer(thd, false);
|
|
|
|
}
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2015-08-14 08:46:32 +02:00
|
|
|
if (definer)
|
|
|
|
{
|
|
|
|
views->definer.user = definer->user;
|
|
|
|
views->definer.host = definer->host;
|
|
|
|
} else {
|
|
|
|
WSREP_ERROR("Failed to get DEFINER for VIEW.");
|
|
|
|
return 1;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
views->algorithm = lex->create_view_algorithm;
|
|
|
|
views->view_suid = lex->create_view_suid;
|
|
|
|
views->with_check = lex->create_view_check;
|
|
|
|
|
2015-07-20 04:51:19 +02:00
|
|
|
view_store_options4(thd, views, &buff, true);
|
2013-09-03 16:50:36 +02:00
|
|
|
buff.append(STRING_WITH_LEN("VIEW "));
|
|
|
|
/* Test if user supplied a db (ie: we did not use thd->db) */
|
|
|
|
if (views->db && views->db[0] &&
|
|
|
|
(thd->db == NULL || strcmp(views->db, thd->db)))
|
|
|
|
{
|
|
|
|
append_identifier(thd, &buff, views->db,
|
|
|
|
views->db_length);
|
|
|
|
buff.append('.');
|
|
|
|
}
|
|
|
|
append_identifier(thd, &buff, views->table_name,
|
|
|
|
views->table_name_length);
|
|
|
|
if (lex->view_list.elements)
|
|
|
|
{
|
|
|
|
List_iterator_fast<LEX_STRING> names(lex->view_list);
|
|
|
|
LEX_STRING *name;
|
|
|
|
int i;
|
2013-11-26 15:48:30 +01:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
for (i= 0; (name= names++); i++)
|
|
|
|
{
|
|
|
|
buff.append(i ? ", " : "(");
|
|
|
|
append_identifier(thd, &buff, name->str, name->length);
|
|
|
|
}
|
|
|
|
buff.append(')');
|
|
|
|
}
|
|
|
|
buff.append(STRING_WITH_LEN(" AS "));
|
|
|
|
//buff.append(views->source.str, views->source.length);
|
2014-05-21 20:32:57 +02:00
|
|
|
buff.append(thd->lex->create_view_select.str,
|
2013-12-04 09:32:43 +01:00
|
|
|
thd->lex->create_view_select.length);
|
2013-09-03 16:50:36 +02:00
|
|
|
//int errcode= query_error_code(thd, TRUE);
|
|
|
|
//if (thd->binlog_query(THD::STMT_QUERY_TYPE,
|
|
|
|
// buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcod
|
|
|
|
return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
|
|
|
|
}
|
|
|
|
|
2017-02-20 22:29:25 +01:00
|
|
|
/*
|
|
|
|
Rewrite DROP TABLE for TOI. Temporary tables are eliminated from
|
|
|
|
the query as they are visible only to client connection.
|
|
|
|
|
|
|
|
TODO: See comments for sql_base.cc:drop_temporary_table() and refine
|
|
|
|
the function to deal with transactional locked tables.
|
|
|
|
*/
|
|
|
|
static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len)
|
|
|
|
{
|
|
|
|
|
|
|
|
LEX* lex= thd->lex;
|
|
|
|
SELECT_LEX* select_lex= &lex->select_lex;
|
|
|
|
TABLE_LIST* first_table= select_lex->table_list.first;
|
|
|
|
String buff;
|
|
|
|
|
|
|
|
DBUG_ASSERT(!lex->drop_temporary);
|
|
|
|
|
|
|
|
bool found_temp_table= false;
|
|
|
|
for (TABLE_LIST* table= first_table; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
if (find_temporary_table(thd, table->db, table->table_name))
|
|
|
|
{
|
|
|
|
found_temp_table= true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found_temp_table)
|
|
|
|
{
|
|
|
|
buff.append("DROP TABLE ");
|
|
|
|
if (lex->check_exists)
|
|
|
|
buff.append("IF EXISTS ");
|
|
|
|
|
|
|
|
for (TABLE_LIST* table= first_table; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
if (!find_temporary_table(thd, table->db, table->table_name))
|
|
|
|
{
|
|
|
|
append_identifier(thd, &buff, table->db, strlen(table->db));
|
|
|
|
buff.append(".");
|
|
|
|
append_identifier(thd, &buff, table->table_name,
|
|
|
|
strlen(table->table_name));
|
|
|
|
buff.append(",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Chop the last comma */
|
|
|
|
buff.chop();
|
|
|
|
buff.append(" /* generated by wsrep */");
|
|
|
|
|
|
|
|
WSREP_DEBUG("Rewrote '%s' as '%s'", thd->query(), buff.ptr());
|
|
|
|
|
|
|
|
return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
|
|
|
|
buf, buf_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Decide if statement should run in TOI.
|
|
|
|
|
|
|
|
Look if table or table_list contain temporary tables. If the
|
|
|
|
statement affects only temporary tables, statement should not run
|
|
|
|
in TOI. If the table list contains mix of regular and temporary tables
|
|
|
|
(DROP TABLE, OPTIMIZE, ANALYZE), statement should be run in TOI but
|
|
|
|
should be rewritten at later time for replication to contain only
|
|
|
|
non-temporary tables.
|
|
|
|
*/
|
|
|
|
static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
|
|
|
|
const TABLE_LIST *table_list)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(!table || db);
|
|
|
|
DBUG_ASSERT(table_list || db);
|
|
|
|
|
|
|
|
LEX* lex= thd->lex;
|
|
|
|
SELECT_LEX* select_lex= &lex->select_lex;
|
|
|
|
TABLE_LIST* first_table= select_lex->table_list.first;
|
|
|
|
|
|
|
|
switch (lex->sql_command)
|
|
|
|
{
|
|
|
|
case SQLCOM_CREATE_TABLE:
|
|
|
|
DBUG_ASSERT(!table_list);
|
|
|
|
if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SQLCOM_CREATE_VIEW:
|
|
|
|
|
|
|
|
DBUG_ASSERT(!table_list);
|
|
|
|
DBUG_ASSERT(first_table); /* First table is view name */
|
|
|
|
/*
|
|
|
|
If any of the remaining tables refer to temporary table error
|
|
|
|
is returned to client, so TOI can be skipped
|
|
|
|
*/
|
|
|
|
for (TABLE_LIST* it= first_table->next_global; it; it= it->next_global)
|
|
|
|
{
|
|
|
|
if (find_temporary_table(thd, it))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SQLCOM_CREATE_TRIGGER:
|
|
|
|
|
|
|
|
DBUG_ASSERT(!table_list);
|
|
|
|
DBUG_ASSERT(first_table);
|
|
|
|
|
|
|
|
if (find_temporary_table(thd, first_table))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (table && !find_temporary_table(thd, db, table))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (table_list)
|
|
|
|
{
|
|
|
|
for (TABLE_LIST* table= first_table; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
if (!find_temporary_table(thd, table->db, table->table_name))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !(table || table_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 14:13:31 +02:00
|
|
|
static const char* wsrep_get_query_or_msg(const THD* thd)
|
|
|
|
{
|
|
|
|
switch(thd->lex->sql_command)
|
|
|
|
{
|
|
|
|
case SQLCOM_CREATE_USER:
|
|
|
|
return "CREATE USER";
|
|
|
|
case SQLCOM_GRANT:
|
|
|
|
return "GRANT";
|
|
|
|
case SQLCOM_REVOKE:
|
|
|
|
return "REVOKE";
|
|
|
|
case SQLCOM_SET_OPTION:
|
|
|
|
if (thd->lex->definer)
|
|
|
|
return "SET PASSWORD";
|
|
|
|
/* fallthrough */
|
|
|
|
default:
|
|
|
|
return thd->query();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-13 13:04:23 +01:00
|
|
|
/*
|
|
|
|
returns:
|
|
|
|
0: statement was replicated as TOI
|
|
|
|
1: TOI replication was skipped
|
|
|
|
-1: TOI replication failed
|
|
|
|
*/
|
2017-03-10 08:25:24 +01:00
|
|
|
static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
|
2014-05-21 20:32:57 +02:00
|
|
|
const TABLE_LIST* table_list)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
wsrep_status_t ret(WSREP_WARNING);
|
|
|
|
uchar* buf(0);
|
2013-12-04 09:32:43 +01:00
|
|
|
size_t buf_len(0);
|
2013-09-03 16:50:36 +02:00
|
|
|
int buf_err;
|
2015-08-14 07:37:21 +02:00
|
|
|
int rc= 0;
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2017-02-20 22:29:25 +01:00
|
|
|
if (wsrep_can_run_in_toi(thd, db_, table_, table_list) == false)
|
|
|
|
{
|
|
|
|
WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-11-26 15:48:30 +01:00
|
|
|
WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
|
2018-07-19 14:13:31 +02:00
|
|
|
thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
switch (thd->lex->sql_command)
|
|
|
|
{
|
|
|
|
case SQLCOM_CREATE_VIEW:
|
|
|
|
buf_err= create_view_query(thd, &buf, &buf_len);
|
|
|
|
break;
|
|
|
|
case SQLCOM_CREATE_PROCEDURE:
|
|
|
|
case SQLCOM_CREATE_SPFUNCTION:
|
|
|
|
buf_err= wsrep_create_sp(thd, &buf, &buf_len);
|
|
|
|
break;
|
|
|
|
case SQLCOM_CREATE_TRIGGER:
|
|
|
|
buf_err= wsrep_create_trigger_query(thd, &buf, &buf_len);
|
|
|
|
break;
|
|
|
|
case SQLCOM_CREATE_EVENT:
|
|
|
|
buf_err= wsrep_create_event_query(thd, &buf, &buf_len);
|
|
|
|
break;
|
2014-06-20 00:48:20 +02:00
|
|
|
case SQLCOM_ALTER_EVENT:
|
|
|
|
buf_err= wsrep_alter_event_query(thd, &buf, &buf_len);
|
|
|
|
break;
|
2016-08-24 21:32:48 +02:00
|
|
|
case SQLCOM_CREATE_ROLE:
|
|
|
|
if (sp_process_definer(thd))
|
|
|
|
{
|
|
|
|
WSREP_WARN("Failed to set CREATE ROLE definer for TOI.");
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
2013-09-03 16:50:36 +02:00
|
|
|
default:
|
2017-03-10 08:25:24 +01:00
|
|
|
buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
|
2017-02-16 22:19:10 +01:00
|
|
|
&buf, &buf_len);
|
2013-09-03 16:50:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsrep_key_arr_t key_arr= {0, 0};
|
2013-11-26 15:48:30 +01:00
|
|
|
struct wsrep_buf buff = { buf, buf_len };
|
2017-02-20 22:29:25 +01:00
|
|
|
if (!buf_err &&
|
|
|
|
!wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr) &&
|
|
|
|
key_arr.keys_len > 0 &&
|
2013-09-03 16:50:36 +02:00
|
|
|
WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
|
2014-11-13 13:04:23 +01:00
|
|
|
key_arr.keys, key_arr.keys_len,
|
|
|
|
&buff, 1,
|
|
|
|
&thd->wsrep_trx_meta)))
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
thd->wsrep_exec_mode= TOTAL_ORDER;
|
|
|
|
wsrep_to_isolation++;
|
|
|
|
wsrep_keys_free(&key_arr);
|
2013-11-26 15:48:30 +01:00
|
|
|
WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd),
|
2014-11-13 13:04:23 +01:00
|
|
|
thd->wsrep_exec_mode);
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2014-11-13 13:04:23 +01:00
|
|
|
else if (key_arr.keys_len > 0) {
|
2013-09-03 16:50:36 +02:00
|
|
|
/* jump to error handler in mysql_execute_command() */
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. Check wsrep "
|
2013-09-03 16:50:36 +02:00
|
|
|
"connection state and retry the query.",
|
2015-10-19 10:56:04 +02:00
|
|
|
ret,
|
|
|
|
(thd->db ? thd->db : "(null)"),
|
|
|
|
(thd->query()) ? thd->query() : "void");
|
2013-09-03 16:50:36 +02:00
|
|
|
my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
|
2014-11-13 13:04:23 +01:00
|
|
|
"your wsrep connection state and retry the query.");
|
2013-09-03 16:50:36 +02:00
|
|
|
wsrep_keys_free(&key_arr);
|
2015-08-14 07:37:21 +02:00
|
|
|
rc= -1;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2014-11-13 13:04:23 +01:00
|
|
|
else {
|
|
|
|
/* non replicated DDL, affecting temporary tables only */
|
|
|
|
WSREP_DEBUG("TO isolation skipped for: %d, sql: %s."
|
|
|
|
"Only temporary tables affected.",
|
|
|
|
ret, (thd->query()) ? thd->query() : "void");
|
2015-08-14 07:37:21 +02:00
|
|
|
rc= 1;
|
2014-11-13 13:04:23 +01:00
|
|
|
}
|
2015-08-14 07:37:21 +02:00
|
|
|
if (buf) my_free(buf);
|
|
|
|
return rc;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void wsrep_TOI_end(THD *thd) {
|
|
|
|
wsrep_status_t ret;
|
|
|
|
wsrep_to_isolation--;
|
2013-11-26 21:09:14 +01:00
|
|
|
|
2018-07-19 14:13:31 +02:00
|
|
|
WSREP_DEBUG("TO END: %lld, %d: %s", (long long)wsrep_thd_trx_seqno(thd),
|
|
|
|
thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
|
2015-03-23 22:27:28 +01:00
|
|
|
|
|
|
|
wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
|
|
|
|
thd->wsrep_trx_meta.gtid.seqno);
|
2014-06-20 00:48:20 +02:00
|
|
|
WSREP_DEBUG("TO END: %lld, update seqno",
|
|
|
|
(long long)wsrep_thd_trx_seqno(thd));
|
|
|
|
|
2013-11-26 21:09:14 +01:00
|
|
|
if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) {
|
|
|
|
WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd));
|
|
|
|
}
|
|
|
|
else {
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s",
|
|
|
|
ret,
|
|
|
|
(thd->db ? thd->db : "(null)"),
|
|
|
|
(thd->query()) ? thd->query() : "void");
|
2013-11-26 21:09:14 +01:00
|
|
|
}
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 20:32:57 +02:00
|
|
|
static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
wsrep_status_t ret(WSREP_WARNING);
|
2013-11-26 15:48:30 +01:00
|
|
|
WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
|
2013-09-03 16:50:36 +02:00
|
|
|
thd->wsrep_exec_mode, thd->query() );
|
|
|
|
|
2016-04-03 02:51:26 +02:00
|
|
|
ret = wsrep->desync(wsrep);
|
|
|
|
if (ret != WSREP_OK)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2016-04-03 02:51:26 +02:00
|
|
|
WSREP_WARN("RSU desync failed %d for schema: %s, query: %s",
|
|
|
|
ret, (thd->db ? thd->db : "(null)"), thd->query());
|
|
|
|
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
|
|
|
return(ret);
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2016-04-03 02:51:26 +02:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
mysql_mutex_lock(&LOCK_wsrep_replaying);
|
|
|
|
wsrep_replaying++;
|
|
|
|
mysql_mutex_unlock(&LOCK_wsrep_replaying);
|
|
|
|
|
|
|
|
if (wsrep_wait_committing_connections_close(5000))
|
|
|
|
{
|
|
|
|
/* no can do, bail out from DDL */
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_WARN("RSU failed due to pending transactions, schema: %s, query %s",
|
|
|
|
(thd->db ? thd->db : "(null)"),
|
|
|
|
thd->query());
|
2013-09-03 16:50:36 +02:00
|
|
|
mysql_mutex_lock(&LOCK_wsrep_replaying);
|
|
|
|
wsrep_replaying--;
|
|
|
|
mysql_mutex_unlock(&LOCK_wsrep_replaying);
|
|
|
|
|
2016-04-03 02:51:26 +02:00
|
|
|
ret = wsrep->resync(wsrep);
|
|
|
|
if (ret != WSREP_OK)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2016-04-03 02:51:26 +02:00
|
|
|
WSREP_WARN("resync failed %d for schema: %s, query: %s",
|
|
|
|
ret, (thd->db ? thd->db : "(null)"), thd->query());
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2016-04-03 02:51:26 +02:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
wsrep_seqno_t seqno = wsrep->pause(wsrep);
|
|
|
|
if (seqno == WSREP_SEQNO_UNDEFINED)
|
|
|
|
{
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_WARN("pause failed %lld for schema: %s, query: %s", (long long)seqno,
|
|
|
|
(thd->db ? thd->db : "(null)"),
|
|
|
|
thd->query());
|
2013-09-03 16:50:36 +02:00
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
WSREP_DEBUG("paused at %lld", (long long)seqno);
|
|
|
|
thd->variables.wsrep_on = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wsrep_RSU_end(THD *thd)
|
|
|
|
{
|
|
|
|
wsrep_status_t ret(WSREP_WARNING);
|
2013-11-26 15:48:30 +01:00
|
|
|
WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
|
2013-09-03 16:50:36 +02:00
|
|
|
thd->wsrep_exec_mode, thd->query() );
|
|
|
|
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_wsrep_replaying);
|
|
|
|
wsrep_replaying--;
|
|
|
|
mysql_mutex_unlock(&LOCK_wsrep_replaying);
|
|
|
|
|
|
|
|
ret = wsrep->resume(wsrep);
|
|
|
|
if (ret != WSREP_OK)
|
|
|
|
{
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_WARN("resume failed %d for schema: %s, query: %s", ret,
|
|
|
|
(thd->db ? thd->db : "(null)"),
|
|
|
|
thd->query());
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2016-04-03 02:51:26 +02:00
|
|
|
|
|
|
|
ret = wsrep->resync(wsrep);
|
|
|
|
if (ret != WSREP_OK)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2016-04-03 02:51:26 +02:00
|
|
|
WSREP_WARN("resync failed %d for schema: %s, query: %s", ret,
|
|
|
|
(thd->db ? thd->db : "(null)"), thd->query());
|
|
|
|
return;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2016-04-03 02:51:26 +02:00
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
thd->variables.wsrep_on = 1;
|
|
|
|
}
|
|
|
|
|
2017-02-22 22:10:36 +01:00
|
|
|
int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
|
2013-09-03 16:50:36 +02:00
|
|
|
const TABLE_LIST* table_list)
|
|
|
|
{
|
2013-11-26 21:09:14 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
No isolation for applier or replaying threads.
|
|
|
|
*/
|
|
|
|
if (thd->wsrep_exec_mode == REPL_RECV) return 0;
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
int ret= 0;
|
|
|
|
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
|
2013-11-26 21:09:14 +01:00
|
|
|
|
2014-05-21 20:32:57 +02:00
|
|
|
if (thd->wsrep_conflict_state == MUST_ABORT)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_INFO("thread: %lu, schema: %s, query: %s has been aborted due to multi-master conflict",
|
|
|
|
thd->thread_id,
|
|
|
|
(thd->db ? thd->db : "(null)"),
|
|
|
|
thd->query());
|
2013-09-03 16:50:36 +02:00
|
|
|
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
|
|
|
|
return WSREP_TRX_FAIL;
|
|
|
|
}
|
|
|
|
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
|
|
|
|
|
2013-11-26 21:09:14 +01:00
|
|
|
DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
|
|
|
|
DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
|
|
|
|
|
2014-03-25 19:42:15 +01:00
|
|
|
if (thd->global_read_lock.can_acquire_protection())
|
|
|
|
{
|
|
|
|
WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lu",
|
|
|
|
thd->query(), thd->thread_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
if (wsrep_debug && thd->mdl_context.has_locks())
|
|
|
|
{
|
2014-05-21 20:32:57 +02:00
|
|
|
WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu",
|
2013-09-03 16:50:36 +02:00
|
|
|
thd->query(), thd->thread_id);
|
|
|
|
}
|
2013-11-26 23:18:44 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE)
|
|
|
|
{
|
2015-03-12 09:25:34 +01:00
|
|
|
switch (thd->variables.wsrep_OSU_method) {
|
2017-02-20 22:29:25 +01:00
|
|
|
case WSREP_OSU_TOI:
|
2017-03-10 08:25:24 +01:00
|
|
|
ret = wsrep_TOI_begin(thd, db_, table_, table_list);
|
2017-02-20 22:29:25 +01:00
|
|
|
break;
|
|
|
|
case WSREP_OSU_RSU:
|
|
|
|
ret = wsrep_RSU_begin(thd, db_, table_);
|
|
|
|
break;
|
2015-03-11 12:04:00 +01:00
|
|
|
default:
|
2015-03-12 09:25:34 +01:00
|
|
|
WSREP_ERROR("Unsupported OSU method: %lu",
|
|
|
|
thd->variables.wsrep_OSU_method);
|
2015-03-11 12:04:00 +01:00
|
|
|
ret= -1;
|
|
|
|
break;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2014-11-13 13:04:23 +01:00
|
|
|
switch (ret) {
|
|
|
|
case 0: thd->wsrep_exec_mode= TOTAL_ORDER; break;
|
2015-03-11 12:04:00 +01:00
|
|
|
case 1:
|
|
|
|
/* TOI replication skipped, treat as success */
|
|
|
|
ret = 0;
|
2014-11-13 13:04:23 +01:00
|
|
|
break;
|
|
|
|
case -1:
|
2015-03-11 12:04:00 +01:00
|
|
|
/* TOI replication failed, treat as error */
|
2014-11-13 13:04:23 +01:00
|
|
|
break;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-11-26 21:09:14 +01:00
|
|
|
void wsrep_to_isolation_end(THD *thd)
|
|
|
|
{
|
|
|
|
if (thd->wsrep_exec_mode == TOTAL_ORDER)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2015-03-12 09:25:34 +01:00
|
|
|
switch(thd->variables.wsrep_OSU_method)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2013-11-26 21:09:14 +01:00
|
|
|
case WSREP_OSU_TOI: wsrep_TOI_end(thd); break;
|
|
|
|
case WSREP_OSU_RSU: wsrep_RSU_end(thd); break;
|
2015-03-11 12:04:00 +01:00
|
|
|
default:
|
|
|
|
WSREP_WARN("Unsupported wsrep OSU method at isolation end: %lu",
|
2015-03-12 09:25:34 +01:00
|
|
|
thd->variables.wsrep_OSU_method);
|
2015-03-11 12:04:00 +01:00
|
|
|
break;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2013-11-26 21:09:14 +01:00
|
|
|
wsrep_cleanup_transaction(thd);
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-19 10:56:04 +02:00
|
|
|
#define WSREP_MDL_LOG(severity, msg, schema, schema_len, req, gra) \
|
2013-09-03 16:50:36 +02:00
|
|
|
WSREP_##severity( \
|
2015-10-19 13:14:51 +02:00
|
|
|
"%s\n" \
|
2015-10-19 10:56:04 +02:00
|
|
|
"schema: %.*s\n" \
|
2013-09-03 16:50:36 +02:00
|
|
|
"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)", \
|
2015-10-19 13:14:51 +02:00
|
|
|
msg, schema_len, schema, \
|
2013-11-26 15:48:30 +01:00
|
|
|
req->thread_id, (long long)wsrep_thd_trx_seqno(req), \
|
2013-09-03 16:50:36 +02:00
|
|
|
req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \
|
2015-10-19 13:14:51 +02:00
|
|
|
req->get_command(), req->lex->sql_command, req->query(), \
|
2013-11-26 15:48:30 +01:00
|
|
|
gra->thread_id, (long long)wsrep_thd_trx_seqno(gra), \
|
2013-09-03 16:50:36 +02:00
|
|
|
gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \
|
2013-10-07 10:35:19 +02:00
|
|
|
gra->get_command(), gra->lex->sql_command, gra->query());
|
2013-09-03 16:50:36 +02:00
|
|
|
|
2015-06-20 01:25:15 +02:00
|
|
|
/**
|
|
|
|
Check if request for the metadata lock should be granted to the requester.
|
|
|
|
|
|
|
|
@param requestor_ctx The MDL context of the requestor
|
|
|
|
@param ticket MDL ticket for the requested lock
|
|
|
|
|
|
|
|
@retval TRUE Lock request can be granted
|
|
|
|
@retval FALSE Lock request cannot be granted
|
|
|
|
*/
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
bool
|
|
|
|
wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
|
2015-10-19 10:56:04 +02:00
|
|
|
MDL_ticket *ticket,
|
|
|
|
const MDL_key *key
|
2013-09-03 16:50:36 +02:00
|
|
|
) {
|
2015-06-20 01:25:15 +02:00
|
|
|
/* Fallback to the non-wsrep behaviour */
|
2013-09-03 16:50:36 +02:00
|
|
|
if (!WSREP_ON) return FALSE;
|
|
|
|
|
2016-09-01 18:53:44 +02:00
|
|
|
THD *request_thd = requestor_ctx->get_thd();
|
|
|
|
THD *granted_thd = ticket->get_ctx()->get_thd();
|
2013-09-03 16:50:36 +02:00
|
|
|
bool ret = FALSE;
|
|
|
|
|
2015-10-19 10:56:04 +02:00
|
|
|
const char* schema= key->db_name();
|
|
|
|
int schema_len= key->db_name_length();
|
|
|
|
|
2013-09-03 16:50:36 +02:00
|
|
|
mysql_mutex_lock(&request_thd->LOCK_wsrep_thd);
|
|
|
|
if (request_thd->wsrep_exec_mode == TOTAL_ORDER ||
|
|
|
|
request_thd->wsrep_exec_mode == REPL_RECV)
|
|
|
|
{
|
|
|
|
mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_MDL_LOG(DEBUG, "MDL conflict ", schema, schema_len,
|
|
|
|
request_thd, granted_thd);
|
2013-09-03 16:50:36 +02:00
|
|
|
ticket->wsrep_report(wsrep_debug);
|
|
|
|
|
|
|
|
mysql_mutex_lock(&granted_thd->LOCK_wsrep_thd);
|
|
|
|
if (granted_thd->wsrep_exec_mode == TOTAL_ORDER ||
|
|
|
|
granted_thd->wsrep_exec_mode == REPL_RECV)
|
|
|
|
{
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", schema, schema_len,
|
|
|
|
request_thd, granted_thd);
|
2013-09-03 16:50:36 +02:00
|
|
|
ticket->wsrep_report(true);
|
|
|
|
mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
2015-04-21 15:22:53 +02:00
|
|
|
else if (granted_thd->lex->sql_command == SQLCOM_FLUSH ||
|
2015-04-28 19:38:25 +02:00
|
|
|
granted_thd->mdl_context.wsrep_has_explicit_locks())
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2015-04-21 15:22:53 +02:00
|
|
|
WSREP_DEBUG("BF thread waiting for FLUSH");
|
2013-09-03 16:50:36 +02:00
|
|
|
ticket->wsrep_report(wsrep_debug);
|
|
|
|
mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
|
2015-04-21 15:22:53 +02:00
|
|
|
ret = FALSE;
|
2013-09-03 16:50:36 +02:00
|
|
|
}
|
2014-05-21 20:32:57 +02:00
|
|
|
else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2017-04-27 18:51:18 +02:00
|
|
|
WSREP_DEBUG("DROP caused BF abort, conf %d", granted_thd->wsrep_conflict_state);
|
2013-09-03 16:50:36 +02:00
|
|
|
ticket->wsrep_report(wsrep_debug);
|
|
|
|
mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
|
|
|
|
wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
2014-05-21 20:32:57 +02:00
|
|
|
else if (granted_thd->wsrep_query_state == QUERY_COMMITTING)
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
|
|
|
WSREP_DEBUG("mdl granted, but commiting thd abort scheduled");
|
|
|
|
ticket->wsrep_report(wsrep_debug);
|
|
|
|
mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
|
|
|
|
wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
2014-05-21 20:32:57 +02:00
|
|
|
else
|
2013-09-03 16:50:36 +02:00
|
|
|
{
|
2015-10-19 10:56:04 +02:00
|
|
|
WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", schema, schema_len,
|
|
|
|
request_thd, granted_thd);
|
2013-09-03 16:50:36 +02:00
|
|
|
ticket->wsrep_report(wsrep_debug);
|
|
|
|
mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
|
|
|
|
wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2016-02-29 21:54:58 +01:00
|
|
|
|
|
|
|
bool wsrep_node_is_donor()
|
|
|
|
{
|
|
|
|
return (WSREP_ON) ? (local_status.get() == 2) : false;
|
|
|
|
}
|
2016-03-07 22:34:03 +01:00
|
|
|
bool wsrep_node_is_synced()
|
|
|
|
{
|
|
|
|
return (WSREP_ON) ? (local_status.get() == 4) : false;
|
|
|
|
}
|