2015-07-14 22:05:29 +02:00
|
|
|
/* Copyright (C) 2013-2015 Codership Oy <info@codership.com>
|
2014-01-17 12:28:43 +01: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
|
|
|
|
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.,
|
2019-05-11 21:19:05 +02:00
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */
|
2014-01-17 12:28:43 +01:00
|
|
|
|
2017-06-18 05:42:16 +02:00
|
|
|
#include "mariadb.h"
|
2019-01-23 12:30:00 +01:00
|
|
|
#include "mysql/service_wsrep.h"
|
|
|
|
#include "wsrep_applier.h"
|
|
|
|
|
2014-01-17 12:28:43 +01:00
|
|
|
#include "wsrep_priv.h"
|
2015-07-14 22:05:29 +02:00
|
|
|
#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
|
|
|
|
#include "wsrep_xid.h"
|
2019-01-23 12:30:00 +01:00
|
|
|
#include "wsrep_thd.h"
|
|
|
|
#include "wsrep_trans_observer.h"
|
2014-01-17 12:28:43 +01:00
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
#include "slave.h" // opt_log_slave_updates
|
2015-07-14 22:05:29 +02:00
|
|
|
#include "log_event.h" // class THD, EVENT_LEN_OFFSET, etc.
|
2016-02-24 02:33:21 +01:00
|
|
|
#include "debug_sync.h"
|
2014-01-17 12:28:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
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);
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
uint data_len= uint4korr(head + EVENT_LEN_OFFSET);
|
2014-01-17 12:28:43 +01:00
|
|
|
char *buf= (*arg_buf);
|
|
|
|
const char *error= 0;
|
|
|
|
Log_event *res= 0;
|
|
|
|
|
2016-05-06 16:07:53 +02:00
|
|
|
res= Log_event::read_log_event(buf, data_len, &error, description_event,
|
|
|
|
true);
|
2014-01-17 12:28:43 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-04-02 00:25:40 +02:00
|
|
|
void wsrep_set_apply_format(THD* thd, Format_description_log_event* ev)
|
2014-01-17 12:28:43 +01:00
|
|
|
{
|
|
|
|
if (thd->wsrep_apply_format)
|
|
|
|
{
|
2019-01-23 12:30:00 +01:00
|
|
|
delete (Format_description_log_event*)thd->wsrep_apply_format;
|
2014-01-17 12:28:43 +01:00
|
|
|
}
|
|
|
|
thd->wsrep_apply_format= ev;
|
|
|
|
}
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
Format_description_log_event*
|
|
|
|
wsrep_get_apply_format(THD* thd)
|
2014-01-17 12:28:43 +01:00
|
|
|
{
|
|
|
|
if (thd->wsrep_apply_format)
|
2015-07-14 22:05:29 +02:00
|
|
|
{
|
|
|
|
return (Format_description_log_event*) thd->wsrep_apply_format;
|
|
|
|
}
|
2016-12-06 02:07:30 +01:00
|
|
|
|
|
|
|
DBUG_ASSERT(thd->wsrep_rgi);
|
|
|
|
|
2015-07-14 22:05:29 +02:00
|
|
|
return thd->wsrep_rgi->rli->relay_log.description_event_for_exec;
|
2014-01-17 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
void wsrep_apply_error::store(const THD* const thd)
|
2014-01-17 12:28:43 +01:00
|
|
|
{
|
2019-01-23 12:30:00 +01:00
|
|
|
Diagnostics_area::Sql_condition_iterator it=
|
|
|
|
thd->get_stmt_da()->sql_conditions();
|
|
|
|
const Sql_condition* cond;
|
2014-01-17 12:28:43 +01:00
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
static size_t const max_len= 2*MAX_SLAVE_ERRMSG; // 2x so that we have enough
|
|
|
|
|
|
|
|
if (NULL == str_)
|
|
|
|
{
|
|
|
|
// this must be freeable by standard free()
|
|
|
|
str_= static_cast<char*>(malloc(max_len));
|
|
|
|
if (NULL == str_)
|
|
|
|
{
|
|
|
|
WSREP_ERROR("Failed to allocate %zu bytes for error buffer.", max_len);
|
|
|
|
len_= 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This is possible when we invoke rollback after failed applying.
|
|
|
|
* In this situation DA should not be reset yet and should contain
|
|
|
|
* all previous errors from applying and new ones from rollbacking,
|
|
|
|
* so we just overwrite is from scratch */
|
|
|
|
}
|
2014-01-17 12:28:43 +01:00
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
char* slider= str_;
|
|
|
|
const char* const buf_end= str_ + max_len - 1; // -1: leave space for \0
|
|
|
|
|
|
|
|
for (cond= it++; cond && slider < buf_end; cond= it++)
|
2014-01-17 12:28:43 +01:00
|
|
|
{
|
2019-01-23 12:30:00 +01:00
|
|
|
uint const err_code= cond->get_sql_errno();
|
|
|
|
const char* const err_str= cond->get_message_text();
|
|
|
|
|
|
|
|
slider+= my_snprintf(slider, buf_end - slider, " %s, Error_code: %d;",
|
|
|
|
err_str, err_code);
|
2014-01-17 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
*slider= '\0';
|
|
|
|
len_= slider - str_ + 1; // +1: add \0
|
|
|
|
|
|
|
|
WSREP_DEBUG("Error buffer for thd %llu seqno %lld, %zu bytes: %s",
|
|
|
|
thd->thread_id, (long long)wsrep_thd_trx_seqno(thd),
|
|
|
|
len_, str_ ? str_ : "(null)");
|
|
|
|
}
|
|
|
|
|
|
|
|
int wsrep_apply_events(THD* thd,
|
|
|
|
Relay_log_info* rli,
|
|
|
|
const void* events_buf,
|
|
|
|
size_t buf_len)
|
|
|
|
{
|
|
|
|
char *buf= (char *)events_buf;
|
|
|
|
int rcode= 0;
|
|
|
|
int event= 1;
|
|
|
|
Log_event_type typ;
|
2014-01-17 12:28:43 +01:00
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
DBUG_ENTER("wsrep_apply_events");
|
2014-01-17 12:28:43 +01:00
|
|
|
if (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld",
|
|
|
|
(long long) wsrep_thd_trx_seqno(thd));
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
while (buf_len)
|
2014-01-17 12:28:43 +01:00
|
|
|
{
|
|
|
|
int exec_res;
|
|
|
|
Log_event* ev= wsrep_read_log_event(&buf, &buf_len,
|
2019-01-23 12:30:00 +01:00
|
|
|
wsrep_get_apply_format(thd));
|
2014-01-17 12:28:43 +01:00
|
|
|
if (!ev)
|
|
|
|
{
|
2014-01-30 18:45:38 +01:00
|
|
|
WSREP_ERROR("applier could not read binlog event, seqno: %lld, len: %zu",
|
2014-01-17 12:28:43 +01:00
|
|
|
(long long)wsrep_thd_trx_seqno(thd), buf_len);
|
2019-01-23 12:30:00 +01:00
|
|
|
rcode= WSREP_ERR_BAD_EVENT;
|
2014-01-17 12:28:43 +01:00
|
|
|
goto error;
|
|
|
|
}
|
2014-05-21 23:07:17 +02:00
|
|
|
|
2015-07-14 22:05:29 +02:00
|
|
|
typ= ev->get_type_code();
|
|
|
|
|
|
|
|
switch (typ) {
|
2014-01-17 12:28:43 +01:00
|
|
|
case FORMAT_DESCRIPTION_EVENT:
|
|
|
|
wsrep_set_apply_format(thd, (Format_description_log_event*)ev);
|
|
|
|
continue;
|
|
|
|
#ifdef GTID_SUPPORT
|
|
|
|
case GTID_LOG_EVENT:
|
|
|
|
{
|
|
|
|
Gtid_log_event* gev= (Gtid_log_event*)ev;
|
|
|
|
if (gev->get_gno() == 0)
|
|
|
|
{
|
|
|
|
/* Skip GTID log event to make binlog to generate LTID on commit */
|
|
|
|
delete ev;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* GTID_SUPPORT */
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-14 22:05:29 +02:00
|
|
|
/* Use the original server id for logging. */
|
|
|
|
thd->set_server_id(ev->server_id);
|
|
|
|
thd->set_time(); // time the query
|
2018-08-04 09:52:12 +02:00
|
|
|
thd->transaction.start_time.reset(thd);
|
2014-01-17 12:28:43 +01:00
|
|
|
thd->lex->current_select= 0;
|
|
|
|
if (!ev->when)
|
|
|
|
{
|
|
|
|
my_hrtime_t hrtime= my_hrtime();
|
|
|
|
ev->when= hrtime_to_my_time(hrtime);
|
|
|
|
ev->when_sec_part= hrtime_sec_part(hrtime);
|
|
|
|
}
|
|
|
|
|
2015-07-14 22:05:29 +02:00
|
|
|
thd->variables.option_bits=
|
|
|
|
(thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) |
|
|
|
|
(ev->flags & LOG_EVENT_SKIP_REPLICATION_F ? OPTION_SKIP_REPLICATION : 0);
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
ev->thd= thd;
|
|
|
|
exec_res= ev->apply_event(thd->wsrep_rgi);
|
2014-01-17 12:28:43 +01:00
|
|
|
DBUG_PRINT("info", ("exec_event result: %d", exec_res));
|
|
|
|
|
|
|
|
if (exec_res)
|
|
|
|
{
|
2019-01-23 12:30:00 +01:00
|
|
|
WSREP_WARN("Event %d %s apply failed: %d, seqno %lld",
|
2014-01-17 12:28:43 +01:00
|
|
|
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++;
|
|
|
|
|
2015-07-14 22:05:29 +02:00
|
|
|
delete_or_keep_event_post_apply(thd->wsrep_rgi, typ, ev);
|
2014-01-17 12:28:43 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
error:
|
2014-01-17 12:28:43 +01:00
|
|
|
if (thd->killed == KILL_CONNECTION)
|
|
|
|
WSREP_INFO("applier aborted: %lld", (long long)wsrep_thd_trx_seqno(thd));
|
|
|
|
|
|
|
|
wsrep_set_apply_format(thd, NULL);
|
|
|
|
|
2019-01-23 12:30:00 +01:00
|
|
|
DBUG_RETURN(rcode);
|
2014-01-17 12:28:43 +01:00
|
|
|
}
|