mysql5/mysql-5.7.27/sql/rpl_context.cc

187 lines
5.4 KiB
C++

/* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
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 St, Fifth Floor, Boston, MA
02110-1301 USA */
#include "rpl_context.h"
#include "rpl_gtid.h" // Gtid_set
#include "sql_class.h" // THD
Session_consistency_gtids_ctx::Session_consistency_gtids_ctx() :
m_sid_map(NULL), m_gtid_set(NULL), m_listener(NULL),
m_curr_session_track_gtids(OFF)
{ }
Session_consistency_gtids_ctx::~Session_consistency_gtids_ctx()
{
if (m_gtid_set)
{
delete m_gtid_set;
m_gtid_set= NULL;
}
if (m_sid_map)
{
delete m_sid_map;
m_sid_map= NULL;
}
}
inline bool Session_consistency_gtids_ctx::shall_collect(const THD* thd)
{
return /* Do not track OWN_GTID if session does not own a
(non-anonymous) GTID. */
(thd->owned_gtid.sidno > 0 ||
m_curr_session_track_gtids == ALL_GTIDS) &&
/* if there is no listener/tracker, then there is no reason to collect */
m_listener != NULL &&
/* ROLLBACK statements may end up calling trans_commit_stmt */
thd->lex->sql_command != SQLCOM_ROLLBACK &&
thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT;
}
bool Session_consistency_gtids_ctx::notify_after_transaction_commit(const THD* thd)
{
DBUG_ENTER("Rpl_consistency_ctx::notify_after_transaction_commit");
DBUG_ASSERT(thd);
bool res= false;
if (!shall_collect(thd))
DBUG_RETURN(res);
if (m_curr_session_track_gtids == ALL_GTIDS)
{
/*
If one is configured to read all writes, we always collect
the GTID_EXECUTED.
NOTE: in the future optimize to collect deltas instead maybe.
*/
global_sid_lock->wrlock();
res= m_gtid_set->add_gtid_set(gtid_state->get_executed_gtids()) != RETURN_STATUS_OK;
global_sid_lock->unlock();
if (!res)
notify_ctx_change_listener();
}
DBUG_RETURN(res);
}
bool Session_consistency_gtids_ctx::notify_after_gtid_executed_update(const THD *thd)
{
DBUG_ENTER("Rpl_consistency_ctx::notify_after_gtid_executed_update");
DBUG_ASSERT(thd);
bool res= false;
if (!shall_collect(thd))
DBUG_RETURN(res);
if (m_curr_session_track_gtids == OWN_GTID)
{
DBUG_ASSERT(get_gtid_mode(GTID_MODE_LOCK_SID) != GTID_MODE_OFF);
DBUG_ASSERT(thd->owned_gtid.sidno > 0);
const Gtid& gtid= thd->owned_gtid;
if (gtid.sidno == -1) // we need to add thd->owned_gtid_set
{
/* Caller must only call this function if the set was not empty. */
#ifdef HAVE_GTID_NEXT_LIST
DBUG_ASSERT(!thd->owned_gtid_set.is_empty());
res= m_gtid_set->add_gtid_set(&thd->owned_gtid_set) != RETURN_STATUS_OK;
#else
DBUG_ASSERT(0);
#endif
}
else if (gtid.sidno > 0) // only one gtid
{
/*
Note that the interface is such that m_sid_map must contain
sidno before we add the gtid to m_gtid_set.
Thus, to avoid relying on global_sid_map and thus contributing
to increased contention, we arrange for sidnos on the local
sid map.
*/
rpl_sidno local_set_sidno= m_sid_map->add_sid(thd->owned_sid);
DBUG_ASSERT(!m_gtid_set->contains_gtid(local_set_sidno, gtid.gno));
res= m_gtid_set->ensure_sidno(local_set_sidno) != RETURN_STATUS_OK;
if (!res)
m_gtid_set->_add_gtid(local_set_sidno, gtid.gno);
}
if (!res)
notify_ctx_change_listener();
}
DBUG_RETURN(res);
}
bool Session_consistency_gtids_ctx::notify_after_response_packet(const THD *thd)
{
int res= false;
DBUG_ENTER("Rpl_consistency_ctx::notify_after_response_packet");
if (m_gtid_set && !m_gtid_set->is_empty())
m_gtid_set->clear();
/*
Every time we get a notification that a packet was sent, we update
this value. It may have changed (the previous command may have been
a SET SESSION session_track_gtids=...;).
*/
m_curr_session_track_gtids= thd->variables.session_track_gtids;
DBUG_RETURN(res);
}
void
Session_consistency_gtids_ctx::register_ctx_change_listener(
Session_consistency_gtids_ctx::Ctx_change_listener* listener,
THD* thd)
{
DBUG_ASSERT(m_listener == NULL || m_listener == listener);
if (m_listener == NULL)
{
DBUG_ASSERT(m_sid_map == NULL && m_gtid_set == NULL);
m_listener= listener;
m_sid_map= new Sid_map(NULL);
m_gtid_set= new Gtid_set(m_sid_map);
/*
Caches the value at startup if needed. This is called during THD::init,
if the session_track_gtids value is set at startup time to anything
different than OFF.
*/
m_curr_session_track_gtids= thd->variables.session_track_gtids;
}
}
void Session_consistency_gtids_ctx::unregister_ctx_change_listener(
Session_consistency_gtids_ctx::Ctx_change_listener* listener)
{
DBUG_ASSERT(m_listener == listener || m_listener == NULL);
if (m_gtid_set)
delete m_gtid_set;
if (m_sid_map)
delete m_sid_map;
m_listener= NULL;
m_gtid_set= NULL;
m_sid_map= NULL;
}