2013-03-11 16:02:40 +01:00
|
|
|
/* Copyright (c) 2013, Kristian Nielsen and MariaDB Services Ab.
|
2022-05-14 13:02:51 +03:00
|
|
|
Copyright (c) 2020, 2022, MariaDB Corporation.
|
2013-03-11 16:02:40 +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
|
2019-05-11 22:19:05 +03:00
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* Definitions for MariaDB global transaction ID (GTID). */
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
#include <type_traits>
|
2013-03-11 16:02:40 +01:00
|
|
|
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
#ifndef MYSQL_CLIENT
|
2017-06-18 06:42:16 +03:00
|
|
|
#include "mariadb.h"
|
2013-03-11 16:02:40 +01:00
|
|
|
#include "sql_priv.h"
|
|
|
|
#include "unireg.h"
|
2017-06-18 06:42:16 +03:00
|
|
|
#include "mariadb.h"
|
2013-03-11 16:02:40 +01:00
|
|
|
#include "sql_base.h"
|
|
|
|
#include "sql_parse.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "rpl_rli.h"
|
2017-03-24 12:07:07 +01:00
|
|
|
#include "slave.h"
|
2017-09-29 21:56:59 +03:00
|
|
|
#include "log_event.h"
|
2023-06-20 14:57:04 +03:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
#include "wsrep_mysqld.h" // wsrep_thd_is_local
|
|
|
|
#include "wsrep_trans_observer.h" // wsrep_start_trx_if_not_started
|
|
|
|
#endif
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2018-01-07 18:03:44 +02:00
|
|
|
const LEX_CSTRING rpl_gtid_slave_state_table_name=
|
|
|
|
{ STRING_WITH_LEN("gtid_slave_pos") };
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
void
|
2017-03-09 13:27:27 +01:00
|
|
|
rpl_slave_state::update_state_hash(uint64 sub_id, rpl_gtid *gtid, void *hton,
|
2014-03-12 00:14:49 +01:00
|
|
|
rpl_group_info *rgi)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
/*
|
|
|
|
Add the gtid to the HASH in the replication slave state.
|
|
|
|
|
|
|
|
We must do this only _after_ commit, so that for parallel replication,
|
|
|
|
there will not be an attempt to delete the corresponding table row before
|
|
|
|
it is even committed.
|
|
|
|
*/
|
2017-03-09 13:27:27 +01:00
|
|
|
err= update(gtid->domain_id, gtid->server_id, sub_id, gtid->seq_no, hton, rgi);
|
2013-03-11 16:02:40 +01:00
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
sql_print_warning("Slave: Out of memory during slave state maintenance. "
|
|
|
|
"Some no longer necessary rows in table "
|
2013-03-11 16:16:55 +01:00
|
|
|
"mysql.%s may be left undeleted.",
|
|
|
|
rpl_gtid_slave_state_table_name.str);
|
2013-03-11 16:02:40 +01:00
|
|
|
/*
|
|
|
|
Such failure is not fatal. We will fail to delete the row for this
|
|
|
|
GTID, but it will do no harm and will be removed automatically on next
|
|
|
|
server restart.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2013-09-13 15:09:57 +02:00
|
|
|
rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
DBUG_ENTER("rpl_slave_state::record_and_update_gtid");
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Update the GTID position, if we have it and did not already update
|
|
|
|
it in a GTID transaction.
|
|
|
|
*/
|
MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel
replication causing replication to fail.
Remove the temporary fix for MDEV-5914, which used READ COMMITTED for parallel
replication worker threads. Replace it with a better, more selective solution.
The issue is with certain edge cases of InnoDB gap locks, for example between
INSERT and ranged DELETE. It is possible for the gap lock set by the DELETE to
block the INSERT, if the DELETE runs first, while the record lock set by
INSERT does not block the DELETE, if the INSERT runs first. This can cause a
conflict between the two in parallel replication on the slave even though they
ran without conflicts on the master.
With this patch, InnoDB will ask the server layer about the two involved
transactions before blocking on a gap lock. If the server layer tells InnoDB
that the transactions are already fixed wrt. commit order, as they are in
parallel replication, InnoDB will ignore the gap lock and allow the two
transactions to proceed in parallel, avoiding the conflict.
Improve the fix for MDEV-6020. When InnoDB itself detects a deadlock, it now
asks the server layer for any preferences about which transaction to roll
back. In case of parallel replication with two transactions T1 and T2 fixed to
commit T1 before T2, the server layer will ask InnoDB to roll back T2 as the
deadlock victim, not T1. This helps in some cases to avoid excessive deadlock
rollback, as T2 will in any case need to wait for T1 to complete before it can
itself commit.
Also some misc. fixes found during development and testing:
- Remove thd_rpl_is_parallel(), it is not used or needed.
- Use KILL_CONNECTION instead of KILL_QUERY when a parallel replication
worker thread is killed to resolve a deadlock with fixed commit
ordering. There are some cases, eg. in sql/sql_parse.cc, where a KILL_QUERY
can be ignored if the query otherwise completed successfully, and this
could cause the deadlock kill to be lost, so that the deadlock was not
correctly resolved.
- Fix random test failure due to missing wait_for_binlog_checkpoint.inc.
- Make sure that deadlock or other temporary errors during parallel
replication are not printed to the the error log; there were some places
around the replication code with extra error logging. These conditions can
occur occasionally and are handled automatically without breaking
replication, so they should not pollute the error log.
- Fix handling of rgi->gtid_sub_id. We need to be able to access this also at
the end of a transaction, to be able to detect and resolve deadlocks due to
commit ordering. But this value was also used as a flag to mark whether
record_gtid() had been called, by being set to zero, losing the value. Now,
introduce a separate flag rgi->gtid_pending, so rgi->gtid_sub_id remains
valid for the entire duration of the transaction.
- Fix one place where the code to handle ignored errors called reset_killed()
unconditionally, even if no error was caught that should be ignored. This
could cause loss of a deadlock kill signal, breaking deadlock detection and
resolution.
- Fix a couple of missing mysql_reset_thd_for_next_command(). This could
cause a prior error condition to remain for the next event executed,
causing assertions about errors already being set and possibly giving
incorrect error handling for following event executions.
- Fix code that cleared thd->rgi_slave in the parallel replication worker
threads after each event execution; this caused the deadlock detection and
handling code to not be able to correctly process the associated
transactions as belonging to replication worker threads.
- Remove useless error code in slave_background_kill_request().
- Fix bug where wfc->wakeup_error was not cleared at
wait_for_commit::unregister_wait_for_prior_commit(). This could cause the
error condition to wrongly propagate to a later wait_for_prior_commit(),
causing spurious ER_PRIOR_COMMIT_FAILED errors.
- Do not put the binlog background thread into the processlist. It causes
too many result differences in mtr, but also it probably is not useful
for users to pollute the process list with a system thread that does not
really perform any user-visible tasks...
2014-06-10 10:13:15 +02:00
|
|
|
if (rgi->gtid_pending)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel
replication causing replication to fail.
Remove the temporary fix for MDEV-5914, which used READ COMMITTED for parallel
replication worker threads. Replace it with a better, more selective solution.
The issue is with certain edge cases of InnoDB gap locks, for example between
INSERT and ranged DELETE. It is possible for the gap lock set by the DELETE to
block the INSERT, if the DELETE runs first, while the record lock set by
INSERT does not block the DELETE, if the INSERT runs first. This can cause a
conflict between the two in parallel replication on the slave even though they
ran without conflicts on the master.
With this patch, InnoDB will ask the server layer about the two involved
transactions before blocking on a gap lock. If the server layer tells InnoDB
that the transactions are already fixed wrt. commit order, as they are in
parallel replication, InnoDB will ignore the gap lock and allow the two
transactions to proceed in parallel, avoiding the conflict.
Improve the fix for MDEV-6020. When InnoDB itself detects a deadlock, it now
asks the server layer for any preferences about which transaction to roll
back. In case of parallel replication with two transactions T1 and T2 fixed to
commit T1 before T2, the server layer will ask InnoDB to roll back T2 as the
deadlock victim, not T1. This helps in some cases to avoid excessive deadlock
rollback, as T2 will in any case need to wait for T1 to complete before it can
itself commit.
Also some misc. fixes found during development and testing:
- Remove thd_rpl_is_parallel(), it is not used or needed.
- Use KILL_CONNECTION instead of KILL_QUERY when a parallel replication
worker thread is killed to resolve a deadlock with fixed commit
ordering. There are some cases, eg. in sql/sql_parse.cc, where a KILL_QUERY
can be ignored if the query otherwise completed successfully, and this
could cause the deadlock kill to be lost, so that the deadlock was not
correctly resolved.
- Fix random test failure due to missing wait_for_binlog_checkpoint.inc.
- Make sure that deadlock or other temporary errors during parallel
replication are not printed to the the error log; there were some places
around the replication code with extra error logging. These conditions can
occur occasionally and are handled automatically without breaking
replication, so they should not pollute the error log.
- Fix handling of rgi->gtid_sub_id. We need to be able to access this also at
the end of a transaction, to be able to detect and resolve deadlocks due to
commit ordering. But this value was also used as a flag to mark whether
record_gtid() had been called, by being set to zero, losing the value. Now,
introduce a separate flag rgi->gtid_pending, so rgi->gtid_sub_id remains
valid for the entire duration of the transaction.
- Fix one place where the code to handle ignored errors called reset_killed()
unconditionally, even if no error was caught that should be ignored. This
could cause loss of a deadlock kill signal, breaking deadlock detection and
resolution.
- Fix a couple of missing mysql_reset_thd_for_next_command(). This could
cause a prior error condition to remain for the next event executed,
causing assertions about errors already being set and possibly giving
incorrect error handling for following event executions.
- Fix code that cleared thd->rgi_slave in the parallel replication worker
threads after each event execution; this caused the deadlock detection and
handling code to not be able to correctly process the associated
transactions as belonging to replication worker threads.
- Remove useless error code in slave_background_kill_request().
- Fix bug where wfc->wakeup_error was not cleared at
wait_for_commit::unregister_wait_for_prior_commit(). This could cause the
error condition to wrongly propagate to a later wait_for_prior_commit(),
causing spurious ER_PRIOR_COMMIT_FAILED errors.
- Do not put the binlog background thread into the processlist. It causes
too many result differences in mtr, but also it probably is not useful
for users to pollute the process list with a system thread that does not
really perform any user-visible tasks...
2014-06-10 10:13:15 +02:00
|
|
|
uint64 sub_id= rgi->gtid_sub_id;
|
2017-03-09 13:27:27 +01:00
|
|
|
void *hton= NULL;
|
|
|
|
|
MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel
replication causing replication to fail.
Remove the temporary fix for MDEV-5914, which used READ COMMITTED for parallel
replication worker threads. Replace it with a better, more selective solution.
The issue is with certain edge cases of InnoDB gap locks, for example between
INSERT and ranged DELETE. It is possible for the gap lock set by the DELETE to
block the INSERT, if the DELETE runs first, while the record lock set by
INSERT does not block the DELETE, if the INSERT runs first. This can cause a
conflict between the two in parallel replication on the slave even though they
ran without conflicts on the master.
With this patch, InnoDB will ask the server layer about the two involved
transactions before blocking on a gap lock. If the server layer tells InnoDB
that the transactions are already fixed wrt. commit order, as they are in
parallel replication, InnoDB will ignore the gap lock and allow the two
transactions to proceed in parallel, avoiding the conflict.
Improve the fix for MDEV-6020. When InnoDB itself detects a deadlock, it now
asks the server layer for any preferences about which transaction to roll
back. In case of parallel replication with two transactions T1 and T2 fixed to
commit T1 before T2, the server layer will ask InnoDB to roll back T2 as the
deadlock victim, not T1. This helps in some cases to avoid excessive deadlock
rollback, as T2 will in any case need to wait for T1 to complete before it can
itself commit.
Also some misc. fixes found during development and testing:
- Remove thd_rpl_is_parallel(), it is not used or needed.
- Use KILL_CONNECTION instead of KILL_QUERY when a parallel replication
worker thread is killed to resolve a deadlock with fixed commit
ordering. There are some cases, eg. in sql/sql_parse.cc, where a KILL_QUERY
can be ignored if the query otherwise completed successfully, and this
could cause the deadlock kill to be lost, so that the deadlock was not
correctly resolved.
- Fix random test failure due to missing wait_for_binlog_checkpoint.inc.
- Make sure that deadlock or other temporary errors during parallel
replication are not printed to the the error log; there were some places
around the replication code with extra error logging. These conditions can
occur occasionally and are handled automatically without breaking
replication, so they should not pollute the error log.
- Fix handling of rgi->gtid_sub_id. We need to be able to access this also at
the end of a transaction, to be able to detect and resolve deadlocks due to
commit ordering. But this value was also used as a flag to mark whether
record_gtid() had been called, by being set to zero, losing the value. Now,
introduce a separate flag rgi->gtid_pending, so rgi->gtid_sub_id remains
valid for the entire duration of the transaction.
- Fix one place where the code to handle ignored errors called reset_killed()
unconditionally, even if no error was caught that should be ignored. This
could cause loss of a deadlock kill signal, breaking deadlock detection and
resolution.
- Fix a couple of missing mysql_reset_thd_for_next_command(). This could
cause a prior error condition to remain for the next event executed,
causing assertions about errors already being set and possibly giving
incorrect error handling for following event executions.
- Fix code that cleared thd->rgi_slave in the parallel replication worker
threads after each event execution; this caused the deadlock detection and
handling code to not be able to correctly process the associated
transactions as belonging to replication worker threads.
- Remove useless error code in slave_background_kill_request().
- Fix bug where wfc->wakeup_error was not cleared at
wait_for_commit::unregister_wait_for_prior_commit(). This could cause the
error condition to wrongly propagate to a later wait_for_prior_commit(),
causing spurious ER_PRIOR_COMMIT_FAILED errors.
- Do not put the binlog background thread into the processlist. It causes
too many result differences in mtr, but also it probably is not useful
for users to pollute the process list with a system thread that does not
really perform any user-visible tasks...
2014-06-10 10:13:15 +02:00
|
|
|
rgi->gtid_pending= false;
|
2014-03-12 00:14:49 +01:00
|
|
|
if (rgi->gtid_ignore_duplicate_state!=rpl_group_info::GTID_DUPLICATE_IGNORE)
|
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
if (record_gtid(thd, &rgi->current_gtid, sub_id, false, false, &hton))
|
2014-03-12 00:14:49 +01:00
|
|
|
DBUG_RETURN(1);
|
2017-03-09 13:27:27 +01:00
|
|
|
update_state_hash(sub_id, &rgi->current_gtid, hton, rgi);
|
2014-03-12 00:14:49 +01:00
|
|
|
}
|
|
|
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
DBUG_RETURN(0);
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-09 10:27:38 +01:00
|
|
|
/*
|
|
|
|
Check GTID event execution when --gtid-ignore-duplicates.
|
|
|
|
|
|
|
|
The idea with --gtid-ignore-duplicates is that we allow multiple master
|
|
|
|
connections (in multi-source replication) to all receive the same GTIDs and
|
|
|
|
event groups. Only one instance of each is applied; we use the sequence
|
|
|
|
number in the GTID to decide whether a GTID has already been applied.
|
|
|
|
|
|
|
|
So if the seq_no of a GTID (or a higher sequence number) has already been
|
|
|
|
applied, then the event should be skipped. If not then the event should be
|
|
|
|
applied.
|
|
|
|
|
|
|
|
To avoid two master connections tring to apply the same event
|
|
|
|
simultaneously, only one is allowed to work in any given domain at any point
|
|
|
|
in time. The associated Relay_log_info object is called the owner of the
|
|
|
|
domain (and there can be multiple parallel worker threads working in that
|
|
|
|
domain for that Relay_log_info). Any other Relay_log_info/master connection
|
|
|
|
must wait for the domain to become free, or for their GTID to have been
|
|
|
|
applied, before being allowed to proceed.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
0 This GTID is already applied, it should be skipped.
|
|
|
|
1 The GTID is not yet applied; this rli is now the owner, and must apply
|
|
|
|
the event and release the domain afterwards.
|
|
|
|
-1 Error (out of memory to allocate a new element for the domain).
|
|
|
|
*/
|
|
|
|
int
|
2014-03-12 00:14:49 +01:00
|
|
|
rpl_slave_state::check_duplicate_gtid(rpl_gtid *gtid, rpl_group_info *rgi)
|
2014-03-09 10:27:38 +01:00
|
|
|
{
|
|
|
|
uint32 domain_id= gtid->domain_id;
|
2015-07-19 09:28:22 +02:00
|
|
|
uint64 seq_no= gtid->seq_no;
|
2014-03-09 10:27:38 +01:00
|
|
|
rpl_slave_state::element *elem;
|
|
|
|
int res;
|
2014-06-10 22:20:33 +04:00
|
|
|
bool did_enter_cond= false;
|
2014-03-12 00:14:49 +01:00
|
|
|
PSI_stage_info old_stage;
|
2015-11-23 19:56:03 +02:00
|
|
|
THD *UNINIT_VAR(thd);
|
2014-03-12 00:14:49 +01:00
|
|
|
Relay_log_info *rli= rgi->rli;
|
2014-03-09 10:27:38 +01:00
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
|
|
|
if (!(elem= get_element(domain_id)))
|
|
|
|
{
|
2014-03-12 00:14:49 +01:00
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
2014-03-09 10:27:38 +01:00
|
|
|
res= -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Note that the elem pointer does not change once inserted in the hash. So
|
|
|
|
we can re-use the pointer without looking it up again in the hash after
|
|
|
|
each lock release and re-take.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (elem->highest_seq_no >= seq_no)
|
|
|
|
{
|
|
|
|
/* This sequence number is already applied, ignore it. */
|
|
|
|
res= 0;
|
2014-03-12 00:14:49 +01:00
|
|
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_IGNORE;
|
2014-03-09 10:27:38 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!elem->owner_rli)
|
|
|
|
{
|
|
|
|
/* The domain became free, grab it and apply the event. */
|
|
|
|
elem->owner_rli= rli;
|
|
|
|
elem->owner_count= 1;
|
2014-03-12 00:14:49 +01:00
|
|
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_OWNER;
|
2014-03-09 10:27:38 +01:00
|
|
|
res= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (elem->owner_rli == rli)
|
|
|
|
{
|
|
|
|
/* Already own this domain, increment reference count and apply event. */
|
|
|
|
++elem->owner_count;
|
2014-03-12 00:14:49 +01:00
|
|
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_OWNER;
|
2014-03-09 10:27:38 +01:00
|
|
|
res= 1;
|
|
|
|
break;
|
|
|
|
}
|
2014-03-12 00:14:49 +01:00
|
|
|
thd= rgi->thd;
|
2018-04-04 12:16:12 +03:00
|
|
|
if (unlikely(thd->check_killed()))
|
2014-03-12 00:14:49 +01:00
|
|
|
{
|
|
|
|
res= -1;
|
|
|
|
break;
|
|
|
|
}
|
2014-03-09 10:27:38 +01:00
|
|
|
/*
|
|
|
|
Someone else is currently processing this GTID (or an earlier one).
|
|
|
|
Wait for them to complete (or fail), and then check again.
|
|
|
|
*/
|
2014-03-12 00:14:49 +01:00
|
|
|
if (!did_enter_cond)
|
|
|
|
{
|
|
|
|
thd->ENTER_COND(&elem->COND_gtid_ignore_duplicates, &LOCK_slave_state,
|
|
|
|
&stage_gtid_wait_other_connection, &old_stage);
|
|
|
|
did_enter_cond= true;
|
|
|
|
}
|
2014-03-09 10:27:38 +01:00
|
|
|
mysql_cond_wait(&elem->COND_gtid_ignore_duplicates,
|
|
|
|
&LOCK_slave_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
2014-03-12 00:14:49 +01:00
|
|
|
if (did_enter_cond)
|
|
|
|
thd->EXIT_COND(&old_stage);
|
|
|
|
else
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
2014-03-09 10:27:38 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-12 00:14:49 +01:00
|
|
|
void
|
|
|
|
rpl_slave_state::release_domain_owner(rpl_group_info *rgi)
|
|
|
|
{
|
|
|
|
element *elem= NULL;
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
|
|
|
if (!(elem= get_element(rgi->current_gtid.domain_id)))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We cannot really deal with error here, as we are already called in an
|
|
|
|
error handling case (transaction failure and rollback).
|
|
|
|
|
|
|
|
However, get_element() only fails if the element did not exist already
|
|
|
|
and could not be allocated due to out-of-memory - and if it did not
|
|
|
|
exist, then we would not get here in the first place.
|
|
|
|
*/
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rgi->gtid_ignore_duplicate_state == rpl_group_info::GTID_DUPLICATE_OWNER)
|
|
|
|
{
|
|
|
|
uint32 count= elem->owner_count;
|
|
|
|
DBUG_ASSERT(count > 0);
|
|
|
|
DBUG_ASSERT(elem->owner_rli == rgi->rli);
|
|
|
|
--count;
|
|
|
|
elem->owner_count= count;
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
elem->owner_rli= NULL;
|
|
|
|
mysql_cond_broadcast(&elem->COND_gtid_ignore_duplicates);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
static void
|
|
|
|
rpl_slave_state_free_element(void *arg)
|
|
|
|
{
|
|
|
|
struct rpl_slave_state::element *elem= (struct rpl_slave_state::element *)arg;
|
|
|
|
mysql_cond_destroy(&elem->COND_wait_gtid);
|
2014-03-09 10:27:38 +01:00
|
|
|
mysql_cond_destroy(&elem->COND_gtid_ignore_duplicates);
|
2014-02-07 19:15:28 +01:00
|
|
|
my_free(elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
rpl_slave_state::rpl_slave_state()
|
2018-10-14 20:41:49 +02:00
|
|
|
: pending_gtid_count(0), last_sub_id(0), gtid_pos_tables(0), loaded(false)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2015-11-29 17:51:23 +02:00
|
|
|
mysql_mutex_init(key_LOCK_slave_state, &LOCK_slave_state,
|
|
|
|
MY_MUTEX_INIT_SLOW);
|
2021-09-30 10:14:28 +02:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
|
|
|
|
offsetof(element, domain_id), sizeof(element::domain_id),
|
|
|
|
NULL, rpl_slave_state_free_element, HASH_UNIQUE);
|
2020-02-27 11:52:20 +01:00
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, >id_sort_array, sizeof(rpl_gtid),
|
2020-01-29 13:50:26 +01:00
|
|
|
8, 8, MYF(0));
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rpl_slave_state::~rpl_slave_state()
|
|
|
|
{
|
2020-03-21 17:36:38 +04:00
|
|
|
free_gtid_pos_tables(gtid_pos_tables.load(std::memory_order_relaxed));
|
2015-11-29 17:51:23 +02:00
|
|
|
truncate_hash();
|
|
|
|
my_hash_free(&hash);
|
2015-12-21 21:24:22 +01:00
|
|
|
delete_dynamic(>id_sort_array);
|
2015-11-29 17:51:23 +02:00
|
|
|
mysql_mutex_destroy(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
rpl_slave_state::truncate_hash()
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
|
|
|
list_element *l= e->list;
|
|
|
|
list_element *next;
|
|
|
|
while (l)
|
|
|
|
{
|
|
|
|
next= l->next;
|
|
|
|
my_free(l);
|
|
|
|
l= next;
|
|
|
|
}
|
|
|
|
/* The element itself is freed by the hash element free function. */
|
|
|
|
}
|
|
|
|
my_hash_reset(&hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
2017-03-09 13:27:27 +01:00
|
|
|
uint64 seq_no, void *hton, rpl_group_info *rgi)
|
2023-07-02 21:16:03 +02:00
|
|
|
{
|
|
|
|
int res;
|
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
|
|
|
res= update_nolock(domain_id, server_id, sub_id, seq_no, hton, rgi);
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
rpl_slave_state::update_nolock(uint32 domain_id, uint32 server_id, uint64 sub_id,
|
|
|
|
uint64 seq_no, void *hton, rpl_group_info *rgi)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
element *elem= NULL;
|
|
|
|
list_element *list_elem= NULL;
|
|
|
|
|
2017-04-20 16:16:26 +02:00
|
|
|
DBUG_ASSERT(hton || !loaded);
|
2023-07-02 21:16:03 +02:00
|
|
|
mysql_mutex_assert_owner(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
if (!(elem= get_element(domain_id)))
|
|
|
|
return 1;
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
if (seq_no > elem->highest_seq_no)
|
|
|
|
elem->highest_seq_no= seq_no;
|
2014-02-08 22:28:41 +01:00
|
|
|
if (elem->gtid_waiter && elem->min_wait_seq_no <= seq_no)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Someone was waiting in MASTER_GTID_WAIT() for this GTID to appear.
|
|
|
|
Signal (and remove) them. The waiter will handle all the processing
|
|
|
|
of all pending MASTER_GTID_WAIT(), so we do not slow down the
|
|
|
|
replication SQL thread.
|
|
|
|
*/
|
2014-02-08 22:28:41 +01:00
|
|
|
elem->gtid_waiter= NULL;
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_cond_broadcast(&elem->COND_wait_gtid);
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:14:49 +01:00
|
|
|
if (rgi)
|
2014-03-09 10:27:38 +01:00
|
|
|
{
|
2014-03-12 00:14:49 +01:00
|
|
|
if (rgi->gtid_ignore_duplicate_state==rpl_group_info::GTID_DUPLICATE_OWNER)
|
2014-03-09 10:27:38 +01:00
|
|
|
{
|
2017-07-03 11:35:44 +03:00
|
|
|
#ifdef DBUG_ASSERT_EXISTS
|
2014-03-12 00:14:49 +01:00
|
|
|
Relay_log_info *rli= rgi->rli;
|
2014-06-04 13:23:00 +03:00
|
|
|
#endif
|
2014-03-12 00:14:49 +01:00
|
|
|
uint32 count= elem->owner_count;
|
|
|
|
DBUG_ASSERT(count > 0);
|
|
|
|
DBUG_ASSERT(elem->owner_rli == rli);
|
|
|
|
--count;
|
|
|
|
elem->owner_count= count;
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
elem->owner_rli= NULL;
|
|
|
|
mysql_cond_broadcast(&elem->COND_gtid_ignore_duplicates);
|
|
|
|
}
|
2014-03-09 10:27:38 +01:00
|
|
|
}
|
2014-03-12 00:14:49 +01:00
|
|
|
rgi->gtid_ignore_duplicate_state= rpl_group_info::GTID_DUPLICATE_NULL;
|
2014-03-09 10:27:38 +01:00
|
|
|
}
|
|
|
|
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(list_elem= (list_element *)my_malloc(PSI_INSTRUMENT_ME,
|
|
|
|
sizeof(*list_elem), MYF(MY_WME))))
|
2013-03-11 16:02:40 +01:00
|
|
|
return 1;
|
2018-10-14 20:41:49 +02:00
|
|
|
list_elem->domain_id= domain_id;
|
2013-03-11 16:02:40 +01:00
|
|
|
list_elem->server_id= server_id;
|
|
|
|
list_elem->sub_id= sub_id;
|
|
|
|
list_elem->seq_no= seq_no;
|
2017-03-09 13:27:27 +01:00
|
|
|
list_elem->hton= hton;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
elem->add(list_elem);
|
2013-10-25 21:17:14 +02:00
|
|
|
if (last_sub_id < sub_id)
|
|
|
|
last_sub_id= sub_id;
|
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
++pending_gtid_count;
|
|
|
|
if (pending_gtid_count >= opt_gtid_cleanup_batch_size)
|
|
|
|
{
|
|
|
|
pending_gtid_count = 0;
|
|
|
|
slave_background_gtid_pending_delete_request();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct rpl_slave_state::element *
|
|
|
|
rpl_slave_state::get_element(uint32 domain_id)
|
|
|
|
{
|
|
|
|
struct element *elem;
|
|
|
|
|
2021-09-30 10:14:28 +02:00
|
|
|
elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
|
|
|
|
sizeof(domain_id));
|
2013-03-11 16:02:40 +01:00
|
|
|
if (elem)
|
|
|
|
return elem;
|
|
|
|
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), MYF(MY_WME))))
|
2013-03-11 16:02:40 +01:00
|
|
|
return NULL;
|
|
|
|
elem->list= NULL;
|
|
|
|
elem->domain_id= domain_id;
|
2014-02-07 19:15:28 +01:00
|
|
|
elem->highest_seq_no= 0;
|
2014-02-08 22:28:41 +01:00
|
|
|
elem->gtid_waiter= NULL;
|
2014-03-09 10:27:38 +01:00
|
|
|
elem->owner_rli= NULL;
|
|
|
|
elem->owner_count= 0;
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_cond_init(key_COND_wait_gtid, &elem->COND_wait_gtid, 0);
|
2014-03-09 10:27:38 +01:00
|
|
|
mysql_cond_init(key_COND_gtid_ignore_duplicates,
|
|
|
|
&elem->COND_gtid_ignore_duplicates, 0);
|
2013-03-11 16:02:40 +01:00
|
|
|
if (my_hash_insert(&hash, (uchar *)elem))
|
|
|
|
{
|
|
|
|
my_free(elem);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-29 14:23:40 +02:00
|
|
|
int
|
2018-10-14 20:41:49 +02:00
|
|
|
rpl_slave_state::put_back_list(list_element *list)
|
2013-05-29 14:23:40 +02:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
element *e= NULL;
|
2018-10-07 18:59:52 +02:00
|
|
|
int err= 0;
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
2013-05-29 14:23:40 +02:00
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
list_element *next= list->next;
|
2018-10-14 20:41:49 +02:00
|
|
|
|
|
|
|
if ((!e || e->domain_id != list->domain_id) &&
|
2021-09-30 10:14:28 +02:00
|
|
|
!(e= (element *)my_hash_search(&hash, (const uchar *)&list->domain_id,
|
|
|
|
sizeof(list->domain_id))))
|
2018-10-14 20:41:49 +02:00
|
|
|
{
|
|
|
|
err= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-05-29 14:23:40 +02:00
|
|
|
e->add(list);
|
|
|
|
list= next;
|
|
|
|
}
|
2018-10-07 18:59:52 +02:00
|
|
|
|
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
|
|
|
return err;
|
2013-05-29 14:23:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
int
|
|
|
|
rpl_slave_state::truncate_state_table(THD *thd)
|
|
|
|
{
|
|
|
|
TABLE_LIST tlist;
|
|
|
|
int err= 0;
|
|
|
|
|
2020-01-28 23:23:51 +02:00
|
|
|
tlist.init_one_table(&MYSQL_SCHEMA_NAME, &rpl_gtid_slave_state_table_name,
|
|
|
|
NULL, TL_WRITE);
|
2019-12-17 23:00:23 +04:00
|
|
|
tlist.mdl_request.set_type(MDL_EXCLUSIVE);
|
2020-01-28 23:23:51 +02:00
|
|
|
if (!(err= open_and_lock_tables(thd, &tlist, FALSE,
|
|
|
|
MYSQL_OPEN_IGNORE_LOGGING_FORMAT)))
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2020-01-28 23:23:51 +02:00
|
|
|
DBUG_ASSERT(!tlist.table->file->row_logging);
|
2019-12-17 16:25:15 +04:00
|
|
|
tlist.table->s->tdc->flush(thd, true);
|
2013-11-27 11:02:08 +01:00
|
|
|
err= tlist.table->file->ha_truncate();
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
ha_rollback_trans(thd, FALSE);
|
|
|
|
close_thread_tables(thd);
|
|
|
|
ha_rollback_trans(thd, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ha_commit_trans(thd, FALSE);
|
|
|
|
close_thread_tables(thd);
|
|
|
|
ha_commit_trans(thd, TRUE);
|
|
|
|
}
|
2020-11-30 15:29:32 +02:00
|
|
|
thd->release_transactional_locks();
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const TABLE_FIELD_TYPE mysql_rpl_slave_state_coltypes[4]= {
|
2018-01-08 15:33:23 +02:00
|
|
|
{ { STRING_WITH_LEN("domain_id") },
|
|
|
|
{ STRING_WITH_LEN("int(10) unsigned") },
|
2013-03-11 16:02:40 +01:00
|
|
|
{NULL, 0} },
|
2018-01-08 15:33:23 +02:00
|
|
|
{ { STRING_WITH_LEN("sub_id") },
|
|
|
|
{ STRING_WITH_LEN("bigint(20) unsigned") },
|
2013-03-11 16:02:40 +01:00
|
|
|
{NULL, 0} },
|
2018-01-08 15:33:23 +02:00
|
|
|
{ { STRING_WITH_LEN("server_id") },
|
|
|
|
{ STRING_WITH_LEN("int(10) unsigned") },
|
2013-03-11 16:02:40 +01:00
|
|
|
{NULL, 0} },
|
2018-01-08 15:33:23 +02:00
|
|
|
{ { STRING_WITH_LEN("seq_no") },
|
|
|
|
{ STRING_WITH_LEN("bigint(20) unsigned") },
|
2013-03-11 16:02:40 +01:00
|
|
|
{NULL, 0} },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const uint mysql_rpl_slave_state_pk_parts[]= {0, 1};
|
|
|
|
|
2013-05-22 17:36:48 +02:00
|
|
|
static const TABLE_FIELD_DEF mysql_gtid_slave_pos_tabledef= {
|
2013-03-11 16:02:40 +01:00
|
|
|
array_elements(mysql_rpl_slave_state_coltypes),
|
|
|
|
mysql_rpl_slave_state_coltypes,
|
|
|
|
array_elements(mysql_rpl_slave_state_pk_parts),
|
|
|
|
mysql_rpl_slave_state_pk_parts
|
|
|
|
};
|
|
|
|
|
2016-12-09 17:13:43 +04:00
|
|
|
static Table_check_intact_log_error gtid_table_intact;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-03-11 16:16:55 +01:00
|
|
|
/*
|
2013-05-22 17:36:48 +02:00
|
|
|
Check that the mysql.gtid_slave_pos table has the correct definition.
|
2013-03-11 16:16:55 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
gtid_check_rpl_slave_state_table(TABLE *table)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2013-05-22 17:36:48 +02:00
|
|
|
if ((err= gtid_table_intact.check(table, &mysql_gtid_slave_pos_tabledef)))
|
2013-03-11 16:16:55 +01:00
|
|
|
my_error(ER_GTID_OPEN_TABLE_FAILED, MYF(0), "mysql",
|
|
|
|
rpl_gtid_slave_state_table_name.str);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-14 12:54:10 +01:00
|
|
|
/*
|
|
|
|
Attempt to find a mysql.gtid_slave_posXXX table that has a storage engine
|
|
|
|
that is already in use by the current transaction, if any.
|
|
|
|
*/
|
|
|
|
void
|
2017-07-03 10:36:09 +02:00
|
|
|
rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename)
|
2017-03-14 12:54:10 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
See comments on rpl_slave_state::gtid_pos_tables for rules around proper
|
|
|
|
access to the list.
|
|
|
|
*/
|
2020-03-21 17:36:38 +04:00
|
|
|
auto list= gtid_pos_tables.load(std::memory_order_acquire);
|
2017-03-14 12:54:10 +01:00
|
|
|
|
2017-04-25 19:08:45 +02:00
|
|
|
Ha_trx_info *ha_info;
|
|
|
|
uint count = 0;
|
2020-05-04 14:20:14 +03:00
|
|
|
for (ha_info= thd->transaction->all.ha_list; ha_info; ha_info= ha_info->next())
|
2017-03-14 12:54:10 +01:00
|
|
|
{
|
2017-04-25 19:08:45 +02:00
|
|
|
void *trx_hton= ha_info->ht();
|
2020-03-21 17:36:38 +04:00
|
|
|
auto table_entry= list;
|
2017-04-25 10:01:33 +02:00
|
|
|
|
2017-04-25 19:08:45 +02:00
|
|
|
if (!ha_info->is_trx_read_write() || trx_hton == binlog_hton)
|
2017-04-25 10:01:33 +02:00
|
|
|
continue;
|
2017-03-14 12:54:10 +01:00
|
|
|
while (table_entry)
|
|
|
|
{
|
|
|
|
if (table_entry->table_hton == trx_hton)
|
|
|
|
{
|
2017-03-24 12:07:07 +01:00
|
|
|
if (likely(table_entry->state == GTID_POS_AVAILABLE))
|
|
|
|
{
|
|
|
|
*out_tablename= table_entry->table_name;
|
2017-04-25 19:08:45 +02:00
|
|
|
/*
|
|
|
|
Check if this is a cross-engine transaction, so we can correctly
|
|
|
|
maintain the rpl_transactions_multi_engine status variable.
|
|
|
|
*/
|
|
|
|
if (count >= 1)
|
|
|
|
statistic_increment(rpl_transactions_multi_engine, LOCK_status);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
ha_info= ha_info->next();
|
|
|
|
if (!ha_info)
|
|
|
|
break;
|
|
|
|
if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
|
|
|
|
{
|
|
|
|
statistic_increment(rpl_transactions_multi_engine, LOCK_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-24 12:07:07 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
This engine is marked to automatically create the table.
|
|
|
|
We cannot easily do this here (possibly in the middle of a
|
|
|
|
transaction). But we can request the slave background thread
|
|
|
|
to create it, and in a short while it should become available
|
|
|
|
for following transactions.
|
|
|
|
*/
|
2017-04-29 11:19:09 +02:00
|
|
|
#ifdef HAVE_REPLICATION
|
2017-03-24 12:07:07 +01:00
|
|
|
slave_background_gtid_pos_create_request(table_entry);
|
2017-04-29 11:19:09 +02:00
|
|
|
#endif
|
2017-03-24 12:07:07 +01:00
|
|
|
break;
|
2017-03-14 12:54:10 +01:00
|
|
|
}
|
|
|
|
table_entry= table_entry->next;
|
|
|
|
}
|
2017-04-25 19:08:45 +02:00
|
|
|
++count;
|
2017-03-14 12:54:10 +01:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
If we cannot find any table whose engine matches an engine that is
|
|
|
|
already active in the transaction, or if there is no current transaction
|
|
|
|
engines available, we return the default gtid_slave_pos table.
|
|
|
|
*/
|
2020-03-21 15:52:24 +04:00
|
|
|
*out_tablename=
|
|
|
|
default_gtid_pos_table.load(std::memory_order_acquire)->table_name;
|
2017-04-25 19:08:45 +02:00
|
|
|
/* Record in status that we failed to find a suitable gtid_pos table. */
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
statistic_increment(transactions_gtid_foreign_engine, LOCK_status);
|
|
|
|
if (count > 1)
|
|
|
|
statistic_increment(rpl_transactions_multi_engine, LOCK_status);
|
|
|
|
}
|
2017-03-14 12:54:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
/*
|
|
|
|
Write a gtid to the replication slave state table.
|
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
Do it as part of the transaction, to get slave crash safety, or as a separate
|
|
|
|
transaction if !in_transaction (eg. MyISAM or DDL).
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
gtid The global transaction id for this event group.
|
|
|
|
sub_id Value allocated within the sub_id when the event group was
|
|
|
|
read (sub_id must be consistent with commit order in master binlog).
|
|
|
|
|
|
|
|
Note that caller must later ensure that the new gtid and sub_id is inserted
|
|
|
|
into the appropriate HASH element with rpl_slave_state.add(), so that it can
|
|
|
|
be deleted later. But this must only be done after COMMIT if in transaction.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
|
2018-10-14 20:41:49 +02:00
|
|
|
bool in_transaction, bool in_statement,
|
2017-03-09 13:27:27 +01:00
|
|
|
void **out_hton)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
TABLE_LIST tlist;
|
2017-08-09 23:54:16 +03:00
|
|
|
int err= 0, not_sql_thread;
|
2013-03-11 16:02:40 +01:00
|
|
|
bool table_opened= false;
|
|
|
|
TABLE *table;
|
|
|
|
ulonglong thd_saved_option= thd->variables.option_bits;
|
2013-03-22 08:11:37 +01:00
|
|
|
Query_tables_list lex_backup;
|
2015-04-08 11:01:18 +02:00
|
|
|
wait_for_commit* suspended_wfc;
|
2017-03-09 15:30:19 +01:00
|
|
|
void *hton= NULL;
|
2017-07-03 10:36:09 +02:00
|
|
|
LEX_CSTRING gtid_pos_table_name;
|
MDEV-11675 Lag Free Alter On Slave
This commit implements two phase binloggable ALTER.
When a new
@@session.binlog_alter_two_phase = YES
ALTER query gets logged in two parts, the START ALTER and the COMMIT
or ROLLBACK ALTER. START Alter is written in binlog as soon as
necessary locks have been acquired for the table. The timing is
such that any concurrent DML:s that update the same table are either
committed, thus logged into binary log having done work on the old
version of the table, or will be queued for execution on its new
version.
The "COMPLETE" COMMIT or ROLLBACK ALTER are written at the very point
of a normal "single-piece" ALTER that is after the most of
the query work is done. When its result is positive COMMIT ALTER is
written, otherwise ROLLBACK ALTER is written with specific error
happened after START ALTER phase.
Replication of two-phase binloggable ALTER is
cross-version safe. Specifically the OLD slave merely does not
recognized the start alter part, still being able to process and
memorize its gtid.
Two phase logged ALTER is read from binlog by mysqlbinlog to produce
BINLOG 'string', where 'string' contains base64 encoded
Query_log_event containing either the start part of ALTER, or a
completion part. The Query details can be displayed with `-v` flag,
similarly to ROW format events. Notice, mysqlbinlog output containing
parts of two-phase binloggable ALTER is processable correctly only by
binlog_alter_two_phase server.
@@log_warnings > 2 can reveal details of binlogging and slave side
processing of the ALTER parts.
The current commit also carries fixes to the following list of
reported bugs:
MDEV-27511, MDEV-27471, MDEV-27349, MDEV-27628, MDEV-27528.
Thanks to all people involved into early discussion of the feature
including Kristian Nielsen, those who helped to design, implement and
test: Sergei Golubchik, Andrei Elkin who took the burden of the
implemenation completion, Sujatha Sivakumar, Brandon
Nesterenko, Alice Sherepa, Ramesh Sivaraman, Jan Lindstrom.
2021-01-29 11:59:14 +00:00
|
|
|
TABLE *tbl= nullptr;
|
|
|
|
MDL_savepoint m_start_of_statement_svp(thd->mdl_context.mdl_savepoint());
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
DBUG_ENTER("record_gtid");
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2017-03-09 13:27:27 +01:00
|
|
|
*out_hton= NULL;
|
2013-06-07 10:58:34 +02:00
|
|
|
if (unlikely(!loaded))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Probably the mysql.gtid_slave_pos table is missing (eg. upgrade) or
|
|
|
|
corrupt.
|
|
|
|
|
|
|
|
We already complained loudly about this, but we can try to continue
|
|
|
|
until the DBA fixes it.
|
|
|
|
*/
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
DBUG_RETURN(0);
|
2013-06-07 10:58:34 +02:00
|
|
|
}
|
|
|
|
|
2013-05-22 17:36:48 +02:00
|
|
|
if (!in_statement)
|
2015-04-15 18:32:34 +04:00
|
|
|
thd->reset_for_next_command();
|
2017-08-09 23:54:16 +03:00
|
|
|
|
MDEV-11675 Lag Free Alter On Slave
This commit implements two phase binloggable ALTER.
When a new
@@session.binlog_alter_two_phase = YES
ALTER query gets logged in two parts, the START ALTER and the COMMIT
or ROLLBACK ALTER. START Alter is written in binlog as soon as
necessary locks have been acquired for the table. The timing is
such that any concurrent DML:s that update the same table are either
committed, thus logged into binary log having done work on the old
version of the table, or will be queued for execution on its new
version.
The "COMPLETE" COMMIT or ROLLBACK ALTER are written at the very point
of a normal "single-piece" ALTER that is after the most of
the query work is done. When its result is positive COMMIT ALTER is
written, otherwise ROLLBACK ALTER is written with specific error
happened after START ALTER phase.
Replication of two-phase binloggable ALTER is
cross-version safe. Specifically the OLD slave merely does not
recognized the start alter part, still being able to process and
memorize its gtid.
Two phase logged ALTER is read from binlog by mysqlbinlog to produce
BINLOG 'string', where 'string' contains base64 encoded
Query_log_event containing either the start part of ALTER, or a
completion part. The Query details can be displayed with `-v` flag,
similarly to ROW format events. Notice, mysqlbinlog output containing
parts of two-phase binloggable ALTER is processable correctly only by
binlog_alter_two_phase server.
@@log_warnings > 2 can reveal details of binlogging and slave side
processing of the ALTER parts.
The current commit also carries fixes to the following list of
reported bugs:
MDEV-27511, MDEV-27471, MDEV-27349, MDEV-27628, MDEV-27528.
Thanks to all people involved into early discussion of the feature
including Kristian Nielsen, those who helped to design, implement and
test: Sergei Golubchik, Andrei Elkin who took the burden of the
implemenation completion, Sujatha Sivakumar, Brandon
Nesterenko, Alice Sherepa, Ramesh Sivaraman, Jan Lindstrom.
2021-01-29 11:59:14 +00:00
|
|
|
if (thd->rgi_slave && (thd->rgi_slave->gtid_ev_flags_extra &
|
|
|
|
Gtid_log_event::FL_START_ALTER_E1))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
store the open table table list in ptr, so that is close_thread_tables
|
|
|
|
is called start alter tables are not closed
|
|
|
|
*/
|
|
|
|
mysql_mutex_lock(&thd->LOCK_thd_data);
|
|
|
|
tbl= thd->open_tables;
|
|
|
|
thd->open_tables= nullptr;
|
|
|
|
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
|
|
|
}
|
2017-08-09 23:54:16 +03:00
|
|
|
/*
|
|
|
|
Only the SQL thread can call select_gtid_pos_table without a mutex
|
|
|
|
Other threads needs to use a mutex and take into account that the
|
|
|
|
result may change during execution, so we have to make a copy.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((not_sql_thread= (thd->system_thread != SYSTEM_THREAD_SLAVE_SQL)))
|
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
2017-03-14 12:54:10 +01:00
|
|
|
select_gtid_pos_table(thd, >id_pos_table_name);
|
2017-08-09 23:54:16 +03:00
|
|
|
if (not_sql_thread)
|
|
|
|
{
|
|
|
|
LEX_CSTRING *tmp= thd->make_clex_string(gtid_pos_table_name.str,
|
|
|
|
gtid_pos_table_name.length);
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
|
|
|
if (!tmp)
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
gtid_pos_table_name= *tmp;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-03-21 17:33:29 +01:00
|
|
|
DBUG_EXECUTE_IF("gtid_inject_record_gtid",
|
|
|
|
{
|
|
|
|
my_error(ER_CANNOT_UPDATE_GTID_STATE, MYF(0));
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
DBUG_RETURN(1);
|
2013-03-21 17:33:29 +01:00
|
|
|
} );
|
|
|
|
|
2015-04-08 11:01:18 +02:00
|
|
|
/*
|
|
|
|
If we are applying a non-transactional event group, we will be committing
|
|
|
|
here a transaction, but that does not imply that the event group has
|
|
|
|
completed or has been binlogged. So we should not trigger
|
|
|
|
wakeup_subsequent_commits() here.
|
|
|
|
|
|
|
|
Note: An alternative here could be to put a call to mark_start_commit() in
|
|
|
|
stmt_done() before the call to record_and_update_gtid(). This would
|
|
|
|
prevent later calling mark_start_commit() after we have run
|
|
|
|
wakeup_subsequent_commits() from committing the GTID update transaction
|
|
|
|
(which must be avoided to avoid accessing freed group_commit_orderer
|
|
|
|
object). It would also allow following event groups to start slightly
|
|
|
|
earlier. And in the cases where record_gtid() is called without an active
|
|
|
|
transaction, the current statement should have been binlogged already, so
|
|
|
|
binlog order is preserved.
|
|
|
|
|
|
|
|
But this is rather subtle, and potentially fragile. And it does not really
|
|
|
|
seem worth it; non-transactional loads are unlikely to benefit much from
|
|
|
|
parallel replication in any case. So for now, we go with the simple
|
|
|
|
suspend/resume of wakeup_subsequent_commits() here in record_gtid().
|
|
|
|
*/
|
|
|
|
suspended_wfc= thd->suspend_subsequent_commits();
|
2013-03-22 08:11:37 +01:00
|
|
|
thd->lex->reset_n_backup_query_tables_list(&lex_backup);
|
2018-01-07 18:03:44 +02:00
|
|
|
tlist.init_one_table(&MYSQL_SCHEMA_NAME, >id_pos_table_name, NULL, TL_WRITE);
|
2013-03-11 16:02:40 +01:00
|
|
|
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
|
|
|
goto end;
|
|
|
|
table_opened= true;
|
|
|
|
table= tlist.table;
|
2017-03-09 15:30:19 +01:00
|
|
|
hton= table->s->db_type();
|
2020-01-28 23:23:51 +02:00
|
|
|
table->file->row_logging= 0; // No binary logging
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-03-11 16:16:55 +01:00
|
|
|
if ((err= gtid_check_rpl_slave_state_table(table)))
|
2013-03-11 16:02:40 +01:00
|
|
|
goto end;
|
|
|
|
|
2015-12-14 11:33:52 -05:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
/*
|
2023-06-20 14:57:04 +03:00
|
|
|
We should replicate local gtid_slave_pos updates to other nodes.
|
|
|
|
In applier we should not append them to galera writeset.
|
2015-12-14 11:33:52 -05:00
|
|
|
*/
|
2023-06-20 14:57:04 +03:00
|
|
|
if (WSREP_ON_ && wsrep_thd_is_local(thd))
|
|
|
|
{
|
|
|
|
thd->wsrep_ignore_table= false;
|
|
|
|
wsrep_start_trx_if_not_started(thd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
thd->wsrep_ignore_table= true;
|
|
|
|
}
|
2015-12-14 11:33:52 -05:00
|
|
|
#endif
|
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
if (!in_transaction)
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
{
|
|
|
|
DBUG_PRINT("info", ("resetting OPTION_BEGIN"));
|
2013-03-11 16:02:40 +01:00
|
|
|
thd->variables.option_bits&=
|
2014-02-05 19:01:59 +02:00
|
|
|
~(ulonglong)(OPTION_NOT_AUTOCOMMIT |OPTION_BEGIN |OPTION_BIN_LOG |
|
|
|
|
OPTION_GTID_BEGIN);
|
Fixes for parallel slave:
- Made slaves temporary table multi-thread slave safe by adding mutex around save_temporary_table usage.
- rli->save_temporary_tables is the active list of all used temporary tables
- This is copied to THD->temporary_tables when temporary tables are opened and updated when temporary tables are closed
- Added THD->lock_temporary_tables() and THD->unlock_temporary_tables() to simplify this.
- Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code.
- Added is_part_of_group() to mark functions that are part of the next function. This replaces setting IN_STMT when events are executed.
- Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
- If slave_skip_counter is set run things in single threaded mode. This simplifies code for skipping events.
- Updating state of relay log (IN_STMT and IN_TRANSACTION) is moved to one single function: update_state_of_relay_log()
We can't use OPTION_BEGIN to check for the state anymore as the sql_driver and sql execution threads may be different.
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts
is_in_group() is now independent of state of executed transaction.
- Reset thd->transaction.all.modified_non_trans_table() if we did set it for single table row events.
This was mainly for keeping the flag as documented.
- Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
- Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
- Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
- Changed some functions to take rpl_group_info instead of Relay_log_info to make them multi-slave safe and to simplify usage
- do_shall_skip()
- continue_group()
- sql_slave_killed()
- next_event()
- Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
- set_thd_in_use_temporary_tables() removed as in_use is set on usage
- Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
- In open_table() reuse code from find_temporary_table()
Other things:
- More DBUG statements
- Fixed the rpl_incident.test can be run with --debug
- More comments
- Disabled not used function rpl_connect_master()
mysql-test/suite/perfschema/r/all_instances.result:
Moved sleep_lock and sleep_cond to rpl_group_info
mysql-test/suite/rpl/r/rpl_incident.result:
Updated result
mysql-test/suite/rpl/t/rpl_incident-master.opt:
Not needed anymore
mysql-test/suite/rpl/t/rpl_incident.test:
Fixed that test can be run with --debug
sql/handler.cc:
More DBUG_PRINT
sql/log.cc:
More comments
sql/log_event.cc:
Added DBUG statements
do_shall_skip(), continue_group() now takes rpl_group_info param
Use is_begin(), is_commit() and is_rollback() functions instead of inspecting query string
We don't have set slaves temporary tables 'in_use' as this is now done when tables are opened.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
Use IN_TRANSACTION flag to test state of relay log.
In rows_event_stmt_cleanup() reset thd->transaction.all.modified_non_trans_table if we had set this before.
sql/log_event.h:
do_shall_skip(), continue_group() now takes rpl_group_info param
Added is_part_of_group() to mark events that are part of the next event. This replaces setting IN_STMT when events are executed.
Added is_begin(), is_commit() and is_rollback() functions to Query_log_event to simplify code.
sql/log_event_old.cc:
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/log_event_old.h:
Added is_part_of_group() to mark events that are part of the next event.
do_shall_skip(), continue_group() now takes rpl_group_info param
sql/mysqld.cc:
Changed slave_open_temp_tables to uint32 to be able to use atomic operators on it.
Relay_log_info::sleep_lock -> Rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> Rpl_group_info::sleep_cond
sql/mysqld.h:
Updated types and names
sql/rpl_gtid.cc:
More DBUG
sql/rpl_parallel.cc:
Updated TODO section
Set thd for event that is execution
Use new is_begin(), is_commit() and is_rollback() functions.
More comments
sql/rpl_rli.cc:
sql_thd -> sql_driver_thd
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Clear IN_STMT and IN_TRANSACTION in init_relay_log_pos() and Relay_log_info::cleanup_context() to ensure the flags doesn't survive slave restarts.
Reset table->in_use for temporary tables as the table may have been used by another THD.
Use IN_TRANSACTION instead of OPTION_BEGIN to check state of relay log.
Removed IN_STMT flag setting. This is now done in update_state_of_relay_log()
sql/rpl_rli.h:
Changed relay log state flags to bit masks instead of bit positions (most other code we have uses bit masks)
Added IN_TRANSACTION to mark if we are in a BEGIN ... COMMIT section.
save_temporary_tables is now thread safe
Relay_log_info::sleep_lock -> rpl_group_info::sleep_lock
Relay_log_info::sleep_cond -> rpl_group_info::sleep_cond
Relay_log_info->sql_thd renamed to Relay_log_info->sql_driver_thd to avoid wrong usage for merged code
is_in_group() is now independent of state of executed transaction.
sql/slave.cc:
Simplifed arguments to io_salve_killed(), sql_slave_killed() and check_io_slave_killed(); No reason to supply THD as this is part of the given structure.
set_thd_in_use_temporary_tables() removed as in_use is set on usage in sql_base.cc
sql_thd -> sql_driver_thd
More DBUG
Added update_state_of_relay_log() which will calculate the IN_STMT and IN_TRANSACTION state of the relay log after the current element is executed.
If slave_skip_counter is set run things in single threaded mode.
Simplifed arguments to io_salve_killed(), check_io_slave_killed() and sql_slave_killed(); No reason to supply THD as this is part of the given structure.
Added information to thd_proc_info() which thread is waiting for slave mutex to exit.
Disabled not used function rpl_connect_master()
Updated argument to next_event()
sql/sql_base.cc:
Added mutex around usage of slave's temporary tables. The active list is always kept up to date in sql->rgi_slave->save_temporary_tables.
Clear thd->temporary_tables after query (safety)
More DBUG
When using temporary table, set table->in_use to current thd as the THD may be different for slave threads.
Some code is ifdef:ed with REMOVE_AFTER_MERGE_WITH_10 as the given code in 10.0 is not yet in this tree.
In open_table() reuse code from find_temporary_table()
sql/sql_binlog.cc:
rli->sql_thd -> rli->sql_driver_thd
Remove duplicate setting of rgi->rli
sql/sql_class.cc:
Added helper functions rgi_lock_temporary_tables() and rgi_unlock_temporary_tables()
Would have been nicer to have these inline, but there was no easy way to do that
sql/sql_class.h:
Added functions to protect slaves temporary tables
sql/sql_parse.cc:
Added DBUG_PRINT
sql/transaction.cc:
Added comment
2013-10-14 00:24:05 +03:00
|
|
|
}
|
2013-11-27 11:02:08 +01:00
|
|
|
else
|
|
|
|
thd->variables.option_bits&= ~(ulonglong)OPTION_BIN_LOG;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
bitmap_set_all(table->write_set);
|
2015-12-10 12:39:54 +02:00
|
|
|
table->rpl_write_set= table->write_set;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
table->field[0]->store((ulonglong)gtid->domain_id, true);
|
|
|
|
table->field[1]->store(sub_id, true);
|
|
|
|
table->field[2]->store((ulonglong)gtid->server_id, true);
|
|
|
|
table->field[3]->store(gtid->seq_no, true);
|
2013-03-28 13:03:51 +01:00
|
|
|
DBUG_EXECUTE_IF("inject_crash_before_write_rpl_slave_state", DBUG_SUICIDE(););
|
2013-03-11 16:02:40 +01:00
|
|
|
if ((err= table->file->ha_write_row(table->record[0])))
|
2013-05-29 14:23:40 +02:00
|
|
|
{
|
|
|
|
table->file->print_error(err, MYF(0));
|
|
|
|
goto end;
|
|
|
|
}
|
2017-03-09 15:30:19 +01:00
|
|
|
*out_hton= hton;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-06-21 11:53:46 +02:00
|
|
|
if(opt_bin_log &&
|
|
|
|
(err= mysql_bin_log.bump_seq_no_counter_if_needed(gtid->domain_id,
|
|
|
|
gtid->seq_no)))
|
|
|
|
{
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
goto end;
|
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
end:
|
2013-06-21 11:53:46 +02:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
#ifdef WITH_WSREP
|
|
|
|
thd->wsrep_ignore_table= false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (table_opened)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
if (err || (err= ha_commit_trans(thd, FALSE)))
|
|
|
|
ha_rollback_trans(thd, FALSE);
|
|
|
|
close_thread_tables(thd);
|
MDEV-11675 Lag Free Alter On Slave
This commit implements two phase binloggable ALTER.
When a new
@@session.binlog_alter_two_phase = YES
ALTER query gets logged in two parts, the START ALTER and the COMMIT
or ROLLBACK ALTER. START Alter is written in binlog as soon as
necessary locks have been acquired for the table. The timing is
such that any concurrent DML:s that update the same table are either
committed, thus logged into binary log having done work on the old
version of the table, or will be queued for execution on its new
version.
The "COMPLETE" COMMIT or ROLLBACK ALTER are written at the very point
of a normal "single-piece" ALTER that is after the most of
the query work is done. When its result is positive COMMIT ALTER is
written, otherwise ROLLBACK ALTER is written with specific error
happened after START ALTER phase.
Replication of two-phase binloggable ALTER is
cross-version safe. Specifically the OLD slave merely does not
recognized the start alter part, still being able to process and
memorize its gtid.
Two phase logged ALTER is read from binlog by mysqlbinlog to produce
BINLOG 'string', where 'string' contains base64 encoded
Query_log_event containing either the start part of ALTER, or a
completion part. The Query details can be displayed with `-v` flag,
similarly to ROW format events. Notice, mysqlbinlog output containing
parts of two-phase binloggable ALTER is processable correctly only by
binlog_alter_two_phase server.
@@log_warnings > 2 can reveal details of binlogging and slave side
processing of the ALTER parts.
The current commit also carries fixes to the following list of
reported bugs:
MDEV-27511, MDEV-27471, MDEV-27349, MDEV-27628, MDEV-27528.
Thanks to all people involved into early discussion of the feature
including Kristian Nielsen, those who helped to design, implement and
test: Sergei Golubchik, Andrei Elkin who took the burden of the
implemenation completion, Sujatha Sivakumar, Brandon
Nesterenko, Alice Sherepa, Ramesh Sivaraman, Jan Lindstrom.
2021-01-29 11:59:14 +00:00
|
|
|
if (!thd->rgi_slave || !(thd->rgi_slave->gtid_ev_flags_extra &
|
|
|
|
Gtid_log_event::FL_START_ALTER_E1))
|
|
|
|
{
|
|
|
|
if (in_transaction)
|
|
|
|
thd->mdl_context.release_statement_locks();
|
|
|
|
else
|
|
|
|
thd->release_transactional_locks();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (thd->rgi_slave &&
|
|
|
|
thd->rgi_slave->gtid_ev_flags_extra & Gtid_log_event::FL_START_ALTER_E1)
|
|
|
|
{
|
|
|
|
mysql_mutex_lock(&thd->LOCK_thd_data);
|
|
|
|
thd->open_tables= tbl;
|
|
|
|
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
|
|
|
thd->mdl_context.rollback_to_savepoint(m_start_of_statement_svp);
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
thd->lex->restore_backup_query_tables_list(&lex_backup);
|
|
|
|
thd->variables.option_bits= thd_saved_option;
|
|
|
|
thd->resume_subsequent_commits(suspended_wfc);
|
|
|
|
DBUG_EXECUTE_IF("inject_record_gtid_serverid_100_sleep",
|
|
|
|
{
|
|
|
|
if (gtid->server_id == 100)
|
|
|
|
my_sleep(500000);
|
|
|
|
});
|
|
|
|
DBUG_RETURN(err);
|
|
|
|
}
|
2017-03-09 15:30:19 +01:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Return a list of all old GTIDs in any mysql.gtid_slave_pos* table that are
|
|
|
|
no longer needed and can be deleted from the table.
|
|
|
|
|
|
|
|
Within each domain, we need to keep around the latest GTID (the one with the
|
|
|
|
highest sub_id), but any others in that domain can be deleted.
|
|
|
|
*/
|
|
|
|
rpl_slave_state::list_element *
|
|
|
|
rpl_slave_state::gtid_grab_pending_delete_list()
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
list_element *full_list;
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
|
|
|
full_list= NULL;
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
2013-06-21 11:53:46 +02:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
element *elem= (element *)my_hash_element(&hash, i);
|
|
|
|
list_element *elist= elem->list;
|
|
|
|
list_element *last_elem, **best_ptr_ptr, *cur, *next;
|
|
|
|
uint64 best_sub_id;
|
|
|
|
|
|
|
|
if (!elist)
|
|
|
|
continue; /* Nothing here */
|
|
|
|
|
|
|
|
/* Delete any old stuff, but keep around the most recent one. */
|
|
|
|
cur= elist;
|
|
|
|
best_sub_id= cur->sub_id;
|
|
|
|
best_ptr_ptr= &elist;
|
|
|
|
last_elem= cur;
|
|
|
|
while ((next= cur->next)) {
|
|
|
|
last_elem= next;
|
|
|
|
if (next->sub_id > best_sub_id)
|
2013-06-21 11:53:46 +02:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
best_sub_id= next->sub_id;
|
2013-06-21 11:53:46 +02:00
|
|
|
best_ptr_ptr= &cur->next;
|
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
cur= next;
|
2013-06-21 11:53:46 +02:00
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
/*
|
|
|
|
Append the new elements to the full list. Note the order is important;
|
|
|
|
we do it here so that we do not break the list if best_sub_id is the
|
|
|
|
last of the new elements.
|
|
|
|
*/
|
|
|
|
last_elem->next= full_list;
|
|
|
|
/*
|
|
|
|
Delete the highest sub_id element from the old list, and put it back as
|
|
|
|
the single-element new list.
|
|
|
|
*/
|
2013-06-21 11:53:46 +02:00
|
|
|
cur= *best_ptr_ptr;
|
|
|
|
*best_ptr_ptr= cur->next;
|
2018-10-14 20:41:49 +02:00
|
|
|
cur->next= NULL;
|
2013-06-21 11:53:46 +02:00
|
|
|
elem->list= cur;
|
2018-10-14 20:41:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Collect the full list so far here. Note that elist may have moved if we
|
|
|
|
deleted the first element, so order is again important.
|
|
|
|
*/
|
|
|
|
full_list= elist;
|
2013-06-21 11:53:46 +02:00
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
return full_list;
|
|
|
|
}
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
/* Find the mysql.gtid_slave_posXXX table associated with a given hton. */
|
|
|
|
LEX_CSTRING *
|
|
|
|
rpl_slave_state::select_gtid_pos_table(void *hton)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
See comments on rpl_slave_state::gtid_pos_tables for rules around proper
|
|
|
|
access to the list.
|
|
|
|
*/
|
2020-03-21 17:36:38 +04:00
|
|
|
auto table_entry= gtid_pos_tables.load(std::memory_order_acquire);
|
2018-10-14 20:41:49 +02:00
|
|
|
|
|
|
|
while (table_entry)
|
2013-05-29 14:23:40 +02:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
if (table_entry->table_hton == hton)
|
|
|
|
{
|
|
|
|
if (likely(table_entry->state == GTID_POS_AVAILABLE))
|
|
|
|
return &table_entry->table_name;
|
|
|
|
}
|
|
|
|
table_entry= table_entry->next;
|
2013-05-29 14:23:40 +02:00
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
|
2020-03-21 15:52:24 +04:00
|
|
|
return &default_gtid_pos_table.load(std::memory_order_acquire)->table_name;
|
2018-10-14 20:41:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
rpl_slave_state::gtid_delete_pending(THD *thd,
|
|
|
|
rpl_slave_state::list_element **list_ptr)
|
|
|
|
{
|
|
|
|
int err= 0;
|
|
|
|
ulonglong thd_saved_option;
|
|
|
|
|
|
|
|
if (unlikely(!loaded))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef WITH_WSREP
|
|
|
|
/*
|
2023-06-20 14:57:04 +03:00
|
|
|
We should replicate local gtid_slave_pos updates to other nodes.
|
|
|
|
In applier we should not append them to galera writeset.
|
2018-10-14 20:41:49 +02:00
|
|
|
*/
|
2023-06-20 14:57:04 +03:00
|
|
|
if (WSREP_ON_ && wsrep_thd_is_local(thd) &&
|
|
|
|
thd->wsrep_cs().state() != wsrep::client_state::s_none)
|
|
|
|
{
|
|
|
|
if (thd->wsrep_trx().active() == false)
|
|
|
|
{
|
|
|
|
if (thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID)
|
|
|
|
thd->set_query_id(next_query_id());
|
|
|
|
wsrep_start_transaction(thd, thd->wsrep_next_trx_id());
|
|
|
|
}
|
|
|
|
thd->wsrep_ignore_table= false;
|
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
thd->wsrep_ignore_table= true;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
thd_saved_option= thd->variables.option_bits;
|
|
|
|
thd->variables.option_bits&=
|
|
|
|
~(ulonglong)(OPTION_NOT_AUTOCOMMIT |OPTION_BEGIN |OPTION_BIN_LOG |
|
|
|
|
OPTION_GTID_BEGIN);
|
|
|
|
|
|
|
|
while (*list_ptr)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
LEX_CSTRING *gtid_pos_table_name, *tmp_table_name;
|
|
|
|
Query_tables_list lex_backup;
|
|
|
|
TABLE_LIST tlist;
|
|
|
|
TABLE *table;
|
2019-08-12 10:42:12 +03:00
|
|
|
handler::Table_flags direct_pos= 0;
|
2018-10-14 20:41:49 +02:00
|
|
|
list_element *cur, **cur_ptr_ptr;
|
|
|
|
bool table_opened= false;
|
2019-05-16 13:12:21 +05:30
|
|
|
bool index_inited= false;
|
2018-10-14 20:41:49 +02:00
|
|
|
void *hton= (*list_ptr)->hton;
|
|
|
|
|
|
|
|
thd->reset_for_next_command();
|
|
|
|
|
2013-05-29 14:23:40 +02:00
|
|
|
/*
|
2018-10-14 20:41:49 +02:00
|
|
|
Only the SQL thread can call select_gtid_pos_table without a mutex
|
|
|
|
Other threads needs to use a mutex and take into account that the
|
|
|
|
result may change during execution, so we have to make a copy.
|
2013-05-29 14:23:40 +02:00
|
|
|
*/
|
2018-10-14 20:41:49 +02:00
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
|
|
|
tmp_table_name= select_gtid_pos_table(hton);
|
|
|
|
gtid_pos_table_name= thd->make_clex_string(tmp_table_name->str,
|
|
|
|
tmp_table_name->length);
|
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
|
|
|
if (!gtid_pos_table_name)
|
|
|
|
{
|
|
|
|
/* Out of memory - we can try again later. */
|
2013-05-29 14:23:40 +02:00
|
|
|
break;
|
2018-10-14 20:41:49 +02:00
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
thd->lex->reset_n_backup_query_tables_list(&lex_backup);
|
|
|
|
tlist.init_one_table(&MYSQL_SCHEMA_NAME, gtid_pos_table_name, NULL, TL_WRITE);
|
|
|
|
if ((err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
|
|
|
|
goto end;
|
|
|
|
table_opened= true;
|
|
|
|
table= tlist.table;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
if ((err= gtid_check_rpl_slave_state_table(table)))
|
|
|
|
goto end;
|
2015-12-14 11:33:52 -05:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
direct_pos= table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION;
|
|
|
|
bitmap_set_all(table->write_set);
|
|
|
|
table->rpl_write_set= table->write_set;
|
|
|
|
|
|
|
|
/* Now delete any already committed GTIDs. */
|
|
|
|
bitmap_set_bit(table->read_set, table->field[0]->field_index);
|
|
|
|
bitmap_set_bit(table->read_set, table->field[1]->field_index);
|
|
|
|
|
2019-05-16 13:12:21 +05:30
|
|
|
if (!direct_pos)
|
2018-10-14 20:41:49 +02:00
|
|
|
{
|
2019-05-16 13:12:21 +05:30
|
|
|
if ((err= table->file->ha_index_init(0, 0)))
|
|
|
|
{
|
|
|
|
table->file->print_error(err, MYF(0));
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
index_inited= true;
|
2018-10-14 20:41:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cur = *list_ptr;
|
|
|
|
cur_ptr_ptr = list_ptr;
|
|
|
|
do
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
uchar key_buffer[4+8];
|
|
|
|
list_element *next= cur->next;
|
|
|
|
|
|
|
|
if (cur->hton == hton)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
table->field[0]->store((ulonglong)cur->domain_id, true);
|
|
|
|
table->field[1]->store(cur->sub_id, true);
|
|
|
|
if (direct_pos)
|
|
|
|
{
|
|
|
|
res= table->file->ha_rnd_pos_by_record(table->record[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
key_copy(key_buffer, table->record[0], &table->key_info[0], 0, false);
|
|
|
|
res= table->file->ha_index_read_map(table->record[0], key_buffer,
|
|
|
|
HA_WHOLE_KEY, HA_READ_KEY_EXACT);
|
|
|
|
}
|
|
|
|
DBUG_EXECUTE_IF("gtid_slave_pos_simulate_failed_delete",
|
|
|
|
{ res= 1;
|
|
|
|
err= ENOENT;
|
|
|
|
sql_print_error("<DEBUG> Error deleting old GTID row");
|
|
|
|
});
|
|
|
|
if (res)
|
|
|
|
/* We cannot find the row, assume it is already deleted. */
|
|
|
|
;
|
|
|
|
else if ((err= table->file->ha_delete_row(table->record[0])))
|
|
|
|
{
|
|
|
|
sql_print_error("Error deleting old GTID row: %s",
|
|
|
|
thd->get_stmt_da()->message());
|
|
|
|
/*
|
|
|
|
In case of error, we still discard the element from the list. We do
|
|
|
|
not want to endlessly error on the same element in case of table
|
|
|
|
corruption or such.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
*cur_ptr_ptr= next;
|
|
|
|
my_free(cur);
|
|
|
|
}
|
|
|
|
else
|
2013-05-29 14:23:40 +02:00
|
|
|
{
|
2018-10-14 20:41:49 +02:00
|
|
|
/* Leave this one in the list until we get to the table for its hton. */
|
|
|
|
cur_ptr_ptr= &cur->next;
|
2013-05-29 14:23:40 +02:00
|
|
|
}
|
2018-10-14 20:41:49 +02:00
|
|
|
cur= next;
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
} while (cur);
|
|
|
|
end:
|
|
|
|
if (table_opened)
|
|
|
|
{
|
2019-05-16 13:12:21 +05:30
|
|
|
DBUG_ASSERT(direct_pos || index_inited || err);
|
|
|
|
/*
|
|
|
|
Index may not be initialized if there was a failure during
|
|
|
|
'ha_index_init'. Hence check if index initialization is successful and
|
|
|
|
then invoke ha_index_end(). Ending an index which is not initialized
|
|
|
|
will lead to assert.
|
|
|
|
*/
|
|
|
|
if (index_inited)
|
2018-10-14 20:41:49 +02:00
|
|
|
table->file->ha_index_end();
|
2013-05-29 14:23:40 +02:00
|
|
|
|
2018-10-14 20:41:49 +02:00
|
|
|
if (err || (err= ha_commit_trans(thd, FALSE)))
|
|
|
|
ha_rollback_trans(thd, FALSE);
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
2014-06-27 13:34:29 +02:00
|
|
|
close_thread_tables(thd);
|
2020-12-01 19:51:14 +02:00
|
|
|
thd->release_transactional_locks();
|
2018-10-14 20:41:49 +02:00
|
|
|
thd->lex->restore_backup_query_tables_list(&lex_backup);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
break;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
thd->variables.option_bits= thd_saved_option;
|
2018-10-14 20:41:49 +02:00
|
|
|
|
|
|
|
#ifdef WITH_WSREP
|
|
|
|
thd->wsrep_ignore_table= false;
|
|
|
|
#endif
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint64
|
2013-06-20 09:04:44 +02:00
|
|
|
rpl_slave_state::next_sub_id(uint32 domain_id)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2013-06-20 09:04:44 +02:00
|
|
|
uint64 sub_id= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
2013-10-25 21:17:14 +02:00
|
|
|
sub_id= ++last_sub_id;
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
return sub_id;
|
|
|
|
}
|
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
/* A callback used in sorting of gtid list based on domain_id. */
|
|
|
|
static int rpl_gtid_cmp_cb(const void *id1, const void *id2)
|
|
|
|
{
|
|
|
|
uint32 d1= ((rpl_gtid *)id1)->domain_id;
|
|
|
|
uint32 d2= ((rpl_gtid *)id2)->domain_id;
|
|
|
|
|
|
|
|
if (d1 < d2)
|
|
|
|
return -1;
|
|
|
|
else if (d1 > d2)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
/* Format the specified gtid and store it in the given string buffer. */
|
2013-03-11 16:02:40 +01:00
|
|
|
bool
|
|
|
|
rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first)
|
|
|
|
{
|
|
|
|
if (*first)
|
|
|
|
*first= false;
|
|
|
|
else
|
Reduce usage of strlen()
Changes:
- To detect automatic strlen() I removed the methods in String that
uses 'const char *' without a length:
- String::append(const char*)
- Binary_string(const char *str)
- String(const char *str, CHARSET_INFO *cs)
- append_for_single_quote(const char *)
All usage of append(const char*) is changed to either use
String::append(char), String::append(const char*, size_t length) or
String::append(LEX_CSTRING)
- Added STRING_WITH_LEN() around constant string arguments to
String::append()
- Added overflow argument to escape_string_for_mysql() and
escape_quotes_for_mysql() instead of returning (size_t) -1 on overflow.
This was needed as most usage of the above functions never tested the
result for -1 and would have given wrong results or crashes in case
of overflows.
- Added Item_func_or_sum::func_name_cstring(), which returns LEX_CSTRING.
Changed all Item_func::func_name()'s to func_name_cstring()'s.
The old Item_func_or_sum::func_name() is now an inline function that
returns func_name_cstring().str.
- Changed Item::mode_name() and Item::func_name_ext() to return
LEX_CSTRING.
- Changed for some functions the name argument from const char * to
to const LEX_CSTRING &:
- Item::Item_func_fix_attributes()
- Item::check_type_...()
- Type_std_attributes::agg_item_collations()
- Type_std_attributes::agg_item_set_converter()
- Type_std_attributes::agg_arg_charsets...()
- Type_handler_hybrid_field_type::aggregate_for_result()
- Type_handler_geometry::check_type_geom_or_binary()
- Type_handler::Item_func_or_sum_illegal_param()
- Predicant_to_list_comparator::add_value_skip_null()
- Predicant_to_list_comparator::add_value()
- cmp_item_row::prepare_comparators()
- cmp_item_row::aggregate_row_elements_for_comparison()
- Cursor_ref::print_func()
- Removes String_space() as it was only used in one cases and that
could be simplified to not use String_space(), thanks to the fixed
my_vsnprintf().
- Added some const LEX_CSTRING's for common strings:
- NULL_clex_str, DATA_clex_str, INDEX_clex_str.
- Changed primary_key_name to a LEX_CSTRING
- Renamed String::set_quick() to String::set_buffer_if_not_allocated() to
clarify what the function really does.
- Rename of protocol function:
bool store(const char *from, CHARSET_INFO *cs) to
bool store_string_or_null(const char *from, CHARSET_INFO *cs).
This was done to both clarify the difference between this 'store' function
and also to make it easier to find unoptimal usage of store() calls.
- Added Protocol::store(const LEX_CSTRING*, CHARSET_INFO*)
- Changed some 'const char*' arrays to instead be of type LEX_CSTRING.
- class Item_func_units now used LEX_CSTRING for name.
Other things:
- Fixed a bug in mysql.cc:construct_prompt() where a wrong escape character
in the prompt would cause some part of the prompt to be duplicated.
- Fixed a lot of instances where the length of the argument to
append is known or easily obtain but was not used.
- Removed some not needed 'virtual' definition for functions that was
inherited from the parent. I added override to these.
- Fixed Ordered_key::print() to preallocate needed buffer. Old code could
case memory overruns.
- Simplified some loops when adding char * to a String with delimiters.
2020-08-12 20:29:55 +03:00
|
|
|
if (dest->append(','))
|
2013-03-11 16:02:40 +01:00
|
|
|
return true;
|
|
|
|
return
|
|
|
|
dest->append_ulonglong(gtid->domain_id) ||
|
Reduce usage of strlen()
Changes:
- To detect automatic strlen() I removed the methods in String that
uses 'const char *' without a length:
- String::append(const char*)
- Binary_string(const char *str)
- String(const char *str, CHARSET_INFO *cs)
- append_for_single_quote(const char *)
All usage of append(const char*) is changed to either use
String::append(char), String::append(const char*, size_t length) or
String::append(LEX_CSTRING)
- Added STRING_WITH_LEN() around constant string arguments to
String::append()
- Added overflow argument to escape_string_for_mysql() and
escape_quotes_for_mysql() instead of returning (size_t) -1 on overflow.
This was needed as most usage of the above functions never tested the
result for -1 and would have given wrong results or crashes in case
of overflows.
- Added Item_func_or_sum::func_name_cstring(), which returns LEX_CSTRING.
Changed all Item_func::func_name()'s to func_name_cstring()'s.
The old Item_func_or_sum::func_name() is now an inline function that
returns func_name_cstring().str.
- Changed Item::mode_name() and Item::func_name_ext() to return
LEX_CSTRING.
- Changed for some functions the name argument from const char * to
to const LEX_CSTRING &:
- Item::Item_func_fix_attributes()
- Item::check_type_...()
- Type_std_attributes::agg_item_collations()
- Type_std_attributes::agg_item_set_converter()
- Type_std_attributes::agg_arg_charsets...()
- Type_handler_hybrid_field_type::aggregate_for_result()
- Type_handler_geometry::check_type_geom_or_binary()
- Type_handler::Item_func_or_sum_illegal_param()
- Predicant_to_list_comparator::add_value_skip_null()
- Predicant_to_list_comparator::add_value()
- cmp_item_row::prepare_comparators()
- cmp_item_row::aggregate_row_elements_for_comparison()
- Cursor_ref::print_func()
- Removes String_space() as it was only used in one cases and that
could be simplified to not use String_space(), thanks to the fixed
my_vsnprintf().
- Added some const LEX_CSTRING's for common strings:
- NULL_clex_str, DATA_clex_str, INDEX_clex_str.
- Changed primary_key_name to a LEX_CSTRING
- Renamed String::set_quick() to String::set_buffer_if_not_allocated() to
clarify what the function really does.
- Rename of protocol function:
bool store(const char *from, CHARSET_INFO *cs) to
bool store_string_or_null(const char *from, CHARSET_INFO *cs).
This was done to both clarify the difference between this 'store' function
and also to make it easier to find unoptimal usage of store() calls.
- Added Protocol::store(const LEX_CSTRING*, CHARSET_INFO*)
- Changed some 'const char*' arrays to instead be of type LEX_CSTRING.
- class Item_func_units now used LEX_CSTRING for name.
Other things:
- Fixed a bug in mysql.cc:construct_prompt() where a wrong escape character
in the prompt would cause some part of the prompt to be duplicated.
- Fixed a lot of instances where the length of the argument to
append is known or easily obtain but was not used.
- Removed some not needed 'virtual' definition for functions that was
inherited from the parent. I added override to these.
- Fixed Ordered_key::print() to preallocate needed buffer. Old code could
case memory overruns.
- Simplified some loops when adding char * to a String with delimiters.
2020-08-12 20:29:55 +03:00
|
|
|
dest->append('-') ||
|
2013-03-11 16:02:40 +01:00
|
|
|
dest->append_ulonglong(gtid->server_id) ||
|
Reduce usage of strlen()
Changes:
- To detect automatic strlen() I removed the methods in String that
uses 'const char *' without a length:
- String::append(const char*)
- Binary_string(const char *str)
- String(const char *str, CHARSET_INFO *cs)
- append_for_single_quote(const char *)
All usage of append(const char*) is changed to either use
String::append(char), String::append(const char*, size_t length) or
String::append(LEX_CSTRING)
- Added STRING_WITH_LEN() around constant string arguments to
String::append()
- Added overflow argument to escape_string_for_mysql() and
escape_quotes_for_mysql() instead of returning (size_t) -1 on overflow.
This was needed as most usage of the above functions never tested the
result for -1 and would have given wrong results or crashes in case
of overflows.
- Added Item_func_or_sum::func_name_cstring(), which returns LEX_CSTRING.
Changed all Item_func::func_name()'s to func_name_cstring()'s.
The old Item_func_or_sum::func_name() is now an inline function that
returns func_name_cstring().str.
- Changed Item::mode_name() and Item::func_name_ext() to return
LEX_CSTRING.
- Changed for some functions the name argument from const char * to
to const LEX_CSTRING &:
- Item::Item_func_fix_attributes()
- Item::check_type_...()
- Type_std_attributes::agg_item_collations()
- Type_std_attributes::agg_item_set_converter()
- Type_std_attributes::agg_arg_charsets...()
- Type_handler_hybrid_field_type::aggregate_for_result()
- Type_handler_geometry::check_type_geom_or_binary()
- Type_handler::Item_func_or_sum_illegal_param()
- Predicant_to_list_comparator::add_value_skip_null()
- Predicant_to_list_comparator::add_value()
- cmp_item_row::prepare_comparators()
- cmp_item_row::aggregate_row_elements_for_comparison()
- Cursor_ref::print_func()
- Removes String_space() as it was only used in one cases and that
could be simplified to not use String_space(), thanks to the fixed
my_vsnprintf().
- Added some const LEX_CSTRING's for common strings:
- NULL_clex_str, DATA_clex_str, INDEX_clex_str.
- Changed primary_key_name to a LEX_CSTRING
- Renamed String::set_quick() to String::set_buffer_if_not_allocated() to
clarify what the function really does.
- Rename of protocol function:
bool store(const char *from, CHARSET_INFO *cs) to
bool store_string_or_null(const char *from, CHARSET_INFO *cs).
This was done to both clarify the difference between this 'store' function
and also to make it easier to find unoptimal usage of store() calls.
- Added Protocol::store(const LEX_CSTRING*, CHARSET_INFO*)
- Changed some 'const char*' arrays to instead be of type LEX_CSTRING.
- class Item_func_units now used LEX_CSTRING for name.
Other things:
- Fixed a bug in mysql.cc:construct_prompt() where a wrong escape character
in the prompt would cause some part of the prompt to be duplicated.
- Fixed a lot of instances where the length of the argument to
append is known or easily obtain but was not used.
- Removed some not needed 'virtual' definition for functions that was
inherited from the parent. I added override to these.
- Fixed Ordered_key::print() to preallocate needed buffer. Old code could
case memory overruns.
- Simplified some loops when adding char * to a String with delimiters.
2020-08-12 20:29:55 +03:00
|
|
|
dest->append('-') ||
|
2013-03-11 16:02:40 +01:00
|
|
|
dest->append_ulonglong(gtid->seq_no);
|
|
|
|
}
|
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
/*
|
|
|
|
Sort the given gtid list based on domain_id and store them in the specified
|
|
|
|
string.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
rpl_slave_state_tostring_helper(DYNAMIC_ARRAY *gtid_dynarr, String *str)
|
|
|
|
{
|
|
|
|
bool first= true, res= true;
|
|
|
|
|
|
|
|
sort_dynamic(gtid_dynarr, rpl_gtid_cmp_cb);
|
|
|
|
|
|
|
|
for (uint i= 0; i < gtid_dynarr->elements; i ++)
|
|
|
|
{
|
|
|
|
rpl_gtid *gtid= dynamic_element(gtid_dynarr, i, rpl_gtid *);
|
|
|
|
if (rpl_slave_state_tostring_helper(str, gtid, &first))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
res= false;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Sort the given gtid list based on domain_id and call cb for each gtid. */
|
|
|
|
static bool
|
|
|
|
rpl_slave_state_tostring_helper(DYNAMIC_ARRAY *gtid_dynarr,
|
|
|
|
int (*cb)(rpl_gtid *, void *),
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
rpl_gtid *gtid;
|
|
|
|
bool res= true;
|
|
|
|
|
|
|
|
sort_dynamic(gtid_dynarr, rpl_gtid_cmp_cb);
|
|
|
|
|
|
|
|
for (uint i= 0; i < gtid_dynarr->elements; i ++)
|
|
|
|
{
|
|
|
|
gtid= dynamic_element(gtid_dynarr, i, rpl_gtid *);
|
|
|
|
if ((*cb)(gtid, data))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
res= false;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return res;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
int
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
|
2015-02-27 23:33:22 -05:00
|
|
|
rpl_gtid *extra_gtids, uint32 num_extra,
|
|
|
|
bool sort)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
HASH gtid_hash;
|
|
|
|
uchar *rec;
|
|
|
|
rpl_gtid *gtid;
|
|
|
|
int res= 1;
|
2015-02-27 23:33:22 -05:00
|
|
|
bool locked= false;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2020-02-27 11:52:20 +01:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, >id_hash, &my_charset_bin, 32,
|
2021-09-30 10:14:28 +02:00
|
|
|
offsetof(rpl_gtid, domain_id), sizeof(rpl_gtid::domain_id),
|
|
|
|
NULL, NULL, HASH_UNIQUE);
|
2013-03-11 16:02:40 +01:00
|
|
|
for (i= 0; i < num_extra; ++i)
|
2013-03-18 15:09:36 +01:00
|
|
|
if (extra_gtids[i].server_id == global_system_variables.server_id &&
|
|
|
|
my_hash_insert(>id_hash, (uchar *)(&extra_gtids[i])))
|
2013-03-11 16:02:40 +01:00
|
|
|
goto err;
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
2015-02-27 23:33:22 -05:00
|
|
|
locked= true;
|
|
|
|
reset_dynamic(>id_sort_array);
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
uint64 best_sub_id;
|
|
|
|
rpl_gtid best_gtid;
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
|
|
|
list_element *l= e->list;
|
|
|
|
|
|
|
|
if (!l)
|
|
|
|
continue; /* Nothing here */
|
|
|
|
|
|
|
|
best_gtid.domain_id= e->domain_id;
|
|
|
|
best_gtid.server_id= l->server_id;
|
|
|
|
best_gtid.seq_no= l->seq_no;
|
|
|
|
best_sub_id= l->sub_id;
|
|
|
|
while ((l= l->next))
|
|
|
|
{
|
|
|
|
if (l->sub_id > best_sub_id)
|
|
|
|
{
|
|
|
|
best_sub_id= l->sub_id;
|
|
|
|
best_gtid.server_id= l->server_id;
|
|
|
|
best_gtid.seq_no= l->seq_no;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we have something newer in the extra list. */
|
2021-09-30 10:14:28 +02:00
|
|
|
rec= my_hash_search(>id_hash, (const uchar *)&best_gtid.domain_id,
|
|
|
|
sizeof(best_gtid.domain_id));
|
2013-03-11 16:02:40 +01:00
|
|
|
if (rec)
|
|
|
|
{
|
|
|
|
gtid= (rpl_gtid *)rec;
|
|
|
|
if (gtid->seq_no > best_gtid.seq_no)
|
|
|
|
memcpy(&best_gtid, gtid, sizeof(best_gtid));
|
|
|
|
if (my_hash_delete(>id_hash, rec))
|
|
|
|
{
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
if ((res= sort ? insert_dynamic(>id_sort_array,
|
|
|
|
(const void *) &best_gtid) :
|
|
|
|
(*cb)(&best_gtid, data)))
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Also add any remaining extra domain_ids. */
|
|
|
|
for (i= 0; i < gtid_hash.records; ++i)
|
|
|
|
{
|
|
|
|
gtid= (rpl_gtid *)my_hash_element(>id_hash, i);
|
2015-02-27 23:33:22 -05:00
|
|
|
if ((res= sort ? insert_dynamic(>id_sort_array, (const void *) gtid) :
|
|
|
|
(*cb)(gtid, data)))
|
|
|
|
{
|
2013-03-11 16:02:40 +01:00
|
|
|
goto err;
|
2015-02-27 23:33:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sort && rpl_slave_state_tostring_helper(>id_sort_array, cb, data))
|
|
|
|
{
|
|
|
|
goto err;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
res= 0;
|
|
|
|
|
|
|
|
err:
|
2015-02-27 23:33:22 -05:00
|
|
|
if (locked) mysql_mutex_unlock(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
my_hash_free(>id_hash);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
struct rpl_slave_state_tostring_data {
|
|
|
|
String *dest;
|
|
|
|
bool first;
|
|
|
|
};
|
|
|
|
static int
|
|
|
|
rpl_slave_state_tostring_cb(rpl_gtid *gtid, void *data)
|
|
|
|
{
|
|
|
|
rpl_slave_state_tostring_data *p= (rpl_slave_state_tostring_data *)data;
|
|
|
|
return rpl_slave_state_tostring_helper(p->dest, gtid, &p->first);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Prepare the current slave state as a string, suitable for sending to the
|
|
|
|
master to request to receive binlog events starting from that GTID state.
|
|
|
|
|
|
|
|
The state consists of the most recently applied GTID for each domain_id,
|
|
|
|
ie. the one with the highest sub_id within each domain_id.
|
|
|
|
|
|
|
|
Optinally, extra_gtids is a list of GTIDs from the binlog. This is used when
|
|
|
|
a server was previously a master and now needs to connect to a new master as
|
|
|
|
a slave. For each domain_id, if the GTID in the binlog was logged with our
|
|
|
|
own server_id _and_ has a higher seq_no than what is in the slave state,
|
|
|
|
then this should be used as the position to start replicating at. This
|
|
|
|
allows to promote a slave as new master, and connect the old master as a
|
|
|
|
slave with MASTER_GTID_POS=AUTO.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra)
|
|
|
|
{
|
|
|
|
struct rpl_slave_state_tostring_data data;
|
|
|
|
data.first= true;
|
|
|
|
data.dest= dest;
|
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
return iterate(rpl_slave_state_tostring_cb, &data, extra_gtids,
|
|
|
|
num_extra, true);
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-18 15:09:36 +01:00
|
|
|
/*
|
|
|
|
Lookup a domain_id in the current replication slave state.
|
|
|
|
|
|
|
|
Returns false if the domain_id has no entries in the slave state.
|
|
|
|
Otherwise returns true, and fills in out_gtid with the corresponding
|
|
|
|
GTID.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
rpl_slave_state::domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid)
|
|
|
|
{
|
|
|
|
element *elem;
|
|
|
|
list_element *list;
|
|
|
|
uint64 best_sub_id;
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
2021-09-30 10:14:28 +02:00
|
|
|
elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
|
|
|
|
sizeof(domain_id));
|
2013-03-18 15:09:36 +01:00
|
|
|
if (!elem || !(list= elem->list))
|
|
|
|
{
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
2013-03-18 15:09:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
out_gtid->domain_id= domain_id;
|
|
|
|
out_gtid->server_id= list->server_id;
|
|
|
|
out_gtid->seq_no= list->seq_no;
|
|
|
|
best_sub_id= list->sub_id;
|
|
|
|
|
|
|
|
while ((list= list->next))
|
|
|
|
{
|
|
|
|
if (best_sub_id > list->sub_id)
|
|
|
|
continue;
|
|
|
|
best_sub_id= list->sub_id;
|
|
|
|
out_gtid->server_id= list->server_id;
|
|
|
|
out_gtid->seq_no= list->seq_no;
|
|
|
|
}
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
2013-03-18 15:09:36 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
#endif
|
2013-03-18 15:09:36 +01:00
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
/*
|
|
|
|
Parse a GTID at the start of a string, and update the pointer to point
|
|
|
|
at the first character after the parsed GTID.
|
|
|
|
|
|
|
|
Returns 0 on ok, non-zero on parse error.
|
|
|
|
*/
|
|
|
|
static int
|
2017-04-23 19:39:57 +03:00
|
|
|
gtid_parser_helper(const char **ptr, const char *end, rpl_gtid *out_gtid)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
char *q;
|
2017-04-23 19:39:57 +03:00
|
|
|
const char *p= *ptr;
|
2013-03-11 16:02:40 +01:00
|
|
|
uint64 v1, v2, v3;
|
|
|
|
int err= 0;
|
|
|
|
|
2017-04-23 19:39:57 +03:00
|
|
|
q= (char*) end;
|
2013-03-11 16:02:40 +01:00
|
|
|
v1= (uint64)my_strtoll10(p, &q, &err);
|
|
|
|
if (err != 0 || v1 > (uint32)0xffffffff || q == end || *q != '-')
|
|
|
|
return 1;
|
|
|
|
p= q+1;
|
2017-04-23 19:39:57 +03:00
|
|
|
q= (char*) end;
|
2013-03-11 16:02:40 +01:00
|
|
|
v2= (uint64)my_strtoll10(p, &q, &err);
|
|
|
|
if (err != 0 || v2 > (uint32)0xffffffff || q == end || *q != '-')
|
|
|
|
return 1;
|
|
|
|
p= q+1;
|
2017-04-23 19:39:57 +03:00
|
|
|
q= (char*) end;
|
2013-03-11 16:02:40 +01:00
|
|
|
v3= (uint64)my_strtoll10(p, &q, &err);
|
|
|
|
if (err != 0)
|
|
|
|
return 1;
|
|
|
|
|
2016-06-24 02:25:14 +03:00
|
|
|
out_gtid->domain_id= (uint32) v1;
|
|
|
|
out_gtid->server_id= (uint32) v2;
|
2013-03-11 16:02:40 +01:00
|
|
|
out_gtid->seq_no= v3;
|
|
|
|
*ptr= q;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-23 14:02:13 +02:00
|
|
|
rpl_gtid *
|
|
|
|
gtid_parse_string_to_list(const char *str, size_t str_len, uint32 *out_len)
|
|
|
|
{
|
2017-04-23 19:39:57 +03:00
|
|
|
const char *p= const_cast<char *>(str);
|
|
|
|
const char *end= p + str_len;
|
2013-08-23 14:02:13 +02:00
|
|
|
uint32 len= 0, alloc_len= 5;
|
|
|
|
rpl_gtid *list= NULL;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
rpl_gtid gtid;
|
|
|
|
|
|
|
|
if (len >= (((uint32)1 << 28)-1) || gtid_parser_helper(&p, end, >id))
|
|
|
|
{
|
|
|
|
my_free(list);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if ((!list || len >= alloc_len) &&
|
|
|
|
!(list=
|
2020-01-29 13:50:26 +01:00
|
|
|
(rpl_gtid *)my_realloc(PSI_INSTRUMENT_ME, list,
|
2013-08-23 14:02:13 +02:00
|
|
|
(alloc_len= alloc_len*2) * sizeof(rpl_gtid),
|
|
|
|
MYF(MY_FREE_ON_ERROR|MY_ALLOW_ZERO_PTR))))
|
|
|
|
return NULL;
|
|
|
|
list[len++]= gtid;
|
|
|
|
|
|
|
|
if (p == end)
|
|
|
|
break;
|
|
|
|
if (*p != ',')
|
|
|
|
{
|
|
|
|
my_free(list);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
*out_len= len;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
#ifndef MYSQL_CLIENT
|
2013-08-23 14:02:13 +02:00
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
/*
|
|
|
|
Update the slave replication state with the GTID position obtained from
|
|
|
|
master when connecting with old-style (filename,offset) position.
|
|
|
|
|
|
|
|
If RESET is true then all existing entries are removed. Otherwise only
|
|
|
|
domain_ids mentioned in the STATE_FROM_MASTER are changed.
|
|
|
|
|
|
|
|
Returns 0 if ok, non-zero if error.
|
|
|
|
*/
|
|
|
|
int
|
2017-04-23 19:39:57 +03:00
|
|
|
rpl_slave_state::load(THD *thd, const char *state_from_master, size_t len,
|
2013-05-22 17:36:48 +02:00
|
|
|
bool reset, bool in_statement)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2017-04-23 19:39:57 +03:00
|
|
|
const char *end= state_from_master + len;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2023-07-02 21:16:03 +02:00
|
|
|
mysql_mutex_assert_not_owner(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
if (reset)
|
|
|
|
{
|
|
|
|
if (truncate_state_table(thd))
|
|
|
|
return 1;
|
|
|
|
truncate_hash();
|
|
|
|
}
|
|
|
|
if (state_from_master == end)
|
|
|
|
return 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
rpl_gtid gtid;
|
|
|
|
uint64 sub_id;
|
2017-03-09 13:27:27 +01:00
|
|
|
void *hton= NULL;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
if (gtid_parser_helper(&state_from_master, end, >id) ||
|
2013-06-20 09:04:44 +02:00
|
|
|
!(sub_id= next_sub_id(gtid.domain_id)) ||
|
2018-10-14 20:41:49 +02:00
|
|
|
record_gtid(thd, >id, sub_id, false, in_statement, &hton) ||
|
2017-03-09 13:27:27 +01:00
|
|
|
update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no, hton, NULL))
|
2013-03-11 16:02:40 +01:00
|
|
|
return 1;
|
|
|
|
if (state_from_master == end)
|
|
|
|
break;
|
|
|
|
if (*state_from_master != ',')
|
|
|
|
return 1;
|
|
|
|
++state_from_master;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
rpl_slave_state::is_empty()
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
bool result= true;
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_lock(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
|
|
|
if (e->list)
|
|
|
|
{
|
|
|
|
result= false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_slave_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-09 12:16:15 +01:00
|
|
|
void
|
|
|
|
rpl_slave_state::free_gtid_pos_tables(struct rpl_slave_state::gtid_pos_table *list)
|
|
|
|
{
|
|
|
|
struct gtid_pos_table *cur, *next;
|
|
|
|
|
|
|
|
cur= list;
|
|
|
|
while (cur)
|
|
|
|
{
|
|
|
|
next= cur->next;
|
|
|
|
my_free(cur);
|
|
|
|
cur= next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-14 12:54:10 +01:00
|
|
|
/*
|
|
|
|
Replace the list of available mysql.gtid_slave_posXXX tables with a new list.
|
|
|
|
The caller must be holding LOCK_slave_state. Additionally, this function
|
|
|
|
must only be called while all SQL threads are stopped.
|
|
|
|
*/
|
2017-03-09 12:16:15 +01:00
|
|
|
void
|
2017-03-14 12:54:10 +01:00
|
|
|
rpl_slave_state::set_gtid_pos_tables_list(rpl_slave_state::gtid_pos_table *new_list,
|
|
|
|
rpl_slave_state::gtid_pos_table *default_entry)
|
2017-03-09 12:16:15 +01:00
|
|
|
{
|
|
|
|
mysql_mutex_assert_owner(&LOCK_slave_state);
|
2020-03-21 17:36:38 +04:00
|
|
|
auto old_list= gtid_pos_tables.load(std::memory_order_relaxed);
|
|
|
|
gtid_pos_tables.store(new_list, std::memory_order_release);
|
2020-03-21 15:52:24 +04:00
|
|
|
default_gtid_pos_table.store(default_entry, std::memory_order_release);
|
2017-03-09 12:16:15 +01:00
|
|
|
free_gtid_pos_tables(old_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-14 12:54:10 +01:00
|
|
|
void
|
|
|
|
rpl_slave_state::add_gtid_pos_table(rpl_slave_state::gtid_pos_table *entry)
|
|
|
|
{
|
|
|
|
mysql_mutex_assert_owner(&LOCK_slave_state);
|
2020-03-21 17:36:38 +04:00
|
|
|
entry->next= gtid_pos_tables.load(std::memory_order_relaxed);
|
|
|
|
gtid_pos_tables.store(entry, std::memory_order_release);
|
2017-03-14 12:54:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-09 12:16:15 +01:00
|
|
|
struct rpl_slave_state::gtid_pos_table *
|
2017-07-03 10:36:09 +02:00
|
|
|
rpl_slave_state::alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton,
|
2017-03-24 12:07:07 +01:00
|
|
|
rpl_slave_state::gtid_pos_table_state state)
|
2017-03-09 12:16:15 +01:00
|
|
|
{
|
|
|
|
struct gtid_pos_table *p;
|
|
|
|
char *allocated_str;
|
|
|
|
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &p, sizeof(*p),
|
|
|
|
&allocated_str, table_name->length+1, NULL))
|
2017-03-09 12:16:15 +01:00
|
|
|
{
|
|
|
|
my_error(ER_OUTOFMEMORY, MYF(0), (int)(sizeof(*p) + table_name->length+1));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memcpy(allocated_str, table_name->str, table_name->length+1); // Also copy '\0'
|
|
|
|
p->next = NULL;
|
|
|
|
p->table_hton= hton;
|
|
|
|
p->table_name.str= allocated_str;
|
|
|
|
p->table_name.length= table_name->length;
|
2017-03-24 12:07:07 +01:00
|
|
|
p->state= state;
|
2017-03-09 12:16:15 +01:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-28 17:15:38 +03:00
|
|
|
void rpl_binlog_state::init()
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2021-09-30 10:14:28 +02:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
|
|
|
|
offsetof(element, domain_id), sizeof(element::domain_id),
|
|
|
|
NULL, my_free, HASH_UNIQUE);
|
2020-02-27 11:52:20 +01:00
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, >id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
|
2013-03-11 16:02:40 +01:00
|
|
|
mysql_mutex_init(key_LOCK_binlog_state, &LOCK_binlog_state,
|
|
|
|
MY_MUTEX_INIT_SLOW);
|
2013-05-05 21:39:31 +03:00
|
|
|
initialized= 1;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-11-18 15:22:50 +01:00
|
|
|
rpl_binlog_state::reset_nolock()
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
my_hash_free(&((element *)my_hash_element(&hash, i))->hash);
|
|
|
|
my_hash_reset(&hash);
|
|
|
|
}
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
rpl_binlog_state::reset()
|
|
|
|
{
|
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
reset_nolock();
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-05 21:39:31 +03:00
|
|
|
void rpl_binlog_state::free()
|
|
|
|
{
|
|
|
|
if (initialized)
|
|
|
|
{
|
|
|
|
initialized= 0;
|
2013-11-18 15:22:50 +01:00
|
|
|
reset_nolock();
|
2013-05-05 21:39:31 +03:00
|
|
|
my_hash_free(&hash);
|
2015-02-27 23:33:22 -05:00
|
|
|
delete_dynamic(>id_sort_array);
|
2013-05-05 21:39:31 +03:00
|
|
|
mysql_mutex_destroy(&LOCK_binlog_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 19:52:21 +02:00
|
|
|
|
|
|
|
bool
|
|
|
|
rpl_binlog_state::load(struct rpl_gtid *list, uint32 count)
|
|
|
|
{
|
|
|
|
uint32 i;
|
2013-11-18 15:22:50 +01:00
|
|
|
bool res= false;
|
2013-05-15 19:52:21 +02:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
reset_nolock();
|
2013-05-15 19:52:21 +02:00
|
|
|
for (i= 0; i < count; ++i)
|
|
|
|
{
|
2013-11-18 15:22:50 +01:00
|
|
|
if (update_nolock(&(list[i]), false))
|
|
|
|
{
|
|
|
|
res= true;
|
|
|
|
break;
|
|
|
|
}
|
2013-05-15 19:52:21 +02:00
|
|
|
}
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-05-15 19:52:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
MDEV-6589: Incorrect relay log start position when restarting SQL thread after error in parallel replication
The problem occurs in parallel replication in GTID mode, when we are using
multiple replication domains. In this case, if the SQL thread stops, the
slave GTID position may refer to a different point in the relay log for each
domain.
The bug was that when the SQL thread was stopped and restarted (but the IO
thread was kept running), the SQL thread would resume applying the relay log
from the point of the most advanced replication domain, silently skipping all
earlier events within other domains. This caused replication corruption.
This patch solves the problem by storing, when the SQL thread stops with
multiple parallel replication domains active, the current GTID
position. Additionally, the current position in the relay logs is moved back
to a point known to be earlier than the current position of any replication
domain. Then when the SQL thread restarts from the earlier position, GTIDs
encountered are compared against the stored GTID position. Any GTID that was
already applied before the stop is skipped to avoid duplicate apply.
This patch should have no effect if multi-domain GTID parallel replication is
not used. Similarly, if both SQL and IO thread are stopped and restarted, the
patch has no effect, as in this case the existing relay logs are removed and
re-fetched from the master at the current global @@gtid_slave_pos.
2015-02-18 12:22:50 +01:00
|
|
|
static int rpl_binlog_state_load_cb(rpl_gtid *gtid, void *data)
|
|
|
|
{
|
|
|
|
rpl_binlog_state *self= (rpl_binlog_state *)data;
|
|
|
|
return self->update_nolock(gtid, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
rpl_binlog_state::load(rpl_slave_state *slave_pos)
|
|
|
|
{
|
|
|
|
bool res= false;
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
reset_nolock();
|
2015-03-04 14:06:44 +01:00
|
|
|
if (slave_pos->iterate(rpl_binlog_state_load_cb, this, NULL, 0, false))
|
MDEV-6589: Incorrect relay log start position when restarting SQL thread after error in parallel replication
The problem occurs in parallel replication in GTID mode, when we are using
multiple replication domains. In this case, if the SQL thread stops, the
slave GTID position may refer to a different point in the relay log for each
domain.
The bug was that when the SQL thread was stopped and restarted (but the IO
thread was kept running), the SQL thread would resume applying the relay log
from the point of the most advanced replication domain, silently skipping all
earlier events within other domains. This caused replication corruption.
This patch solves the problem by storing, when the SQL thread stops with
multiple parallel replication domains active, the current GTID
position. Additionally, the current position in the relay logs is moved back
to a point known to be earlier than the current position of any replication
domain. Then when the SQL thread restarts from the earlier position, GTIDs
encountered are compared against the stored GTID position. Any GTID that was
already applied before the stop is skipped to avoid duplicate apply.
This patch should have no effect if multi-domain GTID parallel replication is
not used. Similarly, if both SQL and IO thread are stopped and restarted, the
patch has no effect, as in this case the existing relay logs are removed and
re-fetched from the master at the current global @@gtid_slave_pos.
2015-02-18 12:22:50 +01:00
|
|
|
res= true;
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
rpl_binlog_state::~rpl_binlog_state()
|
|
|
|
{
|
2013-05-05 21:39:31 +03:00
|
|
|
free();
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Update replication state with a new GTID.
|
|
|
|
|
|
|
|
If the (domain_id, server_id) pair already exists, then the new GTID replaces
|
|
|
|
the old one for that domain id. Else a new entry is inserted.
|
|
|
|
|
|
|
|
Returns 0 for ok, 1 for error.
|
|
|
|
*/
|
|
|
|
int
|
2013-11-18 15:22:50 +01:00
|
|
|
rpl_binlog_state::update_nolock(const struct rpl_gtid *gtid, bool strict)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
element *elem;
|
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
if ((elem= (element *)my_hash_search(&hash,
|
2021-09-30 10:14:28 +02:00
|
|
|
(const uchar *)(>id->domain_id),
|
|
|
|
sizeof(gtid->domain_id))))
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2013-05-28 13:28:31 +02:00
|
|
|
if (strict && elem->last_gtid && elem->last_gtid->seq_no >= gtid->seq_no)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2013-05-28 13:28:31 +02:00
|
|
|
my_error(ER_GTID_STRICT_OUT_OF_ORDER, MYF(0), gtid->domain_id,
|
|
|
|
gtid->server_id, gtid->seq_no, elem->last_gtid->domain_id,
|
|
|
|
elem->last_gtid->server_id, elem->last_gtid->seq_no);
|
|
|
|
return 1;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
2013-05-28 13:28:31 +02:00
|
|
|
if (elem->seq_no_counter < gtid->seq_no)
|
|
|
|
elem->seq_no_counter= gtid->seq_no;
|
|
|
|
if (!elem->update_element(gtid))
|
|
|
|
return 0;
|
|
|
|
}
|
2013-11-18 15:22:50 +01:00
|
|
|
else if (!alloc_element_nolock(gtid))
|
2013-05-28 13:28:31 +02:00
|
|
|
return 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
int
|
|
|
|
rpl_binlog_state::update(const struct rpl_gtid *gtid, bool strict)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
res= update_nolock(gtid, strict);
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
/*
|
|
|
|
Fill in a new GTID, allocating next sequence number, and update state
|
|
|
|
accordingly.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rpl_binlog_state::update_with_next_gtid(uint32 domain_id, uint32 server_id,
|
|
|
|
rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
element *elem;
|
2013-11-18 15:22:50 +01:00
|
|
|
int res= 0;
|
2013-05-28 13:28:31 +02:00
|
|
|
|
|
|
|
gtid->domain_id= domain_id;
|
|
|
|
gtid->server_id= server_id;
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2021-09-30 10:14:28 +02:00
|
|
|
if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id),
|
|
|
|
sizeof(domain_id))))
|
2013-05-28 13:28:31 +02:00
|
|
|
{
|
|
|
|
gtid->seq_no= ++elem->seq_no_counter;
|
|
|
|
if (!elem->update_element(gtid))
|
2013-11-18 15:22:50 +01:00
|
|
|
goto end;
|
2013-05-28 13:28:31 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gtid->seq_no= 1;
|
2013-11-18 15:22:50 +01:00
|
|
|
if (!alloc_element_nolock(gtid))
|
|
|
|
goto end;
|
2013-05-28 13:28:31 +02:00
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
2013-11-18 15:22:50 +01:00
|
|
|
res= 1;
|
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-05-28 13:28:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper functions for update. */
|
|
|
|
int
|
|
|
|
rpl_binlog_state::element::update_element(const rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
rpl_gtid *lookup_gtid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
By far the most common case is that successive events within same
|
|
|
|
replication domain have the same server id (it changes only when
|
|
|
|
switching to a new master). So save a hash lookup in this case.
|
|
|
|
*/
|
|
|
|
if (likely(last_gtid && last_gtid->server_id == gtid->server_id))
|
|
|
|
{
|
|
|
|
last_gtid->seq_no= gtid->seq_no;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
lookup_gtid= (rpl_gtid *)
|
2021-09-30 10:14:28 +02:00
|
|
|
my_hash_search(&hash, (const uchar *)>id->server_id,
|
|
|
|
sizeof(gtid->server_id));
|
2013-05-28 13:28:31 +02:00
|
|
|
if (lookup_gtid)
|
|
|
|
{
|
|
|
|
lookup_gtid->seq_no= gtid->seq_no;
|
|
|
|
last_gtid= lookup_gtid;
|
2013-03-11 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
/* Allocate a new GTID and insert it. */
|
2020-01-29 13:50:26 +01:00
|
|
|
lookup_gtid= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*lookup_gtid),
|
|
|
|
MYF(MY_WME));
|
2013-05-28 13:28:31 +02:00
|
|
|
if (!lookup_gtid)
|
|
|
|
return 1;
|
|
|
|
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
|
|
|
|
if (my_hash_insert(&hash, (const uchar *)lookup_gtid))
|
|
|
|
{
|
|
|
|
my_free(lookup_gtid);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
last_gtid= lookup_gtid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2013-11-18 15:22:50 +01:00
|
|
|
rpl_binlog_state::alloc_element_nolock(const rpl_gtid *gtid)
|
2013-05-28 13:28:31 +02:00
|
|
|
{
|
|
|
|
element *elem;
|
|
|
|
rpl_gtid *lookup_gtid;
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
/* First time we see this domain_id; allocate a new element. */
|
2020-01-29 13:50:26 +01:00
|
|
|
elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem), MYF(MY_WME));
|
|
|
|
lookup_gtid= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*lookup_gtid),
|
|
|
|
MYF(MY_WME));
|
2013-03-11 16:02:40 +01:00
|
|
|
if (elem && lookup_gtid)
|
|
|
|
{
|
|
|
|
elem->domain_id= gtid->domain_id;
|
2020-02-27 11:52:20 +01:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32,
|
2021-09-30 10:14:28 +02:00
|
|
|
offsetof(rpl_gtid, server_id), sizeof(rpl_gtid::domain_id),
|
|
|
|
NULL, my_free, HASH_UNIQUE);
|
2013-03-11 16:02:40 +01:00
|
|
|
elem->last_gtid= lookup_gtid;
|
2013-05-28 13:28:31 +02:00
|
|
|
elem->seq_no_counter= gtid->seq_no;
|
2013-03-11 16:02:40 +01:00
|
|
|
memcpy(lookup_gtid, gtid, sizeof(*lookup_gtid));
|
|
|
|
if (0 == my_hash_insert(&elem->hash, (const uchar *)lookup_gtid))
|
|
|
|
{
|
|
|
|
lookup_gtid= NULL; /* Do not free. */
|
|
|
|
if (0 == my_hash_insert(&hash, (const uchar *)elem))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
my_hash_free(&elem->hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* An error. */
|
|
|
|
if (elem)
|
|
|
|
my_free(elem);
|
|
|
|
if (lookup_gtid)
|
|
|
|
my_free(lookup_gtid);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
/*
|
|
|
|
Check that a new GTID can be logged without creating an out-of-order
|
|
|
|
sequence number with existing GTIDs.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
rpl_binlog_state::check_strict_sequence(uint32 domain_id, uint32 server_id,
|
2022-06-30 15:46:19 +03:00
|
|
|
uint64 seq_no, bool no_error)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2013-05-28 13:28:31 +02:00
|
|
|
element *elem;
|
2013-11-18 15:22:50 +01:00
|
|
|
bool res= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2013-05-28 13:28:31 +02:00
|
|
|
if ((elem= (element *)my_hash_search(&hash,
|
2021-09-30 10:14:28 +02:00
|
|
|
(const uchar *)(&domain_id),
|
|
|
|
sizeof(domain_id))) &&
|
2013-05-28 13:28:31 +02:00
|
|
|
elem->last_gtid && elem->last_gtid->seq_no >= seq_no)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2022-06-30 15:46:19 +03:00
|
|
|
if (!no_error)
|
|
|
|
my_error(ER_GTID_STRICT_OUT_OF_ORDER, MYF(0), domain_id, server_id, seq_no,
|
|
|
|
elem->last_gtid->domain_id, elem->last_gtid->server_id,
|
|
|
|
elem->last_gtid->seq_no);
|
2013-11-18 15:22:50 +01:00
|
|
|
res= 1;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-05-28 13:28:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
When we see a new GTID that will not be binlogged (eg. slave thread
|
|
|
|
with --log-slave-updates=0), then we need to remember to allocate any
|
|
|
|
GTID seq_no of our own within that domain starting from there.
|
|
|
|
|
|
|
|
Returns 0 if ok, non-zero if out-of-memory.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
|
|
|
|
{
|
|
|
|
element *elem;
|
2013-11-18 15:22:50 +01:00
|
|
|
int res;
|
2013-05-28 13:28:31 +02:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2021-09-30 10:14:28 +02:00
|
|
|
if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id),
|
|
|
|
sizeof(domain_id))))
|
2013-05-28 13:28:31 +02:00
|
|
|
{
|
|
|
|
if (elem->seq_no_counter < seq_no)
|
|
|
|
elem->seq_no_counter= seq_no;
|
2013-11-18 15:22:50 +01:00
|
|
|
res= 0;
|
|
|
|
goto end;
|
2013-05-28 13:28:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We need to allocate a new, empty element to remember the next seq_no. */
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(elem= (element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*elem),
|
|
|
|
MYF(MY_WME))))
|
2013-11-18 15:22:50 +01:00
|
|
|
{
|
|
|
|
res= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-05-28 13:28:31 +02:00
|
|
|
|
|
|
|
elem->domain_id= domain_id;
|
2020-02-27 11:52:20 +01:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &elem->hash, &my_charset_bin, 32,
|
2021-09-30 10:14:28 +02:00
|
|
|
offsetof(rpl_gtid, server_id), sizeof(rpl_gtid::server_id),
|
|
|
|
NULL, my_free, HASH_UNIQUE);
|
2013-05-28 13:28:31 +02:00
|
|
|
elem->last_gtid= NULL;
|
|
|
|
elem->seq_no_counter= seq_no;
|
|
|
|
if (0 == my_hash_insert(&hash, (const uchar *)elem))
|
2013-11-18 15:22:50 +01:00
|
|
|
{
|
|
|
|
res= 0;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-05-28 13:28:31 +02:00
|
|
|
|
|
|
|
my_hash_free(&elem->hash);
|
|
|
|
my_free(elem);
|
2013-11-18 15:22:50 +01:00
|
|
|
res= 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Write binlog state to text file, so we can read it in again without having
|
|
|
|
to scan last binlog file (normal shutdown/startup, not crash recovery).
|
|
|
|
|
|
|
|
The most recent GTID within each domain_id is written after any other GTID
|
|
|
|
within this domain.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rpl_binlog_state::write_to_iocache(IO_CACHE *dest)
|
|
|
|
{
|
|
|
|
ulong i, j;
|
|
|
|
char buf[21];
|
2013-11-18 15:22:50 +01:00
|
|
|
int res= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
2013-05-28 13:28:31 +02:00
|
|
|
if (!e->last_gtid)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(e->hash.records == 0);
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
for (j= 0; j <= e->hash.records; ++j)
|
|
|
|
{
|
|
|
|
const rpl_gtid *gtid;
|
|
|
|
if (j < e->hash.records)
|
|
|
|
{
|
|
|
|
gtid= (const rpl_gtid *)my_hash_element(&e->hash, j);
|
|
|
|
if (gtid == e->last_gtid)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
gtid= e->last_gtid;
|
|
|
|
|
|
|
|
longlong10_to_str(gtid->seq_no, buf, 10);
|
2017-12-23 16:59:41 +02:00
|
|
|
if (my_b_printf(dest, "%u-%u-%s\n", gtid->domain_id, gtid->server_id,
|
|
|
|
buf))
|
2013-11-18 15:22:50 +01:00
|
|
|
{
|
|
|
|
res= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
rpl_binlog_state::read_from_iocache(IO_CACHE *src)
|
|
|
|
{
|
|
|
|
/* 10-digit - 10-digit - 20-digit \n \0 */
|
|
|
|
char buf[10+1+10+1+20+1+1];
|
2017-04-23 19:39:57 +03:00
|
|
|
const char *p, *end;
|
2013-03-11 16:02:40 +01:00
|
|
|
rpl_gtid gtid;
|
2013-11-18 15:22:50 +01:00
|
|
|
int res= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
reset_nolock();
|
2013-03-11 16:02:40 +01:00
|
|
|
for (;;)
|
|
|
|
{
|
2013-11-18 15:22:50 +01:00
|
|
|
size_t len= my_b_gets(src, buf, sizeof(buf));
|
|
|
|
if (!len)
|
2013-03-11 16:02:40 +01:00
|
|
|
break;
|
|
|
|
p= buf;
|
2013-11-18 15:22:50 +01:00
|
|
|
end= buf + len;
|
|
|
|
if (gtid_parser_helper(&p, end, >id) ||
|
|
|
|
update_nolock(>id, false))
|
|
|
|
{
|
|
|
|
res= 1;
|
|
|
|
break;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-18 15:09:36 +01:00
|
|
|
rpl_gtid *
|
2013-11-18 15:22:50 +01:00
|
|
|
rpl_binlog_state::find_nolock(uint32 domain_id, uint32 server_id)
|
2013-03-18 15:09:36 +01:00
|
|
|
{
|
|
|
|
element *elem;
|
2021-09-30 10:14:28 +02:00
|
|
|
if (!(elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
|
|
|
|
sizeof(domain_id))))
|
2013-03-18 15:09:36 +01:00
|
|
|
return NULL;
|
2021-09-30 10:14:28 +02:00
|
|
|
return (rpl_gtid *)my_hash_search(&elem->hash, (const uchar *)&server_id,
|
|
|
|
sizeof(server_id));
|
2013-03-18 15:09:36 +01:00
|
|
|
}
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
rpl_gtid *
|
|
|
|
rpl_binlog_state::find(uint32 domain_id, uint32 server_id)
|
|
|
|
{
|
|
|
|
rpl_gtid *p;
|
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
p= find_nolock(domain_id, server_id);
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2013-05-28 13:28:31 +02:00
|
|
|
rpl_gtid *
|
|
|
|
rpl_binlog_state::find_most_recent(uint32 domain_id)
|
|
|
|
{
|
|
|
|
element *elem;
|
2013-11-18 15:22:50 +01:00
|
|
|
rpl_gtid *gtid= NULL;
|
2013-05-28 13:28:31 +02:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2021-09-30 10:14:28 +02:00
|
|
|
elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id,
|
|
|
|
sizeof(domain_id));
|
2013-05-28 13:28:31 +02:00
|
|
|
if (elem && elem->last_gtid)
|
2013-11-18 15:22:50 +01:00
|
|
|
gtid= elem->last_gtid;
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
|
|
|
|
return gtid;
|
2013-05-28 13:28:31 +02:00
|
|
|
}
|
|
|
|
|
2013-03-18 15:09:36 +01:00
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
uint32
|
|
|
|
rpl_binlog_state::count()
|
|
|
|
{
|
|
|
|
uint32 c= 0;
|
|
|
|
uint32 i;
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
c+= ((element *)my_hash_element(&hash, i))->hash.records;
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
rpl_binlog_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
|
|
|
|
{
|
|
|
|
uint32 i, j, pos;
|
2013-11-18 15:22:50 +01:00
|
|
|
int res= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2013-03-11 16:02:40 +01:00
|
|
|
pos= 0;
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
2013-05-28 13:28:31 +02:00
|
|
|
if (!e->last_gtid)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(e->hash.records==0);
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
for (j= 0; j <= e->hash.records; ++j)
|
|
|
|
{
|
|
|
|
const rpl_gtid *gtid;
|
|
|
|
if (j < e->hash.records)
|
|
|
|
{
|
|
|
|
gtid= (rpl_gtid *)my_hash_element(&e->hash, j);
|
|
|
|
if (gtid == e->last_gtid)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
gtid= e->last_gtid;
|
|
|
|
|
|
|
|
if (pos >= list_size)
|
2013-11-18 15:22:50 +01:00
|
|
|
{
|
|
|
|
res= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-03-11 16:02:40 +01:00
|
|
|
memcpy(>id_list[pos++], gtid, sizeof(*gtid));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get a list of the most recently binlogged GTID, for each domain_id.
|
|
|
|
|
|
|
|
This can be used when switching from being a master to being a slave,
|
|
|
|
to know where to start replicating from the new master.
|
|
|
|
|
|
|
|
The returned list must be de-allocated with my_free().
|
|
|
|
|
|
|
|
Returns 0 for ok, non-zero for out-of-memory.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
|
|
|
|
{
|
|
|
|
uint32 i;
|
2013-05-28 13:28:31 +02:00
|
|
|
uint32 alloc_size, out_size;
|
2013-11-18 15:22:50 +01:00
|
|
|
int res= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
out_size= 0;
|
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2013-05-28 13:28:31 +02:00
|
|
|
alloc_size= hash.records;
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(*list= (rpl_gtid *)my_malloc(PSI_INSTRUMENT_ME,
|
|
|
|
alloc_size * sizeof(rpl_gtid), MYF(MY_WME))))
|
2013-11-18 15:22:50 +01:00
|
|
|
{
|
|
|
|
res= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-05-28 13:28:31 +02:00
|
|
|
for (i= 0; i < alloc_size; ++i)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
2013-05-28 13:28:31 +02:00
|
|
|
if (!e->last_gtid)
|
|
|
|
continue;
|
|
|
|
memcpy(&((*list)[out_size++]), e->last_gtid, sizeof(rpl_gtid));
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
2013-05-28 13:28:31 +02:00
|
|
|
*size= out_size;
|
2013-11-18 15:22:50 +01:00
|
|
|
return res;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
2013-05-22 17:36:48 +02:00
|
|
|
bool
|
|
|
|
rpl_binlog_state::append_pos(String *str)
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2015-02-27 23:33:22 -05:00
|
|
|
reset_dynamic(>id_sort_array);
|
|
|
|
|
2013-05-22 17:36:48 +02:00
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
2013-05-28 13:28:31 +02:00
|
|
|
if (e->last_gtid &&
|
2015-02-27 23:33:22 -05:00
|
|
|
insert_dynamic(>id_sort_array, (const void *) e->last_gtid))
|
|
|
|
{
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
2013-05-22 17:36:48 +02:00
|
|
|
return true;
|
2015-02-27 23:33:22 -05:00
|
|
|
}
|
2013-05-22 17:36:48 +02:00
|
|
|
}
|
2015-02-27 23:33:22 -05:00
|
|
|
rpl_slave_state_tostring_helper(>id_sort_array, str);
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
2013-05-22 17:36:48 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 14:02:13 +02:00
|
|
|
bool
|
|
|
|
rpl_binlog_state::append_state(String *str)
|
|
|
|
{
|
|
|
|
uint32 i, j;
|
2013-11-18 15:22:50 +01:00
|
|
|
bool res= false;
|
2013-08-23 14:02:13 +02:00
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
2015-02-27 23:33:22 -05:00
|
|
|
reset_dynamic(>id_sort_array);
|
|
|
|
|
2013-08-23 14:02:13 +02:00
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
element *e= (element *)my_hash_element(&hash, i);
|
|
|
|
if (!e->last_gtid)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(e->hash.records==0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (j= 0; j <= e->hash.records; ++j)
|
|
|
|
{
|
|
|
|
const rpl_gtid *gtid;
|
|
|
|
if (j < e->hash.records)
|
|
|
|
{
|
|
|
|
gtid= (rpl_gtid *)my_hash_element(&e->hash, j);
|
|
|
|
if (gtid == e->last_gtid)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
gtid= e->last_gtid;
|
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
if (insert_dynamic(>id_sort_array, (const void *) gtid))
|
2013-11-18 15:22:50 +01:00
|
|
|
{
|
|
|
|
res= true;
|
|
|
|
goto end;
|
|
|
|
}
|
2013-08-23 14:02:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 23:33:22 -05:00
|
|
|
rpl_slave_state_tostring_helper(>id_sort_array, str);
|
|
|
|
|
2013-11-18 15:22:50 +01:00
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
return res;
|
2013-08-23 14:02:13 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 21:56:59 +03:00
|
|
|
/**
|
|
|
|
Remove domains supplied by the first argument from binlog state.
|
|
|
|
Removal is done for any domain whose last gtids (from all its servers) match
|
|
|
|
ones in Gtid list event of the 2nd argument.
|
|
|
|
|
|
|
|
@param ids gtid domain id sequence, may contain dups
|
|
|
|
@param glev pointer to Gtid list event describing
|
|
|
|
the match condition
|
|
|
|
@param errbuf [out] pointer to possible error message array
|
|
|
|
|
|
|
|
@retval NULL as success when at least one domain is removed
|
|
|
|
@retval "" empty string to indicate ineffective call
|
|
|
|
when no domains removed
|
|
|
|
@retval NOT EMPTY string otherwise an error message
|
|
|
|
*/
|
|
|
|
const char*
|
|
|
|
rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
|
|
|
|
Gtid_list_log_event *glev,
|
|
|
|
char* errbuf)
|
|
|
|
{
|
|
|
|
DYNAMIC_ARRAY domain_unique; // sequece (unsorted) of unique element*:s
|
|
|
|
rpl_binlog_state::element* domain_unique_buffer[16];
|
|
|
|
ulong k, l;
|
|
|
|
const char* errmsg= NULL;
|
|
|
|
|
|
|
|
DBUG_ENTER("rpl_binlog_state::drop_domain");
|
|
|
|
|
2020-02-27 11:52:20 +01:00
|
|
|
my_init_dynamic_array2(PSI_INSTRUMENT_ME, &domain_unique,
|
2017-09-29 21:56:59 +03:00
|
|
|
sizeof(element*), domain_unique_buffer,
|
|
|
|
sizeof(domain_unique_buffer) / sizeof(element*), 4, 0);
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_binlog_state);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gtid list is supposed to come from a binlog's Gtid_list event and
|
|
|
|
therefore should be a subset of the current binlog state. That is
|
|
|
|
for every domain in the list the binlog state contains a gtid with
|
|
|
|
sequence number not less than that of the list.
|
|
|
|
Exceptions of this inclusion rule are:
|
|
|
|
A. the list may still refer to gtids from already deleted domains.
|
|
|
|
Files containing them must have been purged whereas the file
|
|
|
|
with the list is not yet.
|
|
|
|
B. out of order groups were injected
|
|
|
|
C. manually build list of binlog files violating the inclusion
|
|
|
|
constraint.
|
|
|
|
While A is a normal case (not necessarily distinguishable from C though),
|
|
|
|
B and C may require the user's attention so any (incl the A's suspected)
|
|
|
|
inconsistency is diagnosed and *warned*.
|
|
|
|
*/
|
|
|
|
for (l= 0, errbuf[0]= 0; l < glev->count; l++, errbuf[0]= 0)
|
|
|
|
{
|
|
|
|
rpl_gtid* rb_state_gtid= find_nolock(glev->list[l].domain_id,
|
|
|
|
glev->list[l].server_id);
|
|
|
|
if (!rb_state_gtid)
|
|
|
|
sprintf(errbuf,
|
|
|
|
"missing gtids from the '%u-%u' domain-server pair which is "
|
|
|
|
"referred to in the gtid list describing an earlier state. Ignore "
|
|
|
|
"if the domain ('%u') was already explicitly deleted",
|
|
|
|
glev->list[l].domain_id, glev->list[l].server_id,
|
|
|
|
glev->list[l].domain_id);
|
|
|
|
else if (rb_state_gtid->seq_no < glev->list[l].seq_no)
|
|
|
|
sprintf(errbuf,
|
|
|
|
"having a gtid '%u-%u-%llu' which is less than "
|
|
|
|
"the '%u-%u-%llu' of the gtid list describing an earlier state. "
|
|
|
|
"The state may have been affected by manually injecting "
|
|
|
|
"a lower sequence number gtid or via replication",
|
|
|
|
rb_state_gtid->domain_id, rb_state_gtid->server_id,
|
|
|
|
rb_state_gtid->seq_no, glev->list[l].domain_id,
|
|
|
|
glev->list[l].server_id, glev->list[l].seq_no);
|
|
|
|
if (strlen(errbuf)) // use strlen() as cheap flag
|
|
|
|
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
|
|
|
|
ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
|
|
|
|
"The current gtid binlog state is incompatible with "
|
|
|
|
"a former one %s.", errbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
For each domain_id from ids
|
2023-04-23 10:59:32 +02:00
|
|
|
If the domain is already absent from the binlog state
|
|
|
|
Warn && continue
|
|
|
|
If any GTID with that domain in binlog state is missing from glev.list
|
|
|
|
Error out binlog state can't change
|
2017-09-29 21:56:59 +03:00
|
|
|
*/
|
|
|
|
for (ulong i= 0; i < ids->elements; i++)
|
|
|
|
{
|
|
|
|
rpl_binlog_state::element *elem= NULL;
|
2018-10-08 21:47:53 +03:00
|
|
|
uint32 *ptr_domain_id;
|
2023-04-23 10:59:32 +02:00
|
|
|
bool all_found;
|
2017-09-29 21:56:59 +03:00
|
|
|
|
2018-10-08 21:47:53 +03:00
|
|
|
ptr_domain_id= (uint32*) dynamic_array_ptr(ids, i);
|
2017-09-29 21:56:59 +03:00
|
|
|
elem= (rpl_binlog_state::element *)
|
2021-09-30 10:14:28 +02:00
|
|
|
my_hash_search(&hash, (const uchar *) ptr_domain_id,
|
|
|
|
sizeof(ptr_domain_id[0]));
|
2017-09-29 21:56:59 +03:00
|
|
|
if (!elem)
|
|
|
|
{
|
|
|
|
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
|
|
|
|
ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
|
|
|
|
"The gtid domain being deleted ('%lu') is not in "
|
2021-09-06 08:47:54 +10:00
|
|
|
"the current binlog state", (unsigned long) *ptr_domain_id);
|
2017-09-29 21:56:59 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-04-23 10:59:32 +02:00
|
|
|
all_found= true;
|
|
|
|
for (k= 0; k < elem->hash.records && all_found; k++)
|
2017-09-29 21:56:59 +03:00
|
|
|
{
|
|
|
|
rpl_gtid *d_gtid= (rpl_gtid *)my_hash_element(&elem->hash, k);
|
2023-04-23 10:59:32 +02:00
|
|
|
bool match_found= false;
|
|
|
|
for (ulong l= 0; l < glev->count && !match_found; l++)
|
|
|
|
match_found= match_found || (*d_gtid == glev->list[l]);
|
|
|
|
if (!match_found)
|
|
|
|
all_found= false;
|
2017-09-29 21:56:59 +03:00
|
|
|
}
|
|
|
|
|
2023-04-23 10:59:32 +02:00
|
|
|
if (!all_found)
|
2017-09-29 21:56:59 +03:00
|
|
|
{
|
2018-10-08 21:47:53 +03:00
|
|
|
sprintf(errbuf, "binlog files may contain gtids from the domain ('%u') "
|
2017-09-29 21:56:59 +03:00
|
|
|
"being deleted. Make sure to first purge those files",
|
|
|
|
*ptr_domain_id);
|
|
|
|
errmsg= errbuf;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
// compose a sequence of unique pointers to domain object
|
|
|
|
for (k= 0; k < domain_unique.elements; k++)
|
|
|
|
{
|
|
|
|
if ((rpl_binlog_state::element*) dynamic_array_ptr(&domain_unique, k)
|
|
|
|
== elem)
|
|
|
|
break; // domain_id's elem has been already in
|
|
|
|
}
|
|
|
|
if (k == domain_unique.elements) // proven not to have duplicates
|
|
|
|
insert_dynamic(&domain_unique, (uchar*) &elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Domain removal from binlog state
|
|
|
|
for (k= 0; k < domain_unique.elements; k++)
|
|
|
|
{
|
|
|
|
rpl_binlog_state::element *elem= *(rpl_binlog_state::element**)
|
|
|
|
dynamic_array_ptr(&domain_unique, k);
|
|
|
|
my_hash_free(&elem->hash);
|
|
|
|
my_hash_delete(&hash, (uchar*) elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBUG_ASSERT(strlen(errbuf) == 0);
|
|
|
|
|
|
|
|
if (domain_unique.elements == 0)
|
|
|
|
errmsg= "";
|
|
|
|
|
|
|
|
end:
|
|
|
|
mysql_mutex_unlock(&LOCK_binlog_state);
|
|
|
|
delete_dynamic(&domain_unique);
|
|
|
|
|
|
|
|
DBUG_RETURN(errmsg);
|
|
|
|
}
|
2013-08-23 14:02:13 +02:00
|
|
|
|
2013-03-27 16:06:45 +01:00
|
|
|
slave_connection_state::slave_connection_state()
|
|
|
|
{
|
2020-02-27 11:52:20 +01:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
|
2013-08-16 15:10:25 +02:00
|
|
|
offsetof(entry, gtid) + offsetof(rpl_gtid, domain_id),
|
2021-09-30 10:14:28 +02:00
|
|
|
sizeof(rpl_gtid::domain_id), NULL, my_free, HASH_UNIQUE);
|
2020-02-27 11:52:20 +01:00
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, >id_sort_array, sizeof(rpl_gtid), 8, 8, MYF(0));
|
2013-03-27 16:06:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
slave_connection_state::~slave_connection_state()
|
|
|
|
{
|
|
|
|
my_hash_free(&hash);
|
2015-02-27 23:33:22 -05:00
|
|
|
delete_dynamic(>id_sort_array);
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Create a hash from the slave GTID state that is sent to master when slave
|
|
|
|
connects to start replication.
|
|
|
|
|
|
|
|
The state is sent as <GTID>,<GTID>,...,<GTID>, for example:
|
|
|
|
|
|
|
|
0-2-112,1-4-1022
|
|
|
|
|
|
|
|
The state gives for each domain_id the GTID to start replication from for
|
|
|
|
the corresponding replication stream. So domain_id must be unique.
|
|
|
|
|
|
|
|
Returns 0 if ok, non-zero if error due to malformed input.
|
|
|
|
|
|
|
|
Note that input string is built by slave server, so it will not be incorrect
|
|
|
|
unless bug/corruption/malicious server. So we just need basic sanity check,
|
|
|
|
not fancy user-friendly error message.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2017-04-23 19:39:57 +03:00
|
|
|
slave_connection_state::load(const char *slave_request, size_t len)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2017-04-23 19:39:57 +03:00
|
|
|
const char *p, *end;
|
2013-03-11 16:02:40 +01:00
|
|
|
uchar *rec;
|
|
|
|
rpl_gtid *gtid;
|
2013-08-16 15:10:25 +02:00
|
|
|
const entry *e;
|
2013-03-11 16:02:40 +01:00
|
|
|
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
reset();
|
2013-03-11 16:02:40 +01:00
|
|
|
p= slave_request;
|
|
|
|
end= slave_request + len;
|
|
|
|
if (p == end)
|
|
|
|
return 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(rec= (uchar *)my_malloc(PSI_INSTRUMENT_ME, sizeof(entry), MYF(MY_WME))))
|
2013-03-11 16:02:40 +01:00
|
|
|
return 1;
|
2013-08-16 15:10:25 +02:00
|
|
|
gtid= &((entry *)rec)->gtid;
|
2013-03-11 16:02:40 +01:00
|
|
|
if (gtid_parser_helper(&p, end, gtid))
|
|
|
|
{
|
|
|
|
my_free(rec);
|
|
|
|
my_error(ER_INCORRECT_GTID_STATE, MYF(0));
|
|
|
|
return 1;
|
|
|
|
}
|
2013-08-16 15:10:25 +02:00
|
|
|
if ((e= (const entry *)
|
2021-09-30 10:14:28 +02:00
|
|
|
my_hash_search(&hash, (const uchar *)(>id->domain_id),
|
|
|
|
sizeof(gtid->domain_id))))
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
my_error(ER_DUPLICATE_GTID_DOMAIN, MYF(0), gtid->domain_id,
|
2013-08-16 15:10:25 +02:00
|
|
|
gtid->server_id, (ulonglong)gtid->seq_no, e->gtid.domain_id,
|
|
|
|
e->gtid.server_id, (ulonglong)e->gtid.seq_no, gtid->domain_id);
|
2013-03-11 16:02:40 +01:00
|
|
|
my_free(rec);
|
|
|
|
return 1;
|
|
|
|
}
|
2013-08-16 15:10:25 +02:00
|
|
|
((entry *)rec)->flags= 0;
|
2013-03-11 16:02:40 +01:00
|
|
|
if (my_hash_insert(&hash, rec))
|
|
|
|
{
|
|
|
|
my_free(rec);
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (p == end)
|
|
|
|
break; /* Finished. */
|
|
|
|
if (*p != ',')
|
|
|
|
{
|
|
|
|
my_error(ER_INCORRECT_GTID_STATE, MYF(0));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
slave_connection_state::load(const rpl_gtid *gtid_list, uint32 count)
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
reset();
|
2013-03-11 16:02:40 +01:00
|
|
|
for (i= 0; i < count; ++i)
|
|
|
|
if (update(>id_list[i]))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
static int
|
|
|
|
slave_connection_state_load_cb(rpl_gtid *gtid, void *data)
|
|
|
|
{
|
|
|
|
slave_connection_state *state= (slave_connection_state *)data;
|
|
|
|
return state->update(gtid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Same as rpl_slave_state::tostring(), but populates a slave_connection_state
|
|
|
|
instead.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
slave_connection_state::load(rpl_slave_state *state,
|
|
|
|
rpl_gtid *extra_gtids, uint32 num_extra)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
return state->iterate(slave_connection_state_load_cb, this,
|
2015-02-27 23:33:22 -05:00
|
|
|
extra_gtids, num_extra, false);
|
MDEV-26: Global transaction ID.
Fix problems related to reconnect. When we need to reconnect (ie. explict
stop/start of just the IO thread by user, or automatic reconnect due to
loosing network connection with the master), it is a bit complex to correctly
resume at the right point without causing duplicate or missing events in the
relay log. The previous code had multiple problems in this regard.
With this patch, the problem is solved as follows. The IO thread keeps track
(in memory) of which GTID was last queued to the relay log. If it needs to
reconnect, it resumes at that GTID position. It also counts number of events
received within the last, possibly partial, event group, and skips the same
number of events after a reconnect, so that events already enqueued before the
reconnect are not duplicated.
(There is no need to keep any persistent state; whenever we restart slave
threads after both of them being stopped (such as after server restart), we
erase the relay logs and start over from the last GTID applied by SQL thread.
But while the SQL thread is running, this patch is needed to get correct relay
log).
2013-06-05 14:32:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-16 15:10:25 +02:00
|
|
|
slave_connection_state::entry *
|
|
|
|
slave_connection_state::find_entry(uint32 domain_id)
|
|
|
|
{
|
2021-09-30 10:14:28 +02:00
|
|
|
return (entry *) my_hash_search(&hash, (const uchar *)(&domain_id),
|
|
|
|
sizeof(domain_id));
|
2013-08-16 15:10:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
rpl_gtid *
|
|
|
|
slave_connection_state::find(uint32 domain_id)
|
|
|
|
{
|
2013-08-16 15:10:25 +02:00
|
|
|
entry *e= find_entry(domain_id);
|
|
|
|
if (!e)
|
|
|
|
return NULL;
|
|
|
|
return &e->gtid;
|
2013-03-11 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
slave_connection_state::update(const rpl_gtid *in_gtid)
|
|
|
|
{
|
2013-08-16 15:10:25 +02:00
|
|
|
entry *e;
|
2021-09-30 10:14:28 +02:00
|
|
|
uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id),
|
|
|
|
sizeof(in_gtid->domain_id));
|
2013-03-11 16:02:40 +01:00
|
|
|
if (rec)
|
|
|
|
{
|
2013-08-16 15:10:25 +02:00
|
|
|
e= (entry *)rec;
|
|
|
|
e->gtid= *in_gtid;
|
2013-03-11 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(e= (entry *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME))))
|
2013-03-11 16:02:40 +01:00
|
|
|
return 1;
|
2013-08-16 15:10:25 +02:00
|
|
|
e->gtid= *in_gtid;
|
|
|
|
e->flags= 0;
|
|
|
|
if (my_hash_insert(&hash, (uchar *)e))
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
2013-08-16 15:10:25 +02:00
|
|
|
my_free(e);
|
2013-03-11 16:02:40 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
slave_connection_state::remove(const rpl_gtid *in_gtid)
|
|
|
|
{
|
2021-09-30 10:14:28 +02:00
|
|
|
uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id),
|
|
|
|
sizeof(in_gtid->domain_id));
|
2017-07-03 11:35:44 +03:00
|
|
|
#ifdef DBUG_ASSERT_EXISTS
|
2013-03-26 14:58:14 +01:00
|
|
|
bool err;
|
2013-08-16 15:10:25 +02:00
|
|
|
rpl_gtid *slave_gtid= &((entry *)rec)->gtid;
|
2013-03-11 16:02:40 +01:00
|
|
|
DBUG_ASSERT(rec /* We should never try to remove not present domain_id. */);
|
|
|
|
DBUG_ASSERT(slave_gtid->server_id == in_gtid->server_id);
|
|
|
|
DBUG_ASSERT(slave_gtid->seq_no == in_gtid->seq_no);
|
2017-07-03 11:35:44 +03:00
|
|
|
err=
|
2013-03-11 16:02:40 +01:00
|
|
|
#endif
|
2013-03-26 14:58:14 +01:00
|
|
|
my_hash_delete(&hash, rec);
|
2013-03-11 16:02:40 +01:00
|
|
|
DBUG_ASSERT(!err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-22 12:36:42 +02:00
|
|
|
void
|
|
|
|
slave_connection_state::remove_if_present(const rpl_gtid *in_gtid)
|
|
|
|
{
|
2021-09-30 10:14:28 +02:00
|
|
|
uchar *rec= my_hash_search(&hash, (const uchar *)(&in_gtid->domain_id),
|
|
|
|
sizeof(in_gtid->domain_id));
|
2013-08-22 12:36:42 +02:00
|
|
|
if (rec)
|
|
|
|
my_hash_delete(&hash, rec);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-11 16:02:40 +01:00
|
|
|
int
|
|
|
|
slave_connection_state::to_string(String *out_str)
|
2013-05-15 19:52:21 +02:00
|
|
|
{
|
|
|
|
out_str->length(0);
|
|
|
|
return append_to_string(out_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
slave_connection_state::append_to_string(String *out_str)
|
2013-03-11 16:02:40 +01:00
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
bool first;
|
|
|
|
|
|
|
|
first= true;
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
2013-08-16 15:10:25 +02:00
|
|
|
const entry *e= (const entry *)my_hash_element(&hash, i);
|
|
|
|
if (rpl_slave_state_tostring_helper(out_str, &e->gtid, &first))
|
2013-03-11 16:02:40 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2013-08-22 12:36:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
slave_connection_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
|
|
|
|
{
|
|
|
|
uint32 i, pos;
|
|
|
|
|
|
|
|
pos= 0;
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
entry *e;
|
|
|
|
if (pos >= list_size)
|
|
|
|
return 1;
|
|
|
|
e= (entry *)my_hash_element(&hash, i);
|
|
|
|
memcpy(>id_list[pos++], &e->gtid, sizeof(e->gtid));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
|
2015-03-04 13:10:37 +01:00
|
|
|
/*
|
|
|
|
Check if the GTID position has been reached, for mysql_binlog_send().
|
|
|
|
|
|
|
|
The position has not been reached if we have anything in the state, unless
|
|
|
|
it has either the START_ON_EMPTY_DOMAIN flag set (which means it does not
|
|
|
|
belong to this master at all), or the START_OWN_SLAVE_POS (which means that
|
|
|
|
we start on an old position from when the server was a slave with
|
|
|
|
--log-slave-updates=0).
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
slave_connection_state::is_pos_reached()
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
for (i= 0; i < hash.records; ++i)
|
|
|
|
{
|
|
|
|
entry *e= (entry *)my_hash_element(&hash, i);
|
|
|
|
if (!(e->flags & (START_OWN_SLAVE_POS|START_ON_EMPTY_DOMAIN)))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
/*
|
|
|
|
Execute a MASTER_GTID_WAIT().
|
|
|
|
The position to wait for is in gtid_str in string form.
|
|
|
|
The timeout in microseconds is in timeout_us, zero means no timeout.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
1 for error.
|
|
|
|
0 for wait completed.
|
|
|
|
-1 for wait timed out.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
gtid_waiting::wait_for_pos(THD *thd, String *gtid_str, longlong timeout_us)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
rpl_gtid *wait_pos;
|
|
|
|
uint32 count, i;
|
|
|
|
struct timespec wait_until, *wait_until_ptr;
|
2015-03-12 06:43:38 +11:00
|
|
|
ulonglong before;
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
/* Wait for the empty position returns immediately. */
|
|
|
|
if (gtid_str->length() == 0)
|
2015-03-12 06:43:38 +11:00
|
|
|
{
|
|
|
|
status_var_increment(thd->status_var.master_gtid_wait_count);
|
2014-02-07 19:15:28 +01:00
|
|
|
return 0;
|
2015-03-12 06:43:38 +11:00
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
if (!(wait_pos= gtid_parse_string_to_list(gtid_str->ptr(), gtid_str->length(),
|
|
|
|
&count)))
|
|
|
|
{
|
|
|
|
my_error(ER_INCORRECT_GTID_STATE, MYF(0));
|
|
|
|
return 1;
|
|
|
|
}
|
2015-03-12 06:43:38 +11:00
|
|
|
status_var_increment(thd->status_var.master_gtid_wait_count);
|
2015-03-16 14:40:29 +01:00
|
|
|
before= microsecond_interval_timer();
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
if (timeout_us >= 0)
|
|
|
|
{
|
|
|
|
set_timespec_nsec(wait_until, (ulonglong)1000*timeout_us);
|
|
|
|
wait_until_ptr= &wait_until;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wait_until_ptr= NULL;
|
|
|
|
err= 0;
|
|
|
|
for (i= 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
if ((err= wait_for_gtid(thd, &wait_pos[i], wait_until_ptr)))
|
|
|
|
break;
|
|
|
|
}
|
2015-03-12 06:43:38 +11:00
|
|
|
switch (err)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
status_var_increment(thd->status_var.master_gtid_wait_timeouts);
|
2017-05-16 20:08:47 +03:00
|
|
|
/* fall through */
|
2015-03-16 14:40:29 +01:00
|
|
|
case 0:
|
|
|
|
status_var_add(thd->status_var.master_gtid_wait_time,
|
2020-03-20 17:40:39 +02:00
|
|
|
static_cast<ulong>
|
|
|
|
(microsecond_interval_timer() - before));
|
2015-03-12 06:43:38 +11:00
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
my_free(wait_pos);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gtid_waiting::promote_new_waiter(gtid_waiting::hash_element *he)
|
|
|
|
{
|
|
|
|
queue_element *qe;
|
|
|
|
|
|
|
|
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
|
|
|
if (queue_empty(&he->queue))
|
|
|
|
return;
|
|
|
|
qe= (queue_element *)queue_top(&he->queue);
|
2014-02-08 22:28:41 +01:00
|
|
|
qe->do_small_wait= true;
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_cond_signal(&qe->thd->COND_wakeup_ready);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gtid_waiting::process_wait_hash(uint64 wakeup_seq_no,
|
|
|
|
gtid_waiting::hash_element *he)
|
|
|
|
{
|
|
|
|
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
queue_element *qe;
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
if (queue_empty(&he->queue))
|
2014-02-07 19:15:28 +01:00
|
|
|
break;
|
|
|
|
qe= (queue_element *)queue_top(&he->queue);
|
|
|
|
if (qe->wait_seq_no > wakeup_seq_no)
|
|
|
|
break;
|
2014-02-08 22:28:41 +01:00
|
|
|
DBUG_ASSERT(!qe->done);
|
2014-02-07 19:15:28 +01:00
|
|
|
queue_remove_top(&he->queue);
|
2014-02-08 22:28:41 +01:00
|
|
|
qe->done= true;;
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_cond_signal(&qe->thd->COND_wakeup_ready);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Execute a MASTER_GTID_WAIT() for one specific domain.
|
|
|
|
|
|
|
|
The implementation is optimised primarily for (1) minimal performance impact
|
|
|
|
on the slave replication threads, and secondarily for (2) quick performance
|
|
|
|
of MASTER_GTID_WAIT() on a single GTID, which can be useful for consistent
|
|
|
|
read to clients in an async replication read-scaleout scenario.
|
|
|
|
|
|
|
|
To achieve (1), we have a "small" wait and a "large" wait. The small wait
|
|
|
|
contends with the replication threads on the lock on the gtid_slave_pos, so
|
|
|
|
only minimal processing is done under that lock, and only a single waiter at
|
|
|
|
a time does the small wait.
|
|
|
|
|
|
|
|
If there is already a small waiter, a new thread will either replace the
|
|
|
|
small waiter (if it needs to wait for an earlier sequence number), or
|
2014-02-08 22:28:41 +01:00
|
|
|
instead do a "large" wait.
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
Once awoken on the small wait, the waiting thread releases the lock shared
|
|
|
|
with the SQL threads quickly, and then processes all waiters currently doing
|
2014-02-08 22:28:41 +01:00
|
|
|
the large wait using a different lock that does not impact replication.
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
This way, the SQL threads only need to do a single check + possibly a
|
|
|
|
pthread_cond_signal() when updating the gtid_slave_state, and the time that
|
2014-02-08 22:28:41 +01:00
|
|
|
non-SQL threads contend for the lock on gtid_slave_state is minimized.
|
|
|
|
|
|
|
|
There is always at least one thread that has the responsibility to ensure
|
|
|
|
that there is a small waiter; this thread has queue_element::do_small_wait
|
|
|
|
set to true. This thread will do the small wait until it is done, at which
|
|
|
|
point it will make sure to pass on the responsibility to another thread.
|
|
|
|
Normally only one thread has do_small_wait==true, but it can occasionally
|
|
|
|
happen that there is more than one, when threads race one another for the
|
|
|
|
lock on the small wait (this results in slightly increased activity on the
|
|
|
|
small lock but is otherwise harmless).
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
0 Wait completed normally
|
|
|
|
-1 Wait completed due to timeout
|
|
|
|
1 An error (my_error() will have been called to set the error in the da)
|
2014-02-07 19:15:28 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
gtid_waiting::wait_for_gtid(THD *thd, rpl_gtid *wait_gtid,
|
|
|
|
struct timespec *wait_until)
|
|
|
|
{
|
|
|
|
bool timed_out= false;
|
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
queue_element elem;
|
2014-02-08 01:16:45 +01:00
|
|
|
uint32 domain_id= wait_gtid->domain_id;
|
2014-02-07 19:15:28 +01:00
|
|
|
uint64 seq_no= wait_gtid->seq_no;
|
|
|
|
hash_element *he;
|
|
|
|
rpl_slave_state::element *slave_state_elem= NULL;
|
2014-02-10 15:12:17 +01:00
|
|
|
PSI_stage_info old_stage;
|
2014-02-07 19:15:28 +01:00
|
|
|
bool did_enter_cond= false;
|
|
|
|
|
|
|
|
elem.wait_seq_no= seq_no;
|
|
|
|
elem.thd= thd;
|
2014-02-08 22:28:41 +01:00
|
|
|
elem.done= false;
|
|
|
|
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_lock(&LOCK_gtid_waiting);
|
2014-02-08 22:28:41 +01:00
|
|
|
if (!(he= get_entry(wait_gtid->domain_id)))
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
|
|
|
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*
|
2014-02-08 22:28:41 +01:00
|
|
|
If there is already another waiter with seq_no no larger than our own,
|
|
|
|
we are sure that there is already a small waiter that will wake us up
|
|
|
|
(or later pass the small wait responsibility to us). So in this case, we
|
|
|
|
do not need to touch the small wait lock at all.
|
|
|
|
*/
|
|
|
|
elem.do_small_wait=
|
|
|
|
(queue_empty(&he->queue) ||
|
|
|
|
((queue_element *)queue_top(&he->queue))->wait_seq_no > seq_no);
|
2014-02-07 19:15:28 +01:00
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
if (register_in_wait_queue(thd, wait_gtid, he, &elem))
|
|
|
|
{
|
|
|
|
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Loop, doing either the small or large wait as appropriate, until either
|
|
|
|
the position waited for is reached, or we get a kill or timeout.
|
2014-02-07 19:15:28 +01:00
|
|
|
*/
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
if (elem.do_small_wait)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
2014-02-08 22:28:41 +01:00
|
|
|
uint64 wakeup_seq_no;
|
|
|
|
queue_element *cur_waiter;
|
|
|
|
|
2015-11-29 17:51:23 +02:00
|
|
|
mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
2014-02-07 19:15:28 +01:00
|
|
|
/*
|
2014-02-08 22:28:41 +01:00
|
|
|
The elements in the gtid_slave_state_hash are never re-allocated once
|
|
|
|
they enter the hash, so we do not need to re-do the lookup after releasing
|
|
|
|
and re-aquiring the lock.
|
2014-02-07 19:15:28 +01:00
|
|
|
*/
|
2014-02-08 22:28:41 +01:00
|
|
|
if (!slave_state_elem &&
|
2015-11-29 17:51:23 +02:00
|
|
|
!(slave_state_elem= rpl_global_gtid_slave_state->get_element(domain_id)))
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
2015-11-29 17:51:23 +02:00
|
|
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
2014-02-08 22:28:41 +01:00
|
|
|
remove_from_wait_queue(he, &elem);
|
|
|
|
promote_new_waiter(he);
|
|
|
|
if (did_enter_cond)
|
2014-02-10 15:12:17 +01:00
|
|
|
thd->EXIT_COND(&old_stage);
|
2014-02-08 22:28:41 +01:00
|
|
|
else
|
|
|
|
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return 1;
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
2014-02-08 22:28:41 +01:00
|
|
|
|
|
|
|
if ((wakeup_seq_no= slave_state_elem->highest_seq_no) >= seq_no)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
2014-02-08 22:28:41 +01:00
|
|
|
/*
|
|
|
|
We do not have to wait. (We will be removed from the wait queue when
|
|
|
|
we call process_wait_hash() below.
|
|
|
|
*/
|
2015-11-29 17:51:23 +02:00
|
|
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
2014-02-08 22:28:41 +01:00
|
|
|
}
|
|
|
|
else if ((cur_waiter= slave_state_elem->gtid_waiter) &&
|
|
|
|
slave_state_elem->min_wait_seq_no <= seq_no)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
There is already a suitable small waiter, go do the large wait.
|
|
|
|
(Normally we would not have needed to check the small wait in this
|
|
|
|
case, but it can happen if we race with another thread for the small
|
|
|
|
lock).
|
|
|
|
*/
|
|
|
|
elem.do_small_wait= false;
|
2015-11-29 17:51:23 +02:00
|
|
|
mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-08 22:28:41 +01:00
|
|
|
/*
|
|
|
|
We have to do the small wait ourselves (stealing it from any thread
|
|
|
|
that might already be waiting for a later seq_no).
|
|
|
|
*/
|
|
|
|
slave_state_elem->gtid_waiter= &elem;
|
|
|
|
slave_state_elem->min_wait_seq_no= seq_no;
|
|
|
|
if (cur_waiter)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
2014-02-08 22:28:41 +01:00
|
|
|
/* We stole the wait, so wake up the old waiting thread. */
|
|
|
|
mysql_cond_signal(&slave_state_elem->COND_wait_gtid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release the large lock, and do the small wait. */
|
|
|
|
if (did_enter_cond)
|
|
|
|
{
|
2014-02-10 15:12:17 +01:00
|
|
|
thd->EXIT_COND(&old_stage);
|
2014-02-08 22:28:41 +01:00
|
|
|
did_enter_cond= false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
2014-02-10 15:12:17 +01:00
|
|
|
thd->ENTER_COND(&slave_state_elem->COND_wait_gtid,
|
2015-11-29 17:51:23 +02:00
|
|
|
&rpl_global_gtid_slave_state->LOCK_slave_state,
|
2014-02-10 15:12:17 +01:00
|
|
|
&stage_master_gtid_wait_primary, &old_stage);
|
2014-02-08 22:28:41 +01:00
|
|
|
do
|
|
|
|
{
|
2018-05-26 16:57:18 +03:00
|
|
|
if (unlikely(thd->check_killed(1)))
|
2014-02-08 22:28:41 +01:00
|
|
|
break;
|
|
|
|
else if (wait_until)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
2014-02-08 22:28:41 +01:00
|
|
|
int err=
|
|
|
|
mysql_cond_timedwait(&slave_state_elem->COND_wait_gtid,
|
2015-11-29 17:51:23 +02:00
|
|
|
&rpl_global_gtid_slave_state->LOCK_slave_state,
|
2014-02-08 22:28:41 +01:00
|
|
|
wait_until);
|
|
|
|
if (err == ETIMEDOUT || err == ETIME)
|
|
|
|
{
|
|
|
|
timed_out= true;
|
|
|
|
break;
|
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
2014-02-08 22:28:41 +01:00
|
|
|
else
|
|
|
|
mysql_cond_wait(&slave_state_elem->COND_wait_gtid,
|
2015-11-29 17:51:23 +02:00
|
|
|
&rpl_global_gtid_slave_state->LOCK_slave_state);
|
2014-02-08 22:28:41 +01:00
|
|
|
} while (slave_state_elem->gtid_waiter == &elem);
|
|
|
|
wakeup_seq_no= slave_state_elem->highest_seq_no;
|
|
|
|
/*
|
|
|
|
If we aborted due to timeout or kill, remove us as waiter.
|
|
|
|
|
|
|
|
If we were replaced by another waiter with a smaller seq_no, then we
|
|
|
|
no longer have responsibility for the small wait.
|
|
|
|
*/
|
|
|
|
if ((cur_waiter= slave_state_elem->gtid_waiter))
|
|
|
|
{
|
|
|
|
if (cur_waiter == &elem)
|
|
|
|
slave_state_elem->gtid_waiter= NULL;
|
|
|
|
else if (slave_state_elem->min_wait_seq_no <= seq_no)
|
|
|
|
elem.do_small_wait= false;
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
2014-02-10 15:12:17 +01:00
|
|
|
thd->EXIT_COND(&old_stage);
|
2014-02-08 22:28:41 +01:00
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_gtid_waiting);
|
|
|
|
}
|
2014-02-07 19:15:28 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Note that hash_entry pointers do not change once allocated, so we do
|
2014-02-08 22:28:41 +01:00
|
|
|
not need to lookup `he' again after re-aquiring LOCK_gtid_waiting.
|
2014-02-07 19:15:28 +01:00
|
|
|
*/
|
|
|
|
process_wait_hash(wakeup_seq_no, he);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-08 22:28:41 +01:00
|
|
|
/* Do the large wait. */
|
|
|
|
if (!did_enter_cond)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
2014-02-10 15:12:17 +01:00
|
|
|
thd->ENTER_COND(&thd->COND_wakeup_ready, &LOCK_gtid_waiting,
|
|
|
|
&stage_master_gtid_wait, &old_stage);
|
2014-02-08 22:28:41 +01:00
|
|
|
did_enter_cond= true;
|
|
|
|
}
|
2018-05-26 16:57:18 +03:00
|
|
|
while (!elem.done && likely(!thd->check_killed(1)))
|
2014-02-08 22:28:41 +01:00
|
|
|
{
|
|
|
|
thd_wait_begin(thd, THD_WAIT_BINLOG);
|
|
|
|
if (wait_until)
|
|
|
|
{
|
|
|
|
int err= mysql_cond_timedwait(&thd->COND_wakeup_ready,
|
|
|
|
&LOCK_gtid_waiting, wait_until);
|
|
|
|
if (err == ETIMEDOUT || err == ETIME)
|
|
|
|
timed_out= true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mysql_cond_wait(&thd->COND_wakeup_ready, &LOCK_gtid_waiting);
|
|
|
|
thd_wait_end(thd);
|
|
|
|
if (elem.do_small_wait || timed_out)
|
|
|
|
break;
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
if ((thd->killed || timed_out) && !elem.done)
|
|
|
|
{
|
|
|
|
/* Aborted, so remove ourselves from the hash. */
|
|
|
|
remove_from_wait_queue(he, &elem);
|
|
|
|
elem.done= true;
|
|
|
|
}
|
|
|
|
if (elem.done)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
|
|
|
/*
|
2014-02-08 22:28:41 +01:00
|
|
|
If our wait is done, but we have (or were passed) responsibility for
|
|
|
|
the small wait, then we need to pass on that task to someone else.
|
2014-02-07 19:15:28 +01:00
|
|
|
*/
|
2014-02-08 22:28:41 +01:00
|
|
|
if (elem.do_small_wait)
|
2014-02-07 19:15:28 +01:00
|
|
|
promote_new_waiter(he);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (did_enter_cond)
|
2014-02-10 15:12:17 +01:00
|
|
|
thd->EXIT_COND(&old_stage);
|
2014-02-07 19:15:28 +01:00
|
|
|
else
|
|
|
|
mysql_mutex_unlock(&LOCK_gtid_waiting);
|
2014-02-08 22:28:41 +01:00
|
|
|
if (thd->killed)
|
|
|
|
thd->send_kill_message();
|
2014-02-07 19:15:28 +01:00
|
|
|
#endif /* HAVE_REPLICATION */
|
|
|
|
return timed_out ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_hash_element(void *p)
|
|
|
|
{
|
|
|
|
gtid_waiting::hash_element *e= (gtid_waiting::hash_element *)p;
|
|
|
|
delete_queue(&e->queue);
|
|
|
|
my_free(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gtid_waiting::init()
|
|
|
|
{
|
2020-02-27 11:52:20 +01:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &hash, &my_charset_bin, 32,
|
2021-09-30 10:14:28 +02:00
|
|
|
offsetof(hash_element, domain_id),
|
|
|
|
sizeof(hash_element::domain_id), NULL,
|
2020-02-27 11:52:20 +01:00
|
|
|
free_hash_element, HASH_UNIQUE);
|
2014-02-07 19:15:28 +01:00
|
|
|
mysql_mutex_init(key_LOCK_gtid_waiting, &LOCK_gtid_waiting, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gtid_waiting::destroy()
|
|
|
|
{
|
|
|
|
mysql_mutex_destroy(&LOCK_gtid_waiting);
|
|
|
|
my_hash_free(&hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
cmp_queue_elem(void *, uchar *a, uchar *b)
|
|
|
|
{
|
|
|
|
uint64 seq_no_a= *(uint64 *)a;
|
|
|
|
uint64 seq_no_b= *(uint64 *)b;
|
|
|
|
if (seq_no_a < seq_no_b)
|
|
|
|
return -1;
|
|
|
|
else if (seq_no_a == seq_no_b)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gtid_waiting::hash_element *
|
|
|
|
gtid_waiting::get_entry(uint32 domain_id)
|
|
|
|
{
|
|
|
|
hash_element *e;
|
|
|
|
|
2021-09-30 10:14:28 +02:00
|
|
|
if ((e= (hash_element *)my_hash_search(&hash, (const uchar *)&domain_id,
|
|
|
|
sizeof(domain_id))))
|
2014-02-07 19:15:28 +01:00
|
|
|
return e;
|
|
|
|
|
2020-01-29 13:50:26 +01:00
|
|
|
if (!(e= (hash_element *)my_malloc(PSI_INSTRUMENT_ME, sizeof(*e), MYF(MY_WME))))
|
2014-02-07 19:15:28 +01:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (init_queue(&e->queue, 8, offsetof(queue_element, wait_seq_no), 0,
|
|
|
|
cmp_queue_elem, NULL, 1+offsetof(queue_element, queue_idx), 1))
|
|
|
|
{
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
my_free(e);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
e->domain_id= domain_id;
|
|
|
|
if (my_hash_insert(&hash, (uchar *)e))
|
|
|
|
{
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
delete_queue(&e->queue);
|
|
|
|
my_free(e);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
int
|
|
|
|
gtid_waiting::register_in_wait_queue(THD *thd, rpl_gtid *wait_gtid,
|
|
|
|
gtid_waiting::hash_element *he,
|
|
|
|
gtid_waiting::queue_element *elem)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
|
|
|
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
if (queue_insert_safe(&he->queue, (uchar *)elem))
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
2014-02-08 22:28:41 +01:00
|
|
|
return 1;
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
return 0;
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2014-02-08 22:28:41 +01:00
|
|
|
gtid_waiting::remove_from_wait_queue(gtid_waiting::hash_element *he,
|
|
|
|
gtid_waiting::queue_element *elem)
|
2014-02-07 19:15:28 +01:00
|
|
|
{
|
|
|
|
mysql_mutex_assert_owner(&LOCK_gtid_waiting);
|
|
|
|
|
2014-02-08 22:28:41 +01:00
|
|
|
queue_remove(&he->queue, elem->queue_idx);
|
2014-02-07 19:15:28 +01:00
|
|
|
}
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void free_domain_lookup_element(void *p)
|
|
|
|
{
|
|
|
|
struct Binlog_gtid_state_validator::audit_elem *audit_elem=
|
|
|
|
(struct Binlog_gtid_state_validator::audit_elem *) p;
|
|
|
|
delete_dynamic(&audit_elem->late_gtids_previous);
|
|
|
|
delete_dynamic(&audit_elem->late_gtids_real);
|
|
|
|
my_free(audit_elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
Binlog_gtid_state_validator::Binlog_gtid_state_validator()
|
|
|
|
{
|
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &m_audit_elem_domain_lookup, &my_charset_bin, 32,
|
|
|
|
offsetof(struct audit_elem, domain_id), sizeof(uint32),
|
|
|
|
NULL, free_domain_lookup_element, HASH_UNIQUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
Binlog_gtid_state_validator::~Binlog_gtid_state_validator()
|
|
|
|
{
|
|
|
|
my_hash_free(&m_audit_elem_domain_lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Binlog_gtid_state_validator::initialize_start_gtids(rpl_gtid *start_gtids,
|
|
|
|
size_t n_gtids)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for(i= 0; i < n_gtids; i++)
|
|
|
|
{
|
|
|
|
rpl_gtid *domain_state_gtid= &start_gtids[i];
|
|
|
|
|
|
|
|
/*
|
|
|
|
If we are initializing from a GLLE, we can have repeat domain ids from
|
|
|
|
differing servers, so we want to ensure our start gtid matches the last
|
|
|
|
known position
|
|
|
|
*/
|
|
|
|
struct audit_elem *audit_elem= (struct audit_elem *) my_hash_search(
|
|
|
|
&m_audit_elem_domain_lookup,
|
|
|
|
(const uchar *) &(domain_state_gtid->domain_id), 0);
|
|
|
|
if (audit_elem)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We have this domain already specified, so try to overwrite with the
|
|
|
|
more recent GTID
|
|
|
|
*/
|
|
|
|
if (domain_state_gtid->seq_no > audit_elem->start_gtid.seq_no)
|
|
|
|
audit_elem->start_gtid = *domain_state_gtid;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize a new domain */
|
|
|
|
audit_elem= (struct audit_elem *) my_malloc(
|
|
|
|
PSI_NOT_INSTRUMENTED, sizeof(struct audit_elem), MYF(MY_WME));
|
|
|
|
if (!audit_elem)
|
|
|
|
{
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
audit_elem->domain_id= start_gtids[i].domain_id;
|
|
|
|
audit_elem->start_gtid= start_gtids[i];
|
|
|
|
audit_elem->last_gtid= {audit_elem->domain_id, 0, 0};
|
|
|
|
|
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, &audit_elem->late_gtids_real,
|
|
|
|
sizeof(rpl_gtid), 8, 8, MYF(0));
|
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, &audit_elem->late_gtids_previous,
|
|
|
|
sizeof(rpl_gtid), 8, 8, MYF(0));
|
|
|
|
|
|
|
|
if (my_hash_insert(&m_audit_elem_domain_lookup, (uchar *) audit_elem))
|
|
|
|
{
|
|
|
|
my_free(audit_elem);
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Binlog_gtid_state_validator::initialize_gtid_state(FILE *out,
|
|
|
|
rpl_gtid *gtids,
|
|
|
|
size_t n_gtids)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
my_bool err= FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
We weren't initialized with starting positions explicitly, so assume the
|
|
|
|
starting positions of the current gtid state
|
|
|
|
*/
|
|
|
|
if (!m_audit_elem_domain_lookup.records)
|
|
|
|
initialize_start_gtids(gtids, n_gtids);
|
|
|
|
|
|
|
|
for(i= 0; i < n_gtids; i++)
|
|
|
|
{
|
|
|
|
rpl_gtid *domain_state_gtid= >ids[i];
|
|
|
|
|
|
|
|
struct audit_elem *audit_elem= (struct audit_elem *) my_hash_search(
|
|
|
|
&m_audit_elem_domain_lookup,
|
|
|
|
(const uchar *) &(domain_state_gtid->domain_id), 0);
|
|
|
|
|
|
|
|
if (!audit_elem)
|
|
|
|
{
|
|
|
|
Binlog_gtid_state_validator::error(
|
|
|
|
out,
|
|
|
|
"Starting GTID position list does not specify an initial value "
|
|
|
|
"for domain %u, whose events may be present in the requested binlog "
|
|
|
|
"file(s). The last known position for this domain was %u-%u-%llu.",
|
|
|
|
domain_state_gtid->domain_id, PARAM_GTID((*domain_state_gtid)));
|
|
|
|
err= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (audit_elem->start_gtid.seq_no < domain_state_gtid->seq_no)
|
|
|
|
{
|
|
|
|
Binlog_gtid_state_validator::error(
|
|
|
|
out,
|
|
|
|
"Binary logs are missing data for domain %u. Expected data to "
|
|
|
|
"start from state %u-%u-%llu; however, the initial GTID state of "
|
|
|
|
"the logs was %u-%u-%llu.",
|
|
|
|
domain_state_gtid->domain_id, PARAM_GTID(audit_elem->start_gtid),
|
|
|
|
PARAM_GTID((*domain_state_gtid)));
|
|
|
|
err= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (domain_state_gtid->seq_no > audit_elem->last_gtid.seq_no)
|
|
|
|
audit_elem->last_gtid= *domain_state_gtid;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Binlog_gtid_state_validator::verify_stop_state(FILE *out,
|
|
|
|
rpl_gtid *stop_gtids,
|
|
|
|
size_t n_stop_gtids)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for(i= 0; i < n_stop_gtids; i++)
|
|
|
|
{
|
|
|
|
rpl_gtid *stop_gtid= &stop_gtids[i];
|
|
|
|
|
|
|
|
struct audit_elem *audit_elem= (struct audit_elem *) my_hash_search(
|
|
|
|
&m_audit_elem_domain_lookup,
|
|
|
|
(const uchar *) &(stop_gtid->domain_id), 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
It is okay if stop gtid doesn't exist in current state because it will be treated
|
|
|
|
as a new domain
|
|
|
|
*/
|
|
|
|
if (audit_elem && stop_gtid->seq_no <= audit_elem->start_gtid.seq_no)
|
|
|
|
{
|
|
|
|
Binlog_gtid_state_validator::error(
|
|
|
|
out,
|
|
|
|
"--stop-position GTID %u-%u-%llu does not exist in the "
|
|
|
|
"specified binlog files. The current GTID state of domain %u in the "
|
|
|
|
"specified binary logs is %u-%u-%llu",
|
|
|
|
PARAM_GTID((*stop_gtid)), stop_gtid->domain_id,
|
|
|
|
PARAM_GTID(audit_elem->start_gtid));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No issues with any GTIDs */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool
|
|
|
|
Binlog_gtid_state_validator::verify_gtid_state(FILE *out,
|
|
|
|
rpl_gtid *domain_state_gtid)
|
|
|
|
{
|
|
|
|
struct audit_elem *audit_elem= (struct audit_elem *) my_hash_search(
|
|
|
|
&m_audit_elem_domain_lookup,
|
|
|
|
(const uchar *) &(domain_state_gtid->domain_id), 0);
|
|
|
|
|
|
|
|
if (!audit_elem)
|
|
|
|
{
|
|
|
|
Binlog_gtid_state_validator::warn(
|
|
|
|
out,
|
|
|
|
"Binary logs are missing data for domain %u. The current binary log "
|
|
|
|
"specified its "
|
|
|
|
"current state for this domain as %u-%u-%llu, but neither the "
|
|
|
|
"starting GTID position list nor any processed events have "
|
|
|
|
"mentioned "
|
|
|
|
"this domain.",
|
|
|
|
domain_state_gtid->domain_id, PARAM_GTID((*domain_state_gtid)));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (audit_elem->last_gtid.seq_no < domain_state_gtid->seq_no)
|
|
|
|
{
|
|
|
|
Binlog_gtid_state_validator::warn(
|
|
|
|
out,
|
|
|
|
"Binary logs are missing data for domain %u. The current binary log "
|
|
|
|
"state is %u-%u-%llu, but the last seen event was %u-%u-%llu.",
|
|
|
|
domain_state_gtid->domain_id, PARAM_GTID((*domain_state_gtid)),
|
|
|
|
PARAM_GTID(audit_elem->last_gtid));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Binlog_gtid_state_validator::record(rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
struct audit_elem *audit_elem= (struct audit_elem *) my_hash_search(
|
|
|
|
&m_audit_elem_domain_lookup, (const uchar *) &(gtid->domain_id), 0);
|
|
|
|
|
|
|
|
if (!audit_elem)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We haven't seen any GTIDs in this domian yet. Perform initial set up for
|
|
|
|
this domain so we can monitor its events.
|
|
|
|
*/
|
|
|
|
audit_elem= (struct audit_elem *) my_malloc(
|
|
|
|
PSI_NOT_INSTRUMENTED, sizeof(struct audit_elem), MYF(MY_WME));
|
|
|
|
if (!audit_elem)
|
|
|
|
{
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
audit_elem->domain_id= gtid->domain_id;
|
|
|
|
audit_elem->last_gtid= *gtid;
|
|
|
|
audit_elem->start_gtid= {gtid->domain_id, 0, 0};
|
|
|
|
|
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, &audit_elem->late_gtids_real,
|
|
|
|
sizeof(rpl_gtid), 8, 8, MYF(0));
|
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, &audit_elem->late_gtids_previous,
|
|
|
|
sizeof(rpl_gtid), 8, 8, MYF(0));
|
|
|
|
|
|
|
|
if (my_hash_insert(&m_audit_elem_domain_lookup, (uchar *) audit_elem))
|
|
|
|
{
|
|
|
|
my_free(audit_elem);
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Out of order check */
|
|
|
|
if (gtid->seq_no <= audit_elem->last_gtid.seq_no &&
|
|
|
|
gtid->seq_no >= audit_elem->start_gtid.seq_no)
|
|
|
|
{
|
|
|
|
/* GTID is out of order */
|
|
|
|
insert_dynamic(&audit_elem->late_gtids_real, (const void *) gtid);
|
|
|
|
insert_dynamic(&audit_elem->late_gtids_previous,
|
|
|
|
(const void *) &(audit_elem->last_gtid));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* GTID is valid */
|
|
|
|
audit_elem->last_gtid= *gtid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Data structure used to help pass data into report_audit_findings because
|
|
|
|
my_hash_iterate only passes one parameter
|
|
|
|
*/
|
|
|
|
struct gtid_report_ctx
|
|
|
|
{
|
|
|
|
FILE *out_file;
|
|
|
|
my_bool is_strict_mode;
|
|
|
|
my_bool contains_err;
|
|
|
|
};
|
|
|
|
|
|
|
|
static my_bool report_audit_findings(void *entry, void *report_ctx_arg)
|
|
|
|
{
|
|
|
|
struct Binlog_gtid_state_validator::audit_elem *audit_el=
|
|
|
|
(struct Binlog_gtid_state_validator::audit_elem *) entry;
|
|
|
|
|
|
|
|
struct gtid_report_ctx *report_ctx=
|
|
|
|
(struct gtid_report_ctx *) report_ctx_arg;
|
|
|
|
FILE *out= report_ctx->out_file;
|
|
|
|
my_bool is_strict_mode= report_ctx->is_strict_mode;
|
|
|
|
size_t i;
|
|
|
|
void (*report_f)(FILE*, const char*, ...);
|
|
|
|
|
|
|
|
if (is_strict_mode)
|
|
|
|
report_f= Binlog_gtid_state_validator::error;
|
|
|
|
else
|
|
|
|
report_f= Binlog_gtid_state_validator::warn;
|
|
|
|
|
|
|
|
if (audit_el)
|
|
|
|
{
|
|
|
|
if (audit_el->last_gtid.seq_no < audit_el->start_gtid.seq_no)
|
|
|
|
{
|
|
|
|
report_f(out,
|
|
|
|
"Binary logs never reached expected GTID state of %u-%u-%llu",
|
|
|
|
PARAM_GTID(audit_el->start_gtid));
|
|
|
|
report_ctx->contains_err= TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Report any out of order GTIDs */
|
|
|
|
for(i= 0; i < audit_el->late_gtids_real.elements; i++)
|
|
|
|
{
|
|
|
|
rpl_gtid *real_gtid=
|
|
|
|
(rpl_gtid *) dynamic_array_ptr(&(audit_el->late_gtids_real), i);
|
|
|
|
rpl_gtid *last_gtid= (rpl_gtid *) dynamic_array_ptr(
|
|
|
|
&(audit_el->late_gtids_previous), i);
|
|
|
|
DBUG_ASSERT(real_gtid && last_gtid);
|
|
|
|
|
|
|
|
report_f(out,
|
|
|
|
"Found out of order GTID. Got %u-%u-%llu after %u-%u-%llu",
|
|
|
|
PARAM_GTID((*real_gtid)), PARAM_GTID((*last_gtid)));
|
|
|
|
report_ctx->contains_err= TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Binlog_gtid_state_validator::report(FILE *out, my_bool is_strict_mode)
|
|
|
|
{
|
|
|
|
struct gtid_report_ctx report_ctx;
|
|
|
|
report_ctx.out_file= out;
|
|
|
|
report_ctx.is_strict_mode= is_strict_mode;
|
|
|
|
report_ctx.contains_err= FALSE;
|
|
|
|
my_hash_iterate(&m_audit_elem_domain_lookup, report_audit_findings, &report_ctx);
|
|
|
|
fflush(out);
|
|
|
|
return is_strict_mode ? report_ctx.contains_err : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window_gtid_event_filter::Window_gtid_event_filter()
|
|
|
|
: m_has_start(FALSE), m_has_stop(FALSE), m_is_active(FALSE),
|
|
|
|
m_has_passed(FALSE)
|
|
|
|
{
|
|
|
|
// m_start and m_stop do not need initial values if unused
|
|
|
|
}
|
|
|
|
|
|
|
|
int Window_gtid_event_filter::set_start_gtid(rpl_gtid *start)
|
|
|
|
{
|
|
|
|
if (m_has_start)
|
|
|
|
{
|
|
|
|
sql_print_error(
|
|
|
|
"Start position cannot have repeated domain "
|
|
|
|
"ids (found %u-%u-%llu when %u-%u-%llu was previously specified)",
|
|
|
|
PARAM_GTID((*start)), PARAM_GTID(m_start));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_has_start= TRUE;
|
|
|
|
m_start= *start;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Window_gtid_event_filter::set_stop_gtid(rpl_gtid *stop)
|
|
|
|
{
|
|
|
|
if (m_has_stop)
|
|
|
|
{
|
|
|
|
sql_print_error(
|
|
|
|
"Stop position cannot have repeated domain "
|
|
|
|
"ids (found %u-%u-%llu when %u-%u-%llu was previously specified)",
|
|
|
|
PARAM_GTID((*stop)), PARAM_GTID(m_stop));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_has_stop= TRUE;
|
|
|
|
m_stop= *stop;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Window_gtid_event_filter::is_range_invalid()
|
|
|
|
{
|
|
|
|
if (m_has_start && m_has_stop && m_start.seq_no > m_stop.seq_no)
|
|
|
|
{
|
|
|
|
sql_print_error(
|
|
|
|
"Queried GTID range is invalid in strict mode. Stop position "
|
|
|
|
"%u-%u-%llu is not greater than or equal to start %u-%u-%llu.",
|
|
|
|
PARAM_GTID(m_stop), PARAM_GTID(m_start));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline my_bool is_gtid_at_or_after(rpl_gtid *boundary,
|
|
|
|
rpl_gtid *test_gtid)
|
|
|
|
{
|
|
|
|
return test_gtid->domain_id == boundary->domain_id &&
|
|
|
|
test_gtid->seq_no >= boundary->seq_no;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline my_bool is_gtid_at_or_before(rpl_gtid *boundary,
|
|
|
|
rpl_gtid *test_gtid)
|
|
|
|
{
|
|
|
|
return test_gtid->domain_id == boundary->domain_id &&
|
|
|
|
test_gtid->seq_no <= boundary->seq_no;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Window_gtid_event_filter::exclude(rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
/* Assume result should be excluded to start */
|
|
|
|
my_bool should_exclude= TRUE;
|
|
|
|
|
2022-01-30 15:32:56 -07:00
|
|
|
DBUG_ASSERT((m_has_start && gtid->domain_id == m_start.domain_id) ||
|
|
|
|
(m_has_stop && gtid->domain_id == m_stop.domain_id));
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
|
|
|
|
if (!m_is_active && !m_has_passed)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
This filter has not yet been activated. Check if the gtid is within the
|
|
|
|
bounds of this window.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!m_has_start && is_gtid_at_or_before(&m_stop, gtid))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Start GTID was not provided, so we want to include everything from here
|
|
|
|
up to m_stop
|
|
|
|
*/
|
|
|
|
m_is_active= TRUE;
|
|
|
|
should_exclude= FALSE;
|
|
|
|
}
|
|
|
|
else if ((m_has_start && is_gtid_at_or_after(&m_start, gtid)) &&
|
|
|
|
(!m_has_stop || is_gtid_at_or_before(&m_stop, gtid)))
|
|
|
|
{
|
|
|
|
m_is_active= TRUE;
|
|
|
|
|
|
|
|
DBUG_PRINT("gtid-event-filter",
|
|
|
|
("Window: Begin (%d-%d-%llu, %d-%d-%llu]",
|
|
|
|
PARAM_GTID(m_start), PARAM_GTID(m_stop)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
As the start of the range is exclusive, if this gtid is the start of
|
|
|
|
the range, exclude it
|
|
|
|
*/
|
|
|
|
if (gtid->seq_no == m_start.seq_no)
|
|
|
|
should_exclude= TRUE;
|
|
|
|
else
|
|
|
|
should_exclude= FALSE;
|
|
|
|
|
|
|
|
if (m_has_stop && gtid->seq_no == m_stop.seq_no)
|
|
|
|
{
|
|
|
|
m_has_passed= TRUE;
|
|
|
|
DBUG_PRINT("gtid-event-filter",
|
|
|
|
("Window: End (%d-%d-%llu, %d-%d-%llu]",
|
|
|
|
PARAM_GTID(m_start), PARAM_GTID(m_stop)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* if (!m_is_active && !m_has_passed) */
|
|
|
|
else if (m_is_active && !m_has_passed)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
This window is currently active so we want the event group to be included
|
|
|
|
in the results. Additionally check if we are at the end of the window.
|
|
|
|
If no end of the window is provided, go indefinitely
|
|
|
|
*/
|
|
|
|
should_exclude= FALSE;
|
|
|
|
|
|
|
|
if (m_has_stop && is_gtid_at_or_after(&m_stop, gtid))
|
|
|
|
{
|
|
|
|
DBUG_PRINT("gtid-event-filter",
|
|
|
|
("Window: End (%d-%d-%llu, %d-%d-%llu]",
|
|
|
|
PARAM_GTID(m_start), PARAM_GTID(m_stop)));
|
|
|
|
m_is_active= FALSE;
|
|
|
|
m_has_passed= TRUE;
|
|
|
|
|
|
|
|
if (!is_gtid_at_or_before(&m_stop, gtid))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The GTID is after the finite stop of the window, don't let it pass
|
|
|
|
through
|
|
|
|
*/
|
|
|
|
should_exclude= TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return should_exclude;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Window_gtid_event_filter::has_finished()
|
|
|
|
{
|
|
|
|
return m_has_stop ? m_has_passed : FALSE;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
void free_u32_gtid_filter_element(void *p)
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<uint32> *gfe= (gtid_filter_element<uint32> *) p;
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
if (gfe->filter)
|
|
|
|
delete gfe->filter;
|
|
|
|
my_free(gfe);
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
template <typename T>
|
|
|
|
Id_delegating_gtid_event_filter<T>::Id_delegating_gtid_event_filter()
|
|
|
|
: m_num_stateful_filters(0), m_num_completed_filters(0),
|
|
|
|
m_id_restriction_mode(id_restriction_mode::MODE_NOT_SET)
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
void (*free_func)(void *);
|
|
|
|
if (std::is_same<T,uint32>::value)
|
|
|
|
free_func= free_u32_gtid_filter_element;
|
|
|
|
else
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
my_hash_init(PSI_INSTRUMENT_ME, &m_filters_by_id_hash, &my_charset_bin, 32,
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
offsetof(gtid_filter_element<T>, identifier),
|
|
|
|
sizeof(T), NULL, free_func,
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
HASH_UNIQUE);
|
|
|
|
|
|
|
|
m_default_filter= new Accept_all_gtid_filter();
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
template <typename T>
|
|
|
|
Id_delegating_gtid_event_filter<T>::~Id_delegating_gtid_event_filter()
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
|
|
|
my_hash_free(&m_filters_by_id_hash);
|
|
|
|
delete m_default_filter;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
template <typename T>
|
|
|
|
void Id_delegating_gtid_event_filter<T>::set_default_filter(
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
Gtid_event_filter *filter)
|
|
|
|
{
|
|
|
|
if (m_default_filter)
|
|
|
|
delete m_default_filter;
|
|
|
|
|
|
|
|
m_default_filter= filter;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
template <typename T>
|
|
|
|
gtid_filter_element<T> *
|
|
|
|
Id_delegating_gtid_event_filter<T>::find_or_create_filter_element_for_id(
|
|
|
|
T filter_id)
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<T> *fe=
|
|
|
|
(gtid_filter_element<T> *) my_hash_search(
|
|
|
|
&m_filters_by_id_hash, (const uchar *) &filter_id, 0);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
|
|
|
|
if (!fe)
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<T> *new_fe= (gtid_filter_element<T> *) my_malloc(
|
|
|
|
PSI_NOT_INSTRUMENTED, sizeof(gtid_filter_element<T>), MYF(MY_WME));
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
new_fe->filter= NULL;
|
|
|
|
new_fe->identifier= filter_id;
|
|
|
|
if (my_hash_insert(&m_filters_by_id_hash, (uchar*) new_fe))
|
|
|
|
{
|
|
|
|
my_free(new_fe);
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fe= new_fe;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fe;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
template <typename T>
|
|
|
|
my_bool Id_delegating_gtid_event_filter<T>::has_finished()
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
If all user-defined filters have deactivated, we are effectively
|
|
|
|
deactivated
|
|
|
|
*/
|
|
|
|
return m_num_stateful_filters &&
|
|
|
|
m_num_completed_filters == m_num_stateful_filters;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
template <typename T>
|
|
|
|
my_bool Id_delegating_gtid_event_filter<T>::exclude(rpl_gtid *gtid)
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
T filter_id= get_id_from_gtid(gtid);
|
|
|
|
gtid_filter_element<T> *filter_element=
|
|
|
|
(gtid_filter_element<T> *) my_hash_search(&m_filters_by_id_hash,
|
|
|
|
(const uchar *) &filter_id, 0);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
Gtid_event_filter *filter=
|
|
|
|
(filter_element ? filter_element->filter : m_default_filter);
|
|
|
|
my_bool ret= TRUE;
|
|
|
|
|
|
|
|
if(!filter_element || !filter->has_finished())
|
|
|
|
{
|
|
|
|
ret= filter->exclude(gtid);
|
|
|
|
|
|
|
|
/*
|
|
|
|
If this is an explicitly defined filter, e.g. Window-based filter, check
|
|
|
|
if it has completed, and update the counter accordingly if so.
|
|
|
|
*/
|
|
|
|
if (filter_element && filter->has_finished())
|
|
|
|
m_num_completed_filters++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
|
|
|
|
template <typename F> Gtid_event_filter* create_event_filter()
|
|
|
|
{
|
|
|
|
return new F();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
int Id_delegating_gtid_event_filter<T>::set_id_restrictions(
|
|
|
|
T *id_list, size_t n_ids, id_restriction_mode mode)
|
|
|
|
{
|
|
|
|
static const char *WHITELIST_NAME= "do", *BLACKLIST_NAME= "ignore";
|
|
|
|
|
|
|
|
size_t id_ctr;
|
|
|
|
int err;
|
|
|
|
const char *filter_name, *opposite_filter_name;
|
|
|
|
Gtid_event_filter *(*construct_filter)(void);
|
|
|
|
Gtid_event_filter *(*construct_default_filter)(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Set up variables which help this filter either be in whitelist or blacklist
|
|
|
|
mode
|
|
|
|
*/
|
|
|
|
if (mode == Gtid_event_filter::id_restriction_mode::WHITELIST_MODE)
|
|
|
|
{
|
|
|
|
filter_name= WHITELIST_NAME;
|
|
|
|
opposite_filter_name= BLACKLIST_NAME;
|
|
|
|
construct_filter=
|
|
|
|
create_event_filter<Accept_all_gtid_filter>;
|
|
|
|
construct_default_filter=
|
|
|
|
create_event_filter<Reject_all_gtid_filter>;
|
|
|
|
}
|
2022-05-14 13:02:51 +03:00
|
|
|
else
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
{
|
2022-05-14 13:02:51 +03:00
|
|
|
DBUG_ASSERT(mode ==
|
|
|
|
Gtid_event_filter::id_restriction_mode::BLACKLIST_MODE);
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
filter_name= BLACKLIST_NAME;
|
|
|
|
opposite_filter_name= WHITELIST_NAME;
|
|
|
|
construct_filter=
|
|
|
|
create_event_filter<Reject_all_gtid_filter>;
|
|
|
|
construct_default_filter=
|
|
|
|
create_event_filter<Accept_all_gtid_filter>;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_id_restriction_mode !=
|
|
|
|
Gtid_event_filter::id_restriction_mode::MODE_NOT_SET)
|
|
|
|
{
|
|
|
|
if (mode != m_id_restriction_mode)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If a rule specifying the opposite version of this has already been set,
|
|
|
|
error.
|
|
|
|
*/
|
|
|
|
sql_print_error("Cannot create %s filtering rule for %s id because "
|
|
|
|
"%s rule already exists",
|
|
|
|
filter_name, get_id_type_name(),
|
|
|
|
opposite_filter_name);
|
|
|
|
err= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This filter is specified more than once, only use the latest values */
|
|
|
|
my_hash_reset(&m_filters_by_id_hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (id_ctr= 0; id_ctr < n_ids; id_ctr++)
|
|
|
|
{
|
|
|
|
T filter_id= id_list[id_ctr];
|
|
|
|
gtid_filter_element<T> *map_element=
|
|
|
|
find_or_create_filter_element_for_id(filter_id);
|
|
|
|
|
|
|
|
if(map_element == NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If map_element is NULL, find_or_create_filter_element_for_id failed and
|
|
|
|
has already written the error message
|
|
|
|
*/
|
|
|
|
err= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
else if (map_element->filter == NULL)
|
|
|
|
{
|
|
|
|
map_element->filter= construct_filter();
|
|
|
|
m_num_stateful_filters++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(map_element->filter->get_filter_type() ==
|
2022-05-14 13:02:51 +03:00
|
|
|
(mode ==
|
2022-05-14 20:24:09 +03:00
|
|
|
Gtid_event_filter::id_restriction_mode::WHITELIST_MODE
|
|
|
|
? Gtid_event_filter::ACCEPT_ALL_GTID_FILTER_TYPE
|
|
|
|
: Gtid_event_filter::REJECT_ALL_GTID_FILTER_TYPE));
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
With a whitelist, we by only want to accept the ids which are specified.
|
|
|
|
Everything else should be denied.
|
|
|
|
|
|
|
|
With a blacklist, we by default want to accept everything that is not
|
|
|
|
specified in the list
|
|
|
|
*/
|
|
|
|
set_default_filter(construct_default_filter());
|
|
|
|
m_id_restriction_mode= mode;
|
|
|
|
err= 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
Window_gtid_event_filter *
|
|
|
|
Domain_gtid_event_filter::find_or_create_window_filter_for_id(
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
decltype(rpl_gtid::domain_id) domain_id)
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *filter_element=
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
find_or_create_filter_element_for_id(domain_id);
|
|
|
|
Window_gtid_event_filter *wgef= NULL;
|
|
|
|
|
|
|
|
if (filter_element->filter == NULL)
|
|
|
|
{
|
|
|
|
/* New filter */
|
|
|
|
wgef= new Window_gtid_event_filter();
|
|
|
|
filter_element->filter= wgef;
|
|
|
|
}
|
|
|
|
else if (filter_element->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE)
|
|
|
|
{
|
|
|
|
/* We have an existing window filter here */
|
|
|
|
wgef= (Window_gtid_event_filter *) filter_element->filter;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We have an existing filter but it is not of window type so propogate NULL
|
|
|
|
filter
|
|
|
|
*/
|
|
|
|
sql_print_error("cannot subset domain id %d by position, another rule "
|
|
|
|
"exists on that domain",
|
|
|
|
domain_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return wgef;
|
|
|
|
}
|
|
|
|
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
static my_bool check_filter_entry_validity(void *entry,
|
|
|
|
void *are_filters_invalid_arg)
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
(gtid_filter_element<decltype(rpl_gtid::domain_id)> *) entry;
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
|
|
|
|
if (fe)
|
|
|
|
{
|
|
|
|
Gtid_event_filter *gef= fe->filter;
|
|
|
|
if (gef->get_filter_type() == Gtid_event_filter::WINDOW_GTID_FILTER_TYPE)
|
|
|
|
{
|
|
|
|
Window_gtid_event_filter *wgef= (Window_gtid_event_filter *) gef;
|
|
|
|
if (wgef->is_range_invalid())
|
|
|
|
{
|
|
|
|
*((int *) are_filters_invalid_arg)= 1;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Domain_gtid_event_filter::validate_window_filters()
|
|
|
|
{
|
|
|
|
int are_filters_invalid= 0;
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
my_hash_iterate(&m_filters_by_id_hash, check_filter_entry_validity,
|
|
|
|
&are_filters_invalid);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
return are_filters_invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Domain_gtid_event_filter::add_start_gtid(rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
int err= 0;
|
|
|
|
Window_gtid_event_filter *filter_to_update=
|
|
|
|
find_or_create_window_filter_for_id(gtid->domain_id);
|
|
|
|
|
|
|
|
if (filter_to_update == NULL)
|
|
|
|
{
|
|
|
|
err= 1;
|
|
|
|
}
|
|
|
|
else if (!(err= filter_to_update->set_start_gtid(gtid)))
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
(gtid_filter_element<decltype(rpl_gtid::domain_id)> *) my_hash_search(
|
|
|
|
&m_filters_by_id_hash, (const uchar *) &(gtid->domain_id), 0);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
insert_dynamic(&m_start_filters, (const void *) &fe);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Domain_gtid_event_filter::add_stop_gtid(rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
int err= 0;
|
|
|
|
Window_gtid_event_filter *filter_to_update=
|
|
|
|
find_or_create_window_filter_for_id(gtid->domain_id);
|
|
|
|
|
|
|
|
if (filter_to_update == NULL)
|
|
|
|
{
|
|
|
|
err= 1;
|
|
|
|
}
|
|
|
|
else if (!(err= filter_to_update->set_stop_gtid(gtid)))
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
(gtid_filter_element<decltype(rpl_gtid::domain_id)> *) my_hash_search(
|
|
|
|
&m_filters_by_id_hash, (const uchar *) &(gtid->domain_id), 0);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
insert_dynamic(&m_stop_filters, (const void *) &fe);
|
|
|
|
|
|
|
|
/*
|
|
|
|
A window with a stop position can be disabled, and is therefore stateful.
|
|
|
|
*/
|
|
|
|
m_num_stateful_filters++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Default filtering behavior changes with GTID stop positions, where we
|
|
|
|
exclude all domains not present in the stop list
|
|
|
|
*/
|
|
|
|
if (m_default_filter->get_filter_type() == ACCEPT_ALL_GTID_FILTER_TYPE)
|
|
|
|
{
|
|
|
|
delete m_default_filter;
|
|
|
|
m_default_filter= new Reject_all_gtid_filter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_gtid *Domain_gtid_event_filter::get_start_gtids()
|
|
|
|
{
|
|
|
|
rpl_gtid *gtid_list;
|
|
|
|
uint32 i;
|
|
|
|
size_t n_start_gtids= get_num_start_gtids();
|
|
|
|
|
|
|
|
gtid_list= (rpl_gtid *) my_malloc(
|
|
|
|
PSI_INSTRUMENT_ME, n_start_gtids * sizeof(rpl_gtid), MYF(MY_WME));
|
|
|
|
|
|
|
|
for (i = 0; i < n_start_gtids; i++)
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
*(gtid_filter_element<decltype(rpl_gtid::domain_id)> **)
|
|
|
|
dynamic_array_ptr(&m_start_filters, i);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
DBUG_ASSERT(fe->filter &&
|
|
|
|
fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE);
|
|
|
|
Window_gtid_event_filter *wgef=
|
|
|
|
(Window_gtid_event_filter *) fe->filter;
|
|
|
|
|
|
|
|
rpl_gtid win_start_gtid= wgef->get_start_gtid();
|
|
|
|
gtid_list[i]= win_start_gtid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gtid_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpl_gtid *Domain_gtid_event_filter::get_stop_gtids()
|
|
|
|
{
|
|
|
|
rpl_gtid *gtid_list;
|
|
|
|
uint32 i;
|
|
|
|
size_t n_stop_gtids= get_num_stop_gtids();
|
|
|
|
|
|
|
|
gtid_list= (rpl_gtid *) my_malloc(
|
|
|
|
PSI_INSTRUMENT_ME, n_stop_gtids * sizeof(rpl_gtid), MYF(MY_WME));
|
|
|
|
|
|
|
|
for (i = 0; i < n_stop_gtids; i++)
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
*(gtid_filter_element<decltype(rpl_gtid::domain_id)> **)
|
|
|
|
dynamic_array_ptr(&m_stop_filters, i);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
DBUG_ASSERT(fe->filter &&
|
|
|
|
fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE);
|
|
|
|
Window_gtid_event_filter *wgef=
|
|
|
|
(Window_gtid_event_filter *) fe->filter;
|
|
|
|
|
|
|
|
rpl_gtid win_stop_gtid= wgef->get_stop_gtid();
|
|
|
|
gtid_list[i]= win_stop_gtid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gtid_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Domain_gtid_event_filter::clear_start_gtids()
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
for (i = 0; i < get_num_start_gtids(); i++)
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
*(gtid_filter_element<decltype(rpl_gtid::domain_id)> **)
|
|
|
|
dynamic_array_ptr(&m_start_filters, i);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
DBUG_ASSERT(fe->filter &&
|
|
|
|
fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE);
|
|
|
|
Window_gtid_event_filter *wgef=
|
|
|
|
(Window_gtid_event_filter *) fe->filter;
|
|
|
|
|
|
|
|
if (wgef->has_stop())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Don't delete the whole filter if it already has a stop position attached
|
|
|
|
*/
|
|
|
|
wgef->clear_start_pos();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
This domain only has a stop, so delete the whole filter
|
|
|
|
*/
|
|
|
|
my_hash_delete(&m_filters_by_id_hash, (uchar *) fe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
reset_dynamic(&m_start_filters);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Domain_gtid_event_filter::clear_stop_gtids()
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < get_num_stop_gtids(); i++)
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *fe=
|
|
|
|
*(gtid_filter_element<decltype(rpl_gtid::domain_id)> **)
|
|
|
|
dynamic_array_ptr(&m_stop_filters, i);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
DBUG_ASSERT(fe->filter &&
|
|
|
|
fe->filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE);
|
|
|
|
Window_gtid_event_filter *wgef=
|
|
|
|
(Window_gtid_event_filter *) fe->filter;
|
|
|
|
|
|
|
|
if (wgef->has_start())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Don't delete the whole filter if it already has a start position
|
|
|
|
attached
|
|
|
|
*/
|
|
|
|
wgef->clear_stop_pos();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
This domain only has a start, so delete the whole filter
|
|
|
|
*/
|
|
|
|
my_hash_delete(&m_filters_by_id_hash, (uchar *) fe);
|
|
|
|
}
|
|
|
|
m_num_stateful_filters--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Stop positions were cleared and we want to be inclusive again of other
|
|
|
|
domains again
|
|
|
|
*/
|
|
|
|
if (m_default_filter->get_filter_type() == REJECT_ALL_GTID_FILTER_TYPE)
|
|
|
|
{
|
|
|
|
delete m_default_filter;
|
|
|
|
m_default_filter= new Accept_all_gtid_filter();
|
|
|
|
}
|
|
|
|
|
|
|
|
reset_dynamic(&m_stop_filters);
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Domain_gtid_event_filter::exclude(rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
my_bool include_domain= TRUE;
|
|
|
|
/*
|
|
|
|
If GTID stop positions are provided, we limit the domains which are output
|
|
|
|
to only be those specified with stop positions
|
|
|
|
*/
|
|
|
|
if (get_num_stop_gtids())
|
|
|
|
{
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
decltype(rpl_gtid::domain_id) filter_id= get_id_from_gtid(gtid);
|
|
|
|
gtid_filter_element<decltype(rpl_gtid::domain_id)> *filter_element=
|
|
|
|
(gtid_filter_element<decltype(rpl_gtid::domain_id)> *) my_hash_search(
|
|
|
|
&m_filters_by_id_hash, (const uchar *) &filter_id, 0);
|
MDEV-4989: Support for GTID in mysqlbinlog
New Feature:
===========
This commit extends the mariadb-binlog capabilities to allow events
to be filtered by GTID ranges. More specifically, the
--start-position and --stop-position arguments have been extended to
accept values formatted as a list of GTID positions, e.g.
--start-position=0-1-0,1-2-55. The following specific capabilities
are addressed:
1) GTIDs can be used to filter results on local binlog files
2) GTIDs can be used to filter results from remote servers
3) Implemented --gtid-strict-mode that ensures the GTID event
stream in each domain is monotonically increasing
4) Added new level of verbosity in mysqlbinlog -vvv to print
additional diagnostic information/warnings about invalid GTID
states
5) For a given GTID range, its start and stop position parameters
aim to mimic the behaviors of
CHANGE MASTER TO MASTER_USE_GTID=slave_pos and
START SLAVE UNTIL master_gtid_pos=<GTID>, respectively. In
particular, the start-position list expresses a gtid state of
the server, similarly to how @@global.gtid_slave_pos expresses
the gtid state of a slave server when connecting to a master
with MASTER_USE_GTID=slave_pos.
The GTID start-position list is exclusive and the
stop-position list is inclusive. This allows users to receive
events strictly after those that they already have, and is
useful in cases of point in (logical) time recovery including
1) events were received out of order and should be re-sent, or
2) specifying the gtid state of a slave to get events newer
than their current state. If a seq_no is 0 for start-position,
it means to include the entirety of the domain. If a seq_no is
0 for stop-position, it means to exclude all events from that
domain. The GTIDs provided in a start position argument must
match with the GTID state of the first processed log (i.e.
those listed in the Gtid_list event). If a stop position is
provided, the events that are output are limited to only those
with domain ids listed in the argument. When specifying
combinations of start and stop positions, the following
behaviors are expected:
[--start-position without --stop-position]: Events that have domain
ids in the start position are output if their seq_no occurs after
the respective start position. Events with domain ids that are
unspecified in the start position list are also output. Note that if
the Gtid_list event of the first binary log is populated (i.e.
non-empty), each domain in the Gtid_list must be present in the
start-position list with a seq_no at or after the listed value.
This behavior mimics how a slave only processes events after the
state provided by @@global.gtid_slave_pos when connecting to a
master with CHANGE MASTER TO MASTER_USE_GTID=slave_pos.
[--stop-position without --start-position]: Output is limited to
only events with both 1) domain ids that are present in the given
stop position list and 2) seq_nos that are less than or equal to
their respective stop GTID. Once all GTIDs in the stop position
list have been processed, the program will stop processing log
files. This behavior mimics how
START SLAVE UNTIL master_gtid_pos=<G>
has a slave only process events with domain ids present in G with
their seq_nos at or before the respective gtid.
[--start-position and --stop-position]: Output consists of the
intersection between the events permitted by both the start and stop
position rules. More concretely, the output can be defined by a
union of the following rules:
1. For domains which exist in both the start and stop position
lists, the events which exist in-between these positions
(exclusive start, inclusive stop) are output
2. For all other events, the rules of
[--stop-position without --start-position] are followed
This is due to the implicit filtering within each individual rule.
Even though the start position rule always includes events from
unspecified domains, the stop position rule takes precedence because
it always excludes events from unspecified domains. In other words,
events which the start position rule would have included would then
always be excluded by the stop position rule.
[neither --start-position nor --stop-position]: Events are not
omitted based on GTID positioning; however, --gtid-strict-mode and
-vvv can still analyze gtid correctness for warning and error
reporting.
[repeated specification of --start-position or --stop-position]:
Subsequent specifications of start and stop positions completely
override previous ones. E.g., if invoked as
mysqlbinlog --start-position=<G1> --start-position=<G2> ...
All GTIDs specified in G1 are ignored and only those specified in G2
are used for the start position.
A few additional notes:
1) this commit squashes together the commits:
f4319661120e-78a9d49907ba
2) Changed rpl.rpl_blackhole_row_annotate test because it has
out of order GTIDs in its binlog, so I added
--skip-gtid-strict-mode
3) After all binlog events have been written, the session server
id and domain id are reset to their values in the global state
Reviewed By:
===========
Andrei Elkin: <andrei.elkin@mariadb.com>
2021-08-11 11:29:37 -06:00
|
|
|
if (filter_element)
|
|
|
|
{
|
|
|
|
Gtid_event_filter *filter= filter_element->filter;
|
|
|
|
if (filter->get_filter_type() == WINDOW_GTID_FILTER_TYPE)
|
|
|
|
{
|
|
|
|
Window_gtid_event_filter *wgef= (Window_gtid_event_filter *) filter;
|
|
|
|
include_domain= wgef->has_stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return include_domain ? Id_delegating_gtid_event_filter::exclude(gtid)
|
|
|
|
: TRUE;
|
|
|
|
}
|
MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and --ignore-server-ids options for mysqlbinlog
New Feature:
============
Extend mariadb-binlog command-line tool to allow for filtering
events using GTID domain and server ids. The functionality mimics
that of a replica server’s DO_DOMAIN_IDS, IGNORE_DOMAIN_IDS, and
IGNORE_SERVER_IDS from CHANGE MASTER TO. For completeness, this
patch additionally adds the option --do-server-ids as an alias for
--server-id, which now accepts a list of server ids instead of a
single one.
Example usage:
mariadb-binlog --do-domain-ids=2,3,4 --do-server-ids=1,3
master-bin.000001
Functional Notes:
1. --do-domain-ids cannot be combined with --ignore-domain-ids
2. --do-server-ids cannot be combined with --ignore-server-ids
3. A domain id filter can be combined with a server id filter
4. When any new filter options are combined with the
--gtid-strict-mode option, events from excluded domains/servers are
not validated.
5. Domain/server id filters can be combined with GTID ranges (i.e.
specifications of --start-position and --stop-position). However,
because the --stop-position option implicitly undertakes filtering
to only output events within its range of domains, when combined
with --do-domain-ids or --ignore-domain-ids, output will consist of
the intersection between the filters. Specifically, with
--do-domain-ids and --stop-position, only events with domain ids
present in both argument lists will be output. Conversely, with
--ignore-domain-ids and --stop-position, only events with domain ids
present in the --stop-position and absent from the
--ignore-domain-ids options will be output.
Reviewed By
============
Andrei Elkin <andrei.elkin@mariadb.com>
2022-02-03 08:31:05 -07:00
|
|
|
|
|
|
|
Intersecting_gtid_event_filter::Intersecting_gtid_event_filter(
|
|
|
|
Gtid_event_filter *filter1, Gtid_event_filter *filter2)
|
|
|
|
{
|
|
|
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, &m_filters,
|
|
|
|
sizeof(Gtid_event_filter *), 3, 3, MYF(0));
|
|
|
|
insert_dynamic(&m_filters, (void *) &filter1);
|
|
|
|
insert_dynamic(&m_filters, (void *) &filter2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Intersecting_gtid_event_filter::~Intersecting_gtid_event_filter()
|
|
|
|
{
|
|
|
|
Gtid_event_filter *tmp_filter= NULL;
|
|
|
|
ulong i;
|
|
|
|
for (i= 0; i < m_filters.elements; i++)
|
|
|
|
{
|
|
|
|
tmp_filter= *(Gtid_event_filter **) dynamic_array_ptr(&m_filters, i);
|
|
|
|
delete tmp_filter;
|
|
|
|
}
|
|
|
|
delete_dynamic(&m_filters);
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Intersecting_gtid_event_filter::exclude(rpl_gtid *gtid)
|
|
|
|
{
|
|
|
|
Gtid_event_filter *tmp_filter= NULL;
|
|
|
|
ulong i;
|
|
|
|
for (i= 0; i < m_filters.elements; i++)
|
|
|
|
{
|
|
|
|
tmp_filter= *(Gtid_event_filter **) dynamic_array_ptr(&m_filters, i);
|
|
|
|
DBUG_ASSERT(tmp_filter);
|
|
|
|
if (tmp_filter->exclude(gtid))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_bool Intersecting_gtid_event_filter::has_finished()
|
|
|
|
{
|
|
|
|
Gtid_event_filter *tmp_filter= NULL;
|
|
|
|
ulong i;
|
|
|
|
for (i= 0; i < m_filters.elements; i++)
|
|
|
|
{
|
|
|
|
tmp_filter= *(Gtid_event_filter **) dynamic_array_ptr(&m_filters, i);
|
|
|
|
DBUG_ASSERT(tmp_filter);
|
|
|
|
if (tmp_filter->has_finished())
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|