mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
db21fddc37
Implement a new mode for parallel replication. In this mode, all transactions are optimistically attempted applied in parallel. In case of conflicts, the offending transaction is rolled back and retried later non-parallel. This is an early-release patch to facilitate testing, more changes to user interface / options will be expected. The new mode is not enabled by default.
856 lines
27 KiB
C++
856 lines
27 KiB
C++
/* Copyright (c) 2005, 2012, Oracle and/or its affiliates.
|
|
|
|
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 */
|
|
|
|
#ifndef RPL_RLI_H
|
|
#define RPL_RLI_H
|
|
|
|
#include "rpl_tblmap.h"
|
|
#include "rpl_reporting.h"
|
|
#include "rpl_utility.h"
|
|
#include "log.h" /* LOG_INFO, MYSQL_BIN_LOG */
|
|
#include "sql_class.h" /* THD */
|
|
#include "log_event.h"
|
|
#include "rpl_parallel.h"
|
|
|
|
struct RPL_TABLE_LIST;
|
|
class Master_info;
|
|
class Rpl_filter;
|
|
|
|
|
|
enum {
|
|
LINES_IN_RELAY_LOG_INFO_WITH_DELAY= 5
|
|
};
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Replication SQL Thread
|
|
|
|
Relay_log_info contains:
|
|
- the current relay log
|
|
- the current relay log offset
|
|
- master log name
|
|
- master log sequence corresponding to the last update
|
|
- misc information specific to the SQL thread
|
|
|
|
Relay_log_info is initialized from the slave.info file if such
|
|
exists. Otherwise, data members are intialized with defaults. The
|
|
initialization is done with init_relay_log_info() call.
|
|
|
|
The format of slave.info file:
|
|
|
|
relay_log_name
|
|
relay_log_pos
|
|
master_log_name
|
|
master_log_pos
|
|
|
|
To clean up, call end_relay_log_info()
|
|
|
|
*****************************************************************************/
|
|
|
|
struct rpl_group_info;
|
|
struct inuse_relaylog;
|
|
|
|
class Relay_log_info : public Slave_reporting_capability
|
|
{
|
|
public:
|
|
/**
|
|
Flags for the state of reading the relay log. Note that these are
|
|
bit masks.
|
|
*/
|
|
enum enum_state_flag {
|
|
/** We are inside a group of events forming a statement */
|
|
IN_STMT=1,
|
|
/** We have inside a transaction */
|
|
IN_TRANSACTION=2
|
|
};
|
|
|
|
/*
|
|
If flag set, then rli does not store its state in any info file.
|
|
This is the case only when we execute BINLOG SQL commands inside
|
|
a client, non-replication thread.
|
|
*/
|
|
bool no_storage;
|
|
|
|
/*
|
|
If true, events with the same server id should be replicated. This
|
|
field is set on creation of a relay log info structure by copying
|
|
the value of ::replicate_same_server_id and can be overridden if
|
|
necessary. For example of when this is done, check sql_binlog.cc,
|
|
where the BINLOG statement can be used to execute "raw" events.
|
|
*/
|
|
bool replicate_same_server_id;
|
|
|
|
/*** The following variables can only be read when protect by data lock ****/
|
|
|
|
/*
|
|
info_fd - file descriptor of the info file. set only during
|
|
initialization or clean up - safe to read anytime
|
|
cur_log_fd - file descriptor of the current read relay log
|
|
*/
|
|
File info_fd,cur_log_fd;
|
|
|
|
/*
|
|
Protected with internal locks.
|
|
Must get data_lock when resetting the logs.
|
|
*/
|
|
MYSQL_BIN_LOG relay_log;
|
|
LOG_INFO linfo;
|
|
|
|
/*
|
|
cur_log
|
|
Pointer that either points at relay_log.get_log_file() or
|
|
&rli->cache_buf, depending on whether the log is hot or there was
|
|
the need to open a cold relay_log.
|
|
|
|
cache_buf
|
|
IO_CACHE used when opening cold relay logs.
|
|
*/
|
|
IO_CACHE cache_buf,*cur_log;
|
|
|
|
/*
|
|
Keeps track of the number of transactions that commits
|
|
before fsyncing. The option --sync-relay-log-info determines
|
|
how many transactions should commit before fsyncing.
|
|
*/
|
|
uint sync_counter;
|
|
|
|
/*
|
|
Identifies when the recovery process is going on.
|
|
See sql/slave.cc:init_recovery for further details.
|
|
*/
|
|
bool is_relay_log_recovery;
|
|
|
|
/* The following variables are safe to read any time */
|
|
|
|
/* IO_CACHE of the info file - set only during init or end */
|
|
IO_CACHE info_file;
|
|
|
|
/*
|
|
List of temporary tables used by this connection.
|
|
This is updated when a temporary table is created or dropped by
|
|
a replication thread.
|
|
|
|
Not reset when replication ends, to allow one to access the tables
|
|
when replication restarts.
|
|
|
|
Protected by data_lock.
|
|
*/
|
|
TABLE *save_temporary_tables;
|
|
|
|
/*
|
|
standard lock acquisition order to avoid deadlocks:
|
|
run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index
|
|
*/
|
|
mysql_mutex_t data_lock, run_lock;
|
|
/*
|
|
start_cond is broadcast when SQL thread is started
|
|
stop_cond - when stopped
|
|
data_cond - when data protected by data_lock changes
|
|
*/
|
|
mysql_cond_t start_cond, stop_cond, data_cond;
|
|
/* parent Master_info structure */
|
|
Master_info *mi;
|
|
|
|
/*
|
|
List of active relay log files.
|
|
(This can be more than one in case of parallel replication).
|
|
*/
|
|
inuse_relaylog *inuse_relaylog_list;
|
|
inuse_relaylog *last_inuse_relaylog;
|
|
|
|
/*
|
|
Needed to deal properly with cur_log getting closed and re-opened with
|
|
a different log under our feet
|
|
*/
|
|
uint32 cur_log_old_open_count;
|
|
|
|
/*
|
|
Let's call a group (of events) :
|
|
- a transaction
|
|
or
|
|
- an autocommiting query + its associated events (INSERT_ID,
|
|
TIMESTAMP...)
|
|
We need these rli coordinates :
|
|
- relay log name and position of the beginning of the group we currently
|
|
are executing. Needed to know where we have to restart when replication has
|
|
stopped in the middle of a group (which has been rolled back by the slave).
|
|
- relay log name and position just after the event we have just
|
|
executed. This event is part of the current group.
|
|
Formerly we only had the immediately above coordinates, plus a 'pending'
|
|
variable, but this dealt wrong with the case of a transaction starting on a
|
|
relay log and finishing (commiting) on another relay log. Case which can
|
|
happen when, for example, the relay log gets rotated because of
|
|
max_binlog_size.
|
|
*/
|
|
char group_relay_log_name[FN_REFLEN];
|
|
ulonglong group_relay_log_pos;
|
|
char event_relay_log_name[FN_REFLEN];
|
|
ulonglong event_relay_log_pos;
|
|
ulonglong future_event_relay_log_pos;
|
|
/*
|
|
The master log name for current event. Only used in parallel replication.
|
|
*/
|
|
char future_event_master_log_name[FN_REFLEN];
|
|
|
|
#ifdef HAVE_valgrind
|
|
bool is_fake; /* Mark that this is a fake relay log info structure */
|
|
#endif
|
|
|
|
/*
|
|
Original log name and position of the group we're currently executing
|
|
(whose coordinates are group_relay_log_name/pos in the relay log)
|
|
in the master's binlog. These concern the *group*, because in the master's
|
|
binlog the log_pos that comes with each event is the position of the
|
|
beginning of the group.
|
|
*/
|
|
char group_master_log_name[FN_REFLEN];
|
|
volatile my_off_t group_master_log_pos;
|
|
|
|
/*
|
|
Handling of the relay_log_space_limit optional constraint.
|
|
ignore_log_space_limit is used to resolve a deadlock between I/O and SQL
|
|
threads, the SQL thread sets it to unblock the I/O thread and make it
|
|
temporarily forget about the constraint.
|
|
*/
|
|
ulonglong log_space_limit,log_space_total;
|
|
bool ignore_log_space_limit;
|
|
|
|
/*
|
|
Used by the SQL thread to instructs the IO thread to rotate
|
|
the logs when the SQL thread needs to purge to release some
|
|
disk space.
|
|
*/
|
|
bool sql_force_rotate_relay;
|
|
|
|
time_t last_master_timestamp;
|
|
/*
|
|
The SQL driver thread sets this true while it is waiting at the end of the
|
|
relay log for more events to arrive. SHOW SLAVE STATUS uses this to report
|
|
Seconds_Behind_Master as zero while the SQL thread is so waiting.
|
|
*/
|
|
bool sql_thread_caught_up;
|
|
|
|
void clear_until_condition();
|
|
|
|
/*
|
|
Needed for problems when slave stops and we want to restart it
|
|
skipping one or more events in the master log that have caused
|
|
errors, and have been manually applied by DBA already.
|
|
Must be ulong as it's refered to from set_var.cc
|
|
*/
|
|
volatile ulonglong slave_skip_counter;
|
|
ulonglong max_relay_log_size;
|
|
|
|
volatile ulong abort_pos_wait; /* Incremented on change master */
|
|
volatile ulong slave_run_id; /* Incremented on slave start */
|
|
mysql_mutex_t log_space_lock;
|
|
mysql_cond_t log_space_cond;
|
|
/*
|
|
THD for the main sql thread, the one that starts threads to process
|
|
slave requests. If there is only one thread, then this THD is also
|
|
used for SQL processing.
|
|
A kill sent to this THD will kill the replication.
|
|
*/
|
|
THD *sql_driver_thd;
|
|
#ifndef DBUG_OFF
|
|
int events_till_abort;
|
|
#endif
|
|
|
|
/*
|
|
inited changes its value within LOCK_active_mi-guarded critical
|
|
sections at times of start_slave_threads() (0->1) and end_slave() (1->0).
|
|
Readers may not acquire the mutex while they realize potential concurrency
|
|
issue.
|
|
If not set, the value of other members of the structure are undefined.
|
|
*/
|
|
volatile bool inited;
|
|
volatile bool abort_slave;
|
|
volatile bool stop_for_until;
|
|
volatile uint slave_running;
|
|
|
|
/*
|
|
Condition and its parameters from START SLAVE UNTIL clause.
|
|
|
|
UNTIL condition is tested with is_until_satisfied() method that is
|
|
called by exec_relay_log_event(). is_until_satisfied() caches the result
|
|
of the comparison of log names because log names don't change very often;
|
|
this cache is invalidated by parts of code which change log names with
|
|
notify_*_log_name_updated() methods. (They need to be called only if SQL
|
|
thread is running).
|
|
*/
|
|
|
|
enum {
|
|
UNTIL_NONE= 0, UNTIL_MASTER_POS, UNTIL_RELAY_POS, UNTIL_GTID
|
|
} until_condition;
|
|
char until_log_name[FN_REFLEN];
|
|
ulonglong until_log_pos;
|
|
/* extension extracted from log_name and converted to int */
|
|
ulong until_log_name_extension;
|
|
/*
|
|
Cached result of comparison of until_log_name and current log name
|
|
-2 means unitialised, -1,0,1 are comarison results
|
|
*/
|
|
enum
|
|
{
|
|
UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1,
|
|
UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1
|
|
} until_log_names_cmp_result;
|
|
/* Condition for UNTIL master_gtid_pos. */
|
|
slave_connection_state until_gtid_pos;
|
|
|
|
/*
|
|
retried_trans is a cumulative counter: how many times the slave
|
|
has retried a transaction (any) since slave started.
|
|
Protected by data_lock.
|
|
*/
|
|
ulong retried_trans;
|
|
/*
|
|
Number of executed events for SLAVE STATUS.
|
|
Protected by slave_executed_entries_lock
|
|
*/
|
|
int64 executed_entries;
|
|
|
|
/*
|
|
If the end of the hot relay log is made of master's events ignored by the
|
|
slave I/O thread, these two keep track of the coords (in the master's
|
|
binlog) of the last of these events seen by the slave I/O thread. If not,
|
|
ign_master_log_name_end[0] == 0.
|
|
As they are like a Rotate event read/written from/to the relay log, they
|
|
are both protected by rli->relay_log.LOCK_log.
|
|
*/
|
|
char ign_master_log_name_end[FN_REFLEN];
|
|
ulonglong ign_master_log_pos_end;
|
|
/* Similar for ignored GTID events. */
|
|
slave_connection_state ign_gtids;
|
|
|
|
/*
|
|
Indentifies where the SQL Thread should create temporary files for the
|
|
LOAD DATA INFILE. This is used for security reasons.
|
|
*/
|
|
char slave_patternload_file[FN_REFLEN];
|
|
size_t slave_patternload_file_size;
|
|
|
|
rpl_parallel parallel;
|
|
|
|
Relay_log_info(bool is_slave_recovery);
|
|
~Relay_log_info();
|
|
|
|
/*
|
|
Invalidate cached until_log_name and group_relay_log_name comparison
|
|
result. Should be called after any update of group_realy_log_name if
|
|
there chances that sql_thread is running.
|
|
*/
|
|
inline void notify_group_relay_log_name_update()
|
|
{
|
|
if (until_condition==UNTIL_RELAY_POS)
|
|
until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
|
|
}
|
|
|
|
/*
|
|
The same as previous but for group_master_log_name.
|
|
*/
|
|
inline void notify_group_master_log_name_update()
|
|
{
|
|
if (until_condition==UNTIL_MASTER_POS)
|
|
until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
|
|
}
|
|
|
|
void inc_group_relay_log_pos(ulonglong log_pos,
|
|
rpl_group_info *rgi,
|
|
bool skip_lock=0);
|
|
|
|
int wait_for_pos(THD* thd, String* log_name, longlong log_pos,
|
|
longlong timeout);
|
|
void close_temporary_tables();
|
|
|
|
/* Check if UNTIL condition is satisfied. See slave.cc for more. */
|
|
bool is_until_satisfied(THD *thd, Log_event *ev);
|
|
inline ulonglong until_pos()
|
|
{
|
|
DBUG_ASSERT(until_condition == UNTIL_MASTER_POS ||
|
|
until_condition == UNTIL_RELAY_POS);
|
|
return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos :
|
|
group_relay_log_pos);
|
|
}
|
|
|
|
/**
|
|
Helper function to do after statement completion.
|
|
|
|
This function is called from an event to complete the group by
|
|
either stepping the group position, if the "statement" is not
|
|
inside a transaction; or increase the event position, if the
|
|
"statement" is inside a transaction.
|
|
|
|
@param event_log_pos
|
|
Master log position of the event. The position is recorded in the
|
|
relay log info and used to produce information for <code>SHOW
|
|
SLAVE STATUS</code>.
|
|
|
|
@param event_creation_time
|
|
Timestamp for the creation of the event on the master side. The
|
|
time stamp is recorded in the relay log info and used to compute
|
|
the <code>Seconds_behind_master</code> field.
|
|
*/
|
|
void stmt_done(my_off_t event_log_pos,
|
|
time_t event_creation_time, THD *thd,
|
|
rpl_group_info *rgi);
|
|
int alloc_inuse_relaylog(const char *name);
|
|
|
|
/**
|
|
Is the replication inside a group?
|
|
|
|
The reader of the relay log is inside a group if either:
|
|
- The IN_TRANSACTION flag is set, meaning we're inside a transaction
|
|
- The IN_STMT flag is set, meaning we have read at least one row from
|
|
a multi-event entry.
|
|
|
|
This flag reflects the state of the log 'just now', ie after the last
|
|
read event would be executed.
|
|
This allow us to test if we can stop replication before reading
|
|
the next entry.
|
|
|
|
@retval true Replication thread is currently inside a group
|
|
@retval false Replication thread is currently not inside a group
|
|
*/
|
|
bool is_in_group() const {
|
|
return (m_flags & (IN_STMT | IN_TRANSACTION));
|
|
}
|
|
|
|
/**
|
|
Set the value of a replication state flag.
|
|
|
|
@param flag Flag to set
|
|
*/
|
|
void set_flag(enum_state_flag flag)
|
|
{
|
|
m_flags|= flag;
|
|
}
|
|
|
|
/**
|
|
Get the value of a replication state flag.
|
|
|
|
@param flag Flag to get value of
|
|
|
|
@return @c true if the flag was set, @c false otherwise.
|
|
*/
|
|
bool get_flag(enum_state_flag flag)
|
|
{
|
|
return m_flags & flag;
|
|
}
|
|
|
|
/**
|
|
Clear the value of a replication state flag.
|
|
|
|
@param flag Flag to clear
|
|
*/
|
|
void clear_flag(enum_state_flag flag)
|
|
{
|
|
m_flags&= ~flag;
|
|
}
|
|
|
|
private:
|
|
|
|
/*
|
|
Holds the state of the data in the relay log.
|
|
We need this to ensure that we are not in the middle of a
|
|
statement or inside BEGIN ... COMMIT when should rotate the
|
|
relay log.
|
|
*/
|
|
uint32 m_flags;
|
|
};
|
|
|
|
|
|
/*
|
|
In parallel replication, if we need to re-try a transaction due to a
|
|
deadlock or other temporary error, we may need to go back and re-read events
|
|
out of an earlier relay log.
|
|
|
|
This structure keeps track of the relaylogs that are potentially in use.
|
|
Each rpl_group_info has a pointer to one of those, corresponding to the
|
|
first GTID event.
|
|
|
|
A pair of reference count keeps track of how long a relay log is potentially
|
|
in use. When the `completed' flag is set, all events have been read out of
|
|
the relay log, but the log might still be needed for retry in worker
|
|
threads. As worker threads complete an event group, they increment
|
|
atomically the `dequeued_count' with number of events queued. Thus, when
|
|
completed is set and dequeued_count equals queued_count, the relay log file
|
|
is finally done with and can be purged.
|
|
|
|
By separating the queued and dequeued count, only the dequeued_count needs
|
|
multi-thread synchronisation; the completed flag and queued_count fields
|
|
are only accessed by the SQL driver thread and need no synchronisation.
|
|
*/
|
|
struct inuse_relaylog {
|
|
inuse_relaylog *next;
|
|
Relay_log_info *rli;
|
|
/* Number of events in this relay log queued for worker threads. */
|
|
int64 queued_count;
|
|
/* Number of events completed by worker threads. */
|
|
volatile int64 dequeued_count;
|
|
/* Set when all events have been read from a relaylog. */
|
|
bool completed;
|
|
char name[FN_REFLEN];
|
|
/* Lock used to protect inuse_relaylog::dequeued_count */
|
|
my_atomic_rwlock_t inuse_relaylog_atomic_lock;
|
|
};
|
|
|
|
|
|
/*
|
|
This is data for various state needed to be kept for the processing of
|
|
one event group (transaction) during replication.
|
|
|
|
In single-threaded replication, there will be one global rpl_group_info and
|
|
one global Relay_log_info per master connection. They will be linked
|
|
together.
|
|
|
|
In parallel replication, there will be one rpl_group_info object for
|
|
each running sql thread, each having their own thd.
|
|
|
|
All rpl_group_info will share the same Relay_log_info.
|
|
*/
|
|
|
|
struct rpl_group_info
|
|
{
|
|
rpl_group_info *next; /* For free list in rpl_parallel_thread */
|
|
Relay_log_info *rli;
|
|
THD *thd;
|
|
/*
|
|
Current GTID being processed.
|
|
The sub_id gives the binlog order within one domain_id. A zero sub_id
|
|
means that there is no active GTID.
|
|
*/
|
|
uint64 gtid_sub_id;
|
|
rpl_gtid current_gtid;
|
|
uint64 commit_id;
|
|
/*
|
|
This is used to keep transaction commit order.
|
|
We will signal this when we commit, and can register it to wait for the
|
|
commit_orderer of the previous commit to signal us.
|
|
*/
|
|
wait_for_commit commit_orderer;
|
|
/*
|
|
If non-zero, the sub_id of a prior event group whose commit we have to wait
|
|
for before committing ourselves. Then wait_commit_group_info points to the
|
|
event group to wait for.
|
|
|
|
Before using this, rpl_parallel_entry::last_committed_sub_id should be
|
|
compared against wait_commit_sub_id. Only if last_committed_sub_id is
|
|
smaller than wait_commit_sub_id must the wait be done (otherwise the
|
|
waited-for transaction is already committed, so we would otherwise wait
|
|
for the wrong commit).
|
|
*/
|
|
uint64 wait_commit_sub_id;
|
|
rpl_group_info *wait_commit_group_info;
|
|
/*
|
|
This holds a pointer to a struct that keeps track of the need to wait
|
|
for the previous batch of event groups to reach the commit stage, before
|
|
this batch can start to execute.
|
|
|
|
(When we execute in parallel the transactions that group committed
|
|
together on the master, we still need to wait for any prior transactions
|
|
to have reached the commit stage).
|
|
*/
|
|
group_commit_orderer *gco;
|
|
|
|
struct rpl_parallel_entry *parallel_entry;
|
|
|
|
/*
|
|
A container to hold on Intvar-, Rand-, Uservar- log-events in case
|
|
the slave is configured with table filtering rules.
|
|
The withhold events are executed when their parent Query destiny is
|
|
determined for execution as well.
|
|
*/
|
|
Deferred_log_events *deferred_events;
|
|
|
|
/*
|
|
State of the container: true stands for IRU events gathering,
|
|
false does for execution, either deferred or direct.
|
|
*/
|
|
bool deferred_events_collecting;
|
|
|
|
Annotate_rows_log_event *m_annotate_event;
|
|
|
|
RPL_TABLE_LIST *tables_to_lock; /* RBR: Tables to lock */
|
|
uint tables_to_lock_count; /* RBR: Count of tables to lock */
|
|
table_mapping m_table_map; /* RBR: Mapping table-id to table */
|
|
mysql_mutex_t sleep_lock;
|
|
mysql_cond_t sleep_cond;
|
|
|
|
/*
|
|
trans_retries varies between 0 to slave_transaction_retries and counts how
|
|
many times the slave has retried the present transaction; gets reset to 0
|
|
when the transaction finally succeeds.
|
|
*/
|
|
ulong trans_retries;
|
|
|
|
/*
|
|
Used to defer stopping the SQL thread to give it a chance
|
|
to finish up the current group of events.
|
|
The timestamp is set and reset in @c sql_slave_killed().
|
|
*/
|
|
time_t last_event_start_time;
|
|
|
|
char *event_relay_log_name;
|
|
char event_relay_log_name_buf[FN_REFLEN];
|
|
ulonglong event_relay_log_pos;
|
|
ulonglong future_event_relay_log_pos;
|
|
/*
|
|
The master log name for current event. Only used in parallel replication.
|
|
*/
|
|
char future_event_master_log_name[FN_REFLEN];
|
|
bool is_parallel_exec;
|
|
/* When gtid_pending is true, we have not yet done record_gtid(). */
|
|
bool gtid_pending;
|
|
int worker_error;
|
|
/*
|
|
Set true when we signalled that we reach the commit phase. Used to avoid
|
|
counting one event group twice.
|
|
*/
|
|
bool did_mark_start_commit;
|
|
/* Copy of flags2 from GTID event. */
|
|
uchar gtid_ev_flags2;
|
|
enum {
|
|
GTID_DUPLICATE_NULL=0,
|
|
GTID_DUPLICATE_IGNORE=1,
|
|
GTID_DUPLICATE_OWNER=2
|
|
};
|
|
/*
|
|
When --gtid-ignore-duplicates, this is set to one of the above three
|
|
values:
|
|
GTID_DUPLICATE_NULL - Not using --gtid-ignore-duplicates.
|
|
GTID_DUPLICATE_IGNORE - This gtid already applied, skip the event group.
|
|
GTID_DUPLICATE_OWNER - We are the current owner of the domain, and must
|
|
apply the event group and then release the domain.
|
|
*/
|
|
uint8 gtid_ignore_duplicate_state;
|
|
|
|
/*
|
|
Runtime state for printing a note when slave is taking
|
|
too long while processing a row event.
|
|
*/
|
|
time_t row_stmt_start_timestamp;
|
|
bool long_find_row_note_printed;
|
|
/* Needs room for "Gtid D-S-N\x00". */
|
|
char gtid_info_buf[5+10+1+10+1+20+1];
|
|
|
|
/*
|
|
Information to be able to re-try an event group in case of a deadlock or
|
|
other temporary error.
|
|
*/
|
|
inuse_relaylog *relay_log;
|
|
uint64 retry_start_offset;
|
|
uint64 retry_event_count;
|
|
/*
|
|
If `speculation' is != SPECULATE_NO, then we are optimistically running
|
|
this transaction in parallel, even though it might not be safe (there may
|
|
be a conflict with a prior event group).
|
|
|
|
In this case, a conflict can cause other errors than deadlocks (like
|
|
duplicate key for example). So in case of _any_ error, we need to roll
|
|
back and retry the event group.
|
|
*/
|
|
enum enum_speculation {
|
|
/*
|
|
This transaction was group-committed together on the master with the
|
|
other transactions with which it is replicated in parallel.
|
|
*/
|
|
SPECULATE_NO,
|
|
/*
|
|
We will optimistically try to run this transaction in parallel with
|
|
other transactions, even though it is not known to be conflict free.
|
|
If we get a conflict, we will detect it as a deadlock, roll back and
|
|
retry.
|
|
*/
|
|
SPECULATE_OPTIMISTIC,
|
|
/*
|
|
This transaction got a conflict during speculative parallel apply, or
|
|
it was marked on the master as likely to cause a conflict or unsafe to
|
|
speculate. So it will wait for the prior transaction to commit before
|
|
starting to replicate.
|
|
*/
|
|
SPECULATE_WAIT
|
|
} speculation;
|
|
bool killed_for_retry;
|
|
|
|
rpl_group_info(Relay_log_info *rli_);
|
|
~rpl_group_info();
|
|
void reinit(Relay_log_info *rli);
|
|
|
|
/*
|
|
Returns true if the argument event resides in the containter;
|
|
more specifically, the checking is done against the last added event.
|
|
*/
|
|
bool is_deferred_event(Log_event * ev)
|
|
{
|
|
return deferred_events_collecting ? deferred_events->is_last(ev) : false;
|
|
};
|
|
/* The general cleanup that slave applier may need at the end of query. */
|
|
inline void cleanup_after_query()
|
|
{
|
|
if (deferred_events)
|
|
deferred_events->rewind();
|
|
};
|
|
/* The general cleanup that slave applier may need at the end of session. */
|
|
void cleanup_after_session()
|
|
{
|
|
if (deferred_events)
|
|
{
|
|
delete deferred_events;
|
|
deferred_events= NULL;
|
|
}
|
|
};
|
|
|
|
/**
|
|
Save pointer to Annotate_rows event and switch on the
|
|
binlog_annotate_row_events for this sql thread.
|
|
To be called when sql thread recieves an Annotate_rows event.
|
|
*/
|
|
inline void set_annotate_event(Annotate_rows_log_event *event)
|
|
{
|
|
free_annotate_event();
|
|
m_annotate_event= event;
|
|
this->thd->variables.binlog_annotate_row_events= 1;
|
|
}
|
|
|
|
/**
|
|
Returns pointer to the saved Annotate_rows event or NULL if there is
|
|
no saved event.
|
|
*/
|
|
inline Annotate_rows_log_event* get_annotate_event()
|
|
{
|
|
return m_annotate_event;
|
|
}
|
|
|
|
/**
|
|
Delete saved Annotate_rows event (if any) and switch off the
|
|
binlog_annotate_row_events for this sql thread.
|
|
To be called when sql thread has applied the last (i.e. with
|
|
STMT_END_F flag) rbr event.
|
|
*/
|
|
inline void free_annotate_event()
|
|
{
|
|
if (m_annotate_event)
|
|
{
|
|
this->thd->variables.binlog_annotate_row_events= 0;
|
|
delete m_annotate_event;
|
|
m_annotate_event= 0;
|
|
}
|
|
}
|
|
|
|
bool get_table_data(TABLE *table_arg, table_def **tabledef_var, TABLE **conv_table_var) const
|
|
{
|
|
DBUG_ASSERT(tabledef_var && conv_table_var);
|
|
for (TABLE_LIST *ptr= tables_to_lock ; ptr != NULL ; ptr= ptr->next_global)
|
|
if (ptr->table == table_arg)
|
|
{
|
|
*tabledef_var= &static_cast<RPL_TABLE_LIST*>(ptr)->m_tabledef;
|
|
*conv_table_var= static_cast<RPL_TABLE_LIST*>(ptr)->m_conv_table;
|
|
DBUG_PRINT("debug", ("Fetching table data for table %s.%s:"
|
|
" tabledef: %p, conv_table: %p",
|
|
table_arg->s->db.str, table_arg->s->table_name.str,
|
|
*tabledef_var, *conv_table_var));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void clear_tables_to_lock();
|
|
void cleanup_context(THD *, bool);
|
|
void slave_close_thread_tables(THD *);
|
|
void mark_start_commit_no_lock();
|
|
void mark_start_commit();
|
|
char *gtid_info();
|
|
void unmark_start_commit();
|
|
|
|
time_t get_row_stmt_start_timestamp()
|
|
{
|
|
return row_stmt_start_timestamp;
|
|
}
|
|
|
|
time_t set_row_stmt_start_timestamp()
|
|
{
|
|
if (row_stmt_start_timestamp == 0)
|
|
row_stmt_start_timestamp= my_time(0);
|
|
|
|
return row_stmt_start_timestamp;
|
|
}
|
|
|
|
void reset_row_stmt_start_timestamp()
|
|
{
|
|
row_stmt_start_timestamp= 0;
|
|
}
|
|
|
|
void set_long_find_row_note_printed()
|
|
{
|
|
long_find_row_note_printed= true;
|
|
}
|
|
|
|
void unset_long_find_row_note_printed()
|
|
{
|
|
long_find_row_note_printed= false;
|
|
}
|
|
|
|
bool is_long_find_row_note_printed()
|
|
{
|
|
return long_find_row_note_printed;
|
|
}
|
|
|
|
inline void inc_event_relay_log_pos()
|
|
{
|
|
if (!is_parallel_exec)
|
|
rli->event_relay_log_pos= future_event_relay_log_pos;
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
The class rpl_sql_thread_info is the THD::system_thread_info for an SQL
|
|
thread; this is either the driver SQL thread or a worker thread for parallel
|
|
replication.
|
|
*/
|
|
class rpl_sql_thread_info
|
|
{
|
|
public:
|
|
char cached_charset[6];
|
|
Rpl_filter* rpl_filter;
|
|
|
|
rpl_sql_thread_info(Rpl_filter *filter);
|
|
|
|
/*
|
|
Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
|
|
the thread save 3 get_charset() per Query_log_event if the charset is not
|
|
changing from event to event (common situation).
|
|
When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
|
|
*/
|
|
void cached_charset_invalidate();
|
|
bool cached_charset_compare(char *charset) const;
|
|
};
|
|
|
|
|
|
// Defined in rpl_rli.cc
|
|
int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
|
|
|
|
|
|
extern struct rpl_slave_state rpl_global_gtid_slave_state;
|
|
extern gtid_waiting rpl_global_gtid_waiting;
|
|
|
|
int rpl_load_gtid_slave_state(THD *thd);
|
|
int event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev);
|
|
void delete_or_keep_event_post_apply(rpl_group_info *rgi,
|
|
Log_event_type typ, Log_event *ev);
|
|
|
|
#endif /* RPL_RLI_H */
|