[PATCH] Fix "Assertion `THR_PFS_initialized' failed" in main.bootstrap
by Kristian Nielsen 15 Mar '24
by Kristian Nielsen 15 Mar '24
15 Mar '24
The problem is that the manager thread may not have yet started when
bootstrap exits. This causes assertion when the thread tries to access
performance schema data after shutdown_performance_schema() has been called.
Fix by waiting for the manager thread to have started before proceeding.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
sql/sql_manager.cc | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 3d3728b9e00..d4a410ce5fb 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -76,6 +76,8 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
pthread_detach_this_thread();
manager_thread = pthread_self();
mysql_mutex_lock(&LOCK_manager);
+ manager_thread_in_use = 1;
+ mysql_cond_signal(&COND_manager);
while (!abort_manager)
{
/* XXX: This will need to be made more general to handle different
@@ -135,12 +137,19 @@ void start_handle_manager()
pthread_t hThread;
int err;
DBUG_EXECUTE_IF("delay_start_handle_manager", my_sleep(1000););
- manager_thread_in_use = 1;
mysql_cond_init(key_COND_manager, &COND_manager,NULL);
mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL);
if ((err= mysql_thread_create(key_thread_handle_manager, &hThread,
&connection_attrib, handle_manager, 0)))
+ {
sql_print_warning("Can't create handle_manager thread (errno: %M)", err);
+ DBUG_VOID_RETURN;
+ }
+
+ mysql_mutex_lock(&LOCK_manager);
+ while (!manager_thread_in_use)
+ mysql_cond_wait(&COND_manager, &LOCK_manager);
+ mysql_mutex_unlock(&LOCK_manager);
}
DBUG_VOID_RETURN;
}
--
2.30.2
1
0
[PATCH] MDEV-33551: Semi-sync Wait Point AFTER_COMMIT Slow on Workloads with Heavy Concurrency
by Kristian Nielsen 12 Mar '24
by Kristian Nielsen 12 Mar '24
12 Mar '24
From: Brandon Nesterenko <brandon.nesterenko(a)mariadb.com>
When using semi-sync replication with
rpl_semi_sync_master_wait_point=AFTER_COMMIT, the performance of the
primary can significantly reduce compared to AFTER_SYNC's
performance for workloads with many concurrent users executing
transactions. This is because all connections on the primary share
the same cond_wait variable/mutex pair, so any time an ACK is
received from a replica, all waiting connections are awoken to check
if the ACK was for itself, which is done in mutual exclusion.
This patch changes this such that the waiting THD will use its own
local condition variable, and the ACK receiver thread only signals
connections which have been ACKed for wakeup. That is, the
THD::LOCK_wakeup_ready condition variable is re-used for this
purpose, and the Active_tranx queue nodes are extended to hold the
waiting thread, so it can be signalled once ACKed.
Additionally:
1) At master shutdown (when waiting for slaves), instead of the
main loop individually waiting for each ACK,
await_slave_reply() (renamed await_all_slave_replies) now
awaits ACKs for each transaction within one invocation.
2) The time when thd::is_awaiting_semi_sync_ack is set is moved
to at binlogging time, to ensure transactions which have been
binlogged and queued up to await an ACK are not killed,
and are still waited on.
Review note: DBUG_ASSERT addition from previous commit is changed
to a print warning, and the .test assert_greps to ensure its
absence.
Reviewed By:
============
Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
.../r/rpl_semi_sync_cond_var_per_thd.result | 32 +++
.../rpl/t/rpl_semi_sync_cond_var_per_thd.test | 10 +
sql/log.cc | 12 +-
sql/mysqld.cc | 14 +-
sql/semisync_master.cc | 241 +++++++++++-------
sql/semisync_master.h | 122 +++++++--
sql/sql_class.h | 14 +-
7 files changed, 311 insertions(+), 134 deletions(-)
create mode 100644 mysql-test/suite/rpl/r/rpl_semi_sync_cond_var_per_thd.result
diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_cond_var_per_thd.result b/mysql-test/suite/rpl/r/rpl_semi_sync_cond_var_per_thd.result
new file mode 100644
index 00000000000..08f601447d5
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_semi_sync_cond_var_per_thd.result
@@ -0,0 +1,32 @@
+include/master-slave.inc
+[connection master]
+connection master;
+call mtr.add_suppression("Got an error reading communication packets");
+set @save_bgc_count= @@global.binlog_commit_wait_count;
+set @save_bgc_usec= @@global.binlog_commit_wait_usec;
+set @save_debug_dbug= @@global.debug_dbug;
+set @@global.binlog_commit_wait_count=3;
+set @@global.binlog_commit_wait_usec=10000000;
+set @@global.debug_dbug="+d,testing_cond_var_per_thd";
+# Ensure semi-sync is on
+connection slave;
+connection master;
+# Create three transactions to binlog group commit together
+connection master;
+create table t1 (a int);
+connection server_1;
+create table t2 (a int);
+connection default;
+create table t3 (a int);
+connection master;
+connection server_1;
+connection default;
+include/assert_grep.inc [Check that there is no 'Thread awaiting semi-sync ACK was awoken before its ACK' warning in error log.]
+#
+# Cleanup
+connection master;
+set @@global.binlog_commit_wait_count=@save_bgc_count;
+set @@global.binlog_commit_wait_usec=@save_bgc_usec;
+set @@global.debug_dbug=@save_debug_dbug;
+drop table t1, t2, t3;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test b/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test
index f8fa0a99d9c..2d9a6d13048 100644
--- a/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test
+++ b/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test
@@ -22,10 +22,13 @@
--source include/master-slave.inc
--connection master
+call mtr.add_suppression("Got an error reading communication packets");
set @save_bgc_count= @@global.binlog_commit_wait_count;
set @save_bgc_usec= @@global.binlog_commit_wait_usec;
+set @save_debug_dbug= @@global.debug_dbug;
set @@global.binlog_commit_wait_count=3;
set @@global.binlog_commit_wait_usec=10000000;
+set @@global.debug_dbug="+d,testing_cond_var_per_thd";
--echo # Ensure semi-sync is on
--connection slave
@@ -53,12 +56,19 @@ source include/wait_for_status_var.inc;
--connection default
--reap
+--let $assert_text= Check that there is no 'Thread awaiting semi-sync ACK was awoken before its ACK' warning in error log.
+--let $assert_select=Thread awaiting semi-sync ACK was awoken before its ACK
+--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let $assert_count= 0
+--let $assert_only_after=CURRENT_TEST
+--source include/assert_grep.inc
--echo #
--echo # Cleanup
--connection master
set @@global.binlog_commit_wait_count=@save_bgc_count;
set @@global.binlog_commit_wait_usec=@save_bgc_usec;
+set @@global.debug_dbug=@save_debug_dbug;
drop table t1, t2, t3;
--source include/rpl_end.inc
diff --git a/sql/log.cc b/sql/log.cc
index ce5970b6a03..6df6ee7a03c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -6870,8 +6870,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
#ifdef HAVE_REPLICATION
- if (repl_semisync_master.report_binlog_update(thd, log_file_name,
- file->pos_in_file))
+ if (repl_semisync_master.report_binlog_update(
+ thd, thd, log_file_name, file->pos_in_file))
{
sql_print_error("Failed to run 'after_flush' hooks");
error= 1;
@@ -8467,7 +8467,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
#ifdef HAVE_REPLICATION
if (likely(!current->error) &&
unlikely(repl_semisync_master.
- report_binlog_update(current->thd,
+ report_binlog_update(current->thd, leader->thd,
current->cache_mngr->
last_commit_pos_file,
current->cache_mngr->
@@ -8549,17 +8549,19 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
bool first __attribute__((unused))= true;
- bool last __attribute__((unused));
+ bool last;
for (current= queue; current != NULL; current= current->next)
{
last= current->next == NULL;
#ifdef HAVE_REPLICATION
+
if (likely(!current->error))
current->error=
repl_semisync_master.wait_after_sync(current->cache_mngr->
last_commit_pos_file,
current->cache_mngr->
- last_commit_pos_offset);
+ last_commit_pos_offset,
+ last);
#endif
first= false;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e224871795e..b315edc091c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1750,18 +1750,12 @@ static void close_connections(void)
/*
If we are waiting on any ACKs, delay killing the thread until either an ACK
is received or the timeout is hit.
-
- Allow at max the number of sessions to await a timeout; however, if all
- ACKs have been received in less iterations, then quit early
*/
- if (shutdown_wait_for_slaves && repl_semisync_master.get_master_enabled())
+ if (shutdown_wait_for_slaves && repl_semisync_master.get_master_enabled() &&
+ repl_semisync_master.sync_get_master_wait_sessions())
{
- int waiting_threads= repl_semisync_master.sync_get_master_wait_sessions();
- if (waiting_threads)
- sql_print_information("Delaying shutdown to await semi-sync ACK");
-
- while (waiting_threads-- > 0)
- repl_semisync_master.await_slave_reply();
+ sql_print_information("Delaying shutdown to await semi-sync ACK");
+ repl_semisync_master.await_all_slave_replies();
}
DBUG_EXECUTE_IF("delay_shutdown_phase_2_after_semisync_wait",
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index 0eaf0f0e0e2..411b3dfc84e 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -68,6 +68,14 @@ static ulonglong timespec_to_usec(const struct timespec *ts)
return (ulonglong) ts->tv_sec * TIME_MILLION + ts->tv_nsec / TIME_THOUSAND;
}
+int signal_waiting_transaction(THD *waiting_thd, const char *binlog_file,
+ my_off_t binlog_pos)
+{
+ if (waiting_thd->is_awaiting_semisync_ack)
+ mysql_cond_signal(&waiting_thd->COND_wakeup_ready);
+ return 0;
+}
+
/*******************************************************************************
*
* <Active_tranx> class : manage all active transaction nodes
@@ -142,7 +150,18 @@ int Active_tranx::compare(const char *log_file_name1, my_off_t log_file_pos1,
return 0;
}
-int Active_tranx::insert_tranx_node(const char *log_file_name,
+int Active_tranx::for_front(active_tranx_action action)
+{
+ /*
+ This should be called after validating !Active_tranx::is_empty() while
+ holding LOCK_binlog
+ */
+ DBUG_ASSERT(m_trx_front);
+ return action(m_trx_front->thd, m_trx_front->log_name, m_trx_front->log_pos);
+}
+
+int Active_tranx::insert_tranx_node(THD *thd_to_wait,
+ const char *log_file_name,
my_off_t log_file_pos)
{
Tranx_node *ins_node;
@@ -165,6 +184,7 @@ int Active_tranx::insert_tranx_node(const char *log_file_name,
strncpy(ins_node->log_name, log_file_name, FN_REFLEN-1);
ins_node->log_name[FN_REFLEN-1] = 0; /* make sure it ends properly */
ins_node->log_pos = log_file_pos;
+ ins_node->thd= thd_to_wait;
if (!m_trx_front)
{
@@ -232,28 +252,22 @@ bool Active_tranx::is_tranx_end_pos(const char *log_file_name,
DBUG_RETURN(entry != NULL);
}
-void Active_tranx::clear_active_tranx_nodes(const char *log_file_name,
- my_off_t log_file_pos)
+void Active_tranx::clear_active_tranx_nodes(
+ const char *log_file_name, my_off_t log_file_pos,
+ active_tranx_action pre_delete_hook)
{
Tranx_node *new_front;
DBUG_ENTER("Active_tranx::::clear_active_tranx_nodes");
- if (log_file_name != NULL)
+ new_front= m_trx_front;
+ while (new_front)
{
- new_front = m_trx_front;
-
- while (new_front)
- {
- if (compare(new_front, log_file_name, log_file_pos) > 0)
- break;
- new_front = new_front->next;
- }
- }
- else
- {
- /* If log_file_name is NULL, clear everything. */
- new_front = NULL;
+ if ((log_file_name != NULL) &&
+ compare(new_front, log_file_name, log_file_pos) > 0)
+ break;
+ pre_delete_hook(new_front->thd, new_front->log_name, new_front->log_pos);
+ new_front = new_front->next;
}
if (new_front == NULL)
@@ -500,19 +514,31 @@ void Repl_semi_sync_master::unlock()
mysql_mutex_unlock(&LOCK_binlog);
}
-void Repl_semi_sync_master::cond_broadcast()
-{
- mysql_cond_broadcast(&COND_binlog_send);
-}
-
-int Repl_semi_sync_master::cond_timewait(struct timespec *wait_time)
+int Repl_semi_sync_master::cond_timewait(THD *thd, struct timespec *_wait_time)
{
int wait_res;
+ struct timespec gen_wait_time;
+ struct timespec *real_wait_time;
DBUG_ENTER("Repl_semi_sync_master::cond_timewait()");
- wait_res= mysql_cond_timedwait(&COND_binlog_send,
- &LOCK_binlog, wait_time);
+ if (_wait_time == NULL)
+ {
+ create_timeout(&gen_wait_time, NULL);
+ real_wait_time= &gen_wait_time;
+ }
+ else
+ {
+ real_wait_time= _wait_time;
+ }
+
+ /*
+ All connection threads share the mutex (LOCK_binlog) to keep consistent
+ with the Active_tranx cache, but each thread has its own condition variable
+ on which it waits.
+ */
+ wait_res= mysql_cond_timedwait(&thd->COND_wakeup_ready, &LOCK_binlog,
+ real_wait_time);
DBUG_RETURN(wait_res);
}
@@ -533,7 +559,8 @@ void Repl_semi_sync_master::remove_slave()
Signal transactions waiting in commit_trx() that they do not have to
wait anymore.
*/
- cond_broadcast();
+ m_active_tranxs->clear_active_tranx_nodes(NULL, NULL,
+ signal_waiting_transaction);
}
unlock();
}
@@ -616,7 +643,6 @@ int Repl_semi_sync_master::report_reply_binlog(uint32 server_id,
my_off_t log_file_pos)
{
int cmp;
- bool can_release_threads = false;
bool need_copy_send_pos = true;
DBUG_ENTER("Repl_semi_sync_master::report_reply_binlog");
@@ -668,45 +694,26 @@ int Repl_semi_sync_master::report_reply_binlog(uint32 server_id,
/* Remove all active transaction nodes before this point. */
DBUG_ASSERT(m_active_tranxs != NULL);
- m_active_tranxs->clear_active_tranx_nodes(log_file_name, log_file_pos);
+ m_active_tranxs->clear_active_tranx_nodes(log_file_name, log_file_pos,
+ signal_waiting_transaction);
+ m_wait_file_name_inited= false;
DBUG_PRINT("semisync", ("%s: Got reply at (%s, %lu)",
"Repl_semi_sync_master::report_reply_binlog",
log_file_name, (ulong)log_file_pos));
}
- if (rpl_semi_sync_master_wait_sessions > 0)
- {
- /* Let us check if some of the waiting threads doing a trx
- * commit can now proceed.
- */
- cmp = Active_tranx::compare(m_reply_file_name, m_reply_file_pos,
- m_wait_file_name, m_wait_file_pos);
- if (cmp >= 0)
- {
- /* Yes, at least one waiting thread can now proceed:
- * let us release all waiting threads with a broadcast
- */
- can_release_threads = true;
- m_wait_file_name_inited = false;
- }
- }
l_end:
unlock();
- if (can_release_threads)
- {
- DBUG_PRINT("semisync", ("%s: signal all waiting threads.",
- "Repl_semi_sync_master::report_reply_binlog"));
-
- cond_broadcast();
- }
DBUG_RETURN(0);
}
-int Repl_semi_sync_master::wait_after_sync(const char *log_file, my_off_t log_pos)
+int Repl_semi_sync_master::wait_after_sync(const char *log_file,
+ my_off_t log_pos,
+ bool unmark_thd_awaiting_ack)
{
if (!get_master_enabled())
return 0;
@@ -714,7 +721,8 @@ int Repl_semi_sync_master::wait_after_sync(const char *log_file, my_off_t log_po
int ret= 0;
if(log_pos &&
wait_point() == SEMI_SYNC_MASTER_WAIT_POINT_AFTER_BINLOG_SYNC)
- ret= commit_trx(log_file + dirname_length(log_file), log_pos);
+ ret= commit_trx(log_file + dirname_length(log_file), log_pos,
+ unmark_thd_awaiting_ack);
return ret;
}
@@ -762,24 +770,27 @@ int Repl_semi_sync_master::wait_after_rollback(THD *thd, bool all)
/**
The method runs after flush to binary log is done.
*/
-int Repl_semi_sync_master::report_binlog_update(THD* thd, const char *log_file,
+int Repl_semi_sync_master::report_binlog_update(THD *trans_thd,
+ THD *waiter_thd,
+ const char *log_file,
my_off_t log_pos)
{
if (get_master_enabled())
{
Trans_binlog_info *log_info;
- if (!(log_info= thd->semisync_info))
+ if (!(log_info= trans_thd->semisync_info))
{
if(!(log_info= (Trans_binlog_info*)my_malloc(PSI_INSTRUMENT_ME,
sizeof(Trans_binlog_info), MYF(0))))
return 1;
- thd->semisync_info= log_info;
+ trans_thd->semisync_info= log_info;
}
strcpy(log_info->log_file, log_file + dirname_length(log_file));
log_info->log_pos = log_pos;
- return write_tranx_in_binlog(log_info->log_file, log_pos);
+ return write_tranx_in_binlog(waiter_thd, log_info->log_file,
+ log_pos);
}
return 0;
@@ -825,8 +836,9 @@ void Repl_semi_sync_master::dump_end(THD* thd)
ack_receiver.remove_slave(thd);
}
-int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
- my_off_t trx_wait_binlog_pos)
+int Repl_semi_sync_master::commit_trx(const char *trx_wait_binlog_name,
+ my_off_t trx_wait_binlog_pos,
+ bool unmark_thd_awaiting_ack)
{
bool success= 0;
DBUG_ENTER("Repl_semi_sync_master::commit_trx");
@@ -852,9 +864,8 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
lock();
/* This must be called after acquired the lock */
- THD_ENTER_COND(thd, &COND_binlog_send, &LOCK_binlog,
- & stage_waiting_for_semi_sync_ack_from_slave,
- & old_stage);
+ THD_ENTER_COND(thd, &thd->COND_wakeup_ready, &LOCK_binlog,
+ &stage_waiting_for_semi_sync_ack_from_slave, &old_stage);
/* This is the real check inside the mutex. */
if (!get_master_enabled() || !is_on())
@@ -902,7 +913,7 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
trx_wait_binlog_pos,
m_wait_file_name, m_wait_file_pos);
if (cmp <= 0)
- {
+ {
/* This thd has a lower position, let's update the minimum info. */
strmake_buf(m_wait_file_name, trx_wait_binlog_name);
m_wait_file_pos = trx_wait_binlog_pos;
@@ -934,20 +945,13 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
*/
rpl_semi_sync_master_wait_sessions++;
- /* We keep track of when this thread is awaiting an ack to ensure it is
- * not killed while awaiting an ACK if a shutdown is issued.
- */
- set_thd_awaiting_semisync_ack(thd, TRUE);
-
DBUG_PRINT("semisync", ("%s: wait %lu ms for binlog sent (%s, %lu)",
"Repl_semi_sync_master::commit_trx",
m_wait_timeout,
m_wait_file_name, (ulong)m_wait_file_pos));
create_timeout(&abstime, &start_ts);
- wait_result = cond_timewait(&abstime);
-
- set_thd_awaiting_semisync_ack(thd, FALSE);
+ wait_result = cond_timewait(thd, &abstime);
rpl_semi_sync_master_wait_sessions--;
if (wait_result != 0)
@@ -979,14 +983,29 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
{
rpl_semi_sync_master_trx_wait_num++;
rpl_semi_sync_master_trx_wait_time += wait_time;
- /*
- Assert we have either recieved our ACK; or have timed out and are
- awoken in an off state.
- */
- DBUG_ASSERT(!get_master_enabled() || !is_on() || thd->is_killed() ||
- 0 <= Active_tranx::compare(
- m_reply_file_name, m_reply_file_pos,
- trx_wait_binlog_name, trx_wait_binlog_pos));
+
+ DBUG_EXECUTE_IF("testing_cond_var_per_thd", {
+ /*
+ DBUG log warning to ensure we have either recieved our ACK; or
+ have timed out and are awoken in an off state. Test
+ rpl.rpl_semi_sync_cond_var_per_thd scans the logs to ensure this
+ warning is not present.
+ */
+ bool valid_wakeup=
+ (!get_master_enabled() || !is_on() || thd->is_killed() ||
+ 0 <= Active_tranx::compare(
+ m_reply_file_name, m_reply_file_pos,
+ trx_wait_binlog_name, trx_wait_binlog_pos));
+ if (!valid_wakeup)
+ {
+ sql_print_warning(
+ "Thread awaiting semi-sync ACK was awoken before its "
+ "ACK. THD (%llu), Wait coord: (%s, %llu), ACK coord: (%s, "
+ "%llu)",
+ thd->thread_id, trx_wait_binlog_name, trx_wait_binlog_pos,
+ m_reply_file_name, m_reply_file_pos);
+ }
+ });
}
}
}
@@ -997,7 +1016,8 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
m_active_tranxs may be NULL if someone disabled semi sync during
cond_timewait()
*/
- DBUG_ASSERT(thd_killed(thd) || !m_active_tranxs || aborted ||
+ DBUG_ASSERT(thd_killed(thd) || !m_active_tranxs ||
+ m_active_tranxs->is_empty() || aborted ||
!m_active_tranxs->is_tranx_end_pos(trx_wait_binlog_name,
trx_wait_binlog_pos));
@@ -1008,6 +1028,9 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
else
rpl_semi_sync_master_no_transactions++;
+ if (unmark_thd_awaiting_ack)
+ set_thd_awaiting_semisync_ack(thd, FALSE);
+
/* The lock held will be released by thd_exit_cond, so no need to
call unlock() here */
THD_EXIT_COND(thd, &old_stage);
@@ -1038,20 +1061,22 @@ void Repl_semi_sync_master::switch_off()
{
DBUG_ENTER("Repl_semi_sync_master::switch_off");
+ /* Clear the active transaction list. */
+ if (m_active_tranxs)
+ {
+ m_active_tranxs->clear_active_tranx_nodes(NULL, 0,
+ signal_waiting_transaction);
+ }
if (m_state)
{
m_state = false;
- /* Clear the active transaction list. */
- DBUG_ASSERT(m_active_tranxs != NULL);
- m_active_tranxs->clear_active_tranx_nodes(NULL, 0);
rpl_semi_sync_master_off_times++;
m_wait_file_name_inited = false;
m_reply_file_name_inited = false;
sql_print_information("Semi-sync replication switched OFF.");
}
- cond_broadcast(); /* wake up all waiting threads */
DBUG_VOID_RETURN;
}
@@ -1198,7 +1223,8 @@ int Repl_semi_sync_master::update_sync_header(THD* thd, unsigned char *packet,
DBUG_RETURN(0);
}
-int Repl_semi_sync_master::write_tranx_in_binlog(const char* log_file_name,
+int Repl_semi_sync_master::write_tranx_in_binlog(THD *thd,
+ const char *log_file_name,
my_off_t log_file_pos)
{
int result = 0;
@@ -1241,7 +1267,7 @@ int Repl_semi_sync_master::write_tranx_in_binlog(const char* log_file_name,
if (is_on())
{
DBUG_ASSERT(m_active_tranxs != NULL);
- if(m_active_tranxs->insert_tranx_node(log_file_name, log_file_pos))
+ if(m_active_tranxs->insert_tranx_node(thd, log_file_name, log_file_pos))
{
/*
if insert tranx_node failed, print a warning message
@@ -1253,6 +1279,7 @@ int Repl_semi_sync_master::write_tranx_in_binlog(const char* log_file_name,
}
else
{
+ set_thd_awaiting_semisync_ack(thd, TRUE);
rpl_semi_sync_master_request_ack++;
}
}
@@ -1370,22 +1397,40 @@ void Repl_semi_sync_master::set_export_stats()
unlock();
}
-void Repl_semi_sync_master::await_slave_reply()
+void Repl_semi_sync_master::await_all_slave_replies()
{
- struct timespec abstime;
+ int wait_result;
- DBUG_ENTER("Repl_semi_sync_master::::await_slave_reply");
- lock();
-
- /* Just return if there is nothing to wait for */
- if (!rpl_semi_sync_master_wait_sessions)
- goto end;
+ DBUG_ENTER("Repl_semi_sync_master::::await_all_slave_replies");
- create_timeout(&abstime, NULL);
- cond_timewait(&abstime);
+ /*
+ Wait for all transactions that need ACKS to have received them; or timeout.
+ If it is a timeout, the connection thread should attempt to turn off
+ semi-sync and broadcast to all other waiting threads to move on.
-end:
- unlock();
+ The lock is taken per iteration rather than over the whole loop to allow
+ more opportunity for the user threads to handle their ACKs.
+ */
+ while (TRUE)
+ {
+ lock();
+ if (m_active_tranxs->is_empty() || !get_master_enabled() || !is_on())
+ {
+ unlock();
+ break;
+ }
+ wait_result= m_active_tranxs->for_front(
+ [](THD *thd, const char *binlog_file, my_off_t binlog_pos) -> int {
+ return (thd->is_awaiting_semisync_ack)
+ ? repl_semisync_master.cond_timewait(thd, NULL)
+ : 0;
+ });
+ unlock();
+
+ // Check for timeout
+ if (wait_result != 0)
+ break;
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/semisync_master.h b/sql/semisync_master.h
index 99f46869354..1eb690b572b 100644
--- a/sql/semisync_master.h
+++ b/sql/semisync_master.h
@@ -31,6 +31,7 @@ extern PSI_cond_key key_COND_binlog_send;
struct Tranx_node {
char log_name[FN_REFLEN];
my_off_t log_pos;
+ THD *thd; /* The thread awaiting an ACK */
struct Tranx_node *next; /* the next node in the sorted list */
struct Tranx_node *hash_next; /* the next node during hash collision */
};
@@ -288,6 +289,18 @@ class Tranx_node_allocator
}
};
+/**
+ Function pointer type to run on the contents of an Active_tranx node.
+
+ Return 0 for success, 1 for error.
+
+ Note Repl_semi_sync_master::LOCK_binlog is not guaranteed to be held for
+ its invocation. See the context in which it is called to know.
+*/
+
+typedef int (*active_tranx_action)(THD *trx_thd, const char *log_file_name,
+ my_off_t trx_log_file_pos);
+
/**
This class manages memory for active transaction list.
@@ -338,29 +351,60 @@ class Active_tranx
* Return:
* 0: success; non-zero: error
*/
- int insert_tranx_node(const char *log_file_name, my_off_t log_file_pos);
+ int insert_tranx_node(THD *thd_to_wait, const char *log_file_name,
+ my_off_t log_file_pos);
/* Clear the active transaction nodes until(inclusive) the specified
* position.
* If log_file_name is NULL, everything will be cleared: the sorted
* list and the hash table will be reset to empty.
+ *
+ * The pre_delete_hook parameter is a function pointer that will be invoked
+ * for each Active_tranx node, in order, from m_trx_front to log_file_name,
+ * e.g. to signal their wakeup condition. Repl_semi_sync_binlog::LOCK_binlog
+ * is held while this is invoked.
*/
void clear_active_tranx_nodes(const char *log_file_name,
- my_off_t log_file_pos);
+ my_off_t log_file_pos,
+ active_tranx_action pre_delete_hook);
/* Given a position, check to see whether the position is an active
* transaction's ending position by probing the hash table.
*/
bool is_tranx_end_pos(const char *log_file_name, my_off_t log_file_pos);
+ /* Invoke action (function parameter) on only the first element in the list
+ * of active transactions.
+ *
+ * Note this function does not explicitly lock
+ * Repl_semi_sync_master::LOCK_binlog.
+ */
+ int for_front(active_tranx_action action);
+
/* Given two binlog positions, compare which one is bigger based on
* (file_name, file_position).
*/
static int compare(const char *log_file_name1, my_off_t log_file_pos1,
const char *log_file_name2, my_off_t log_file_pos2);
+
+ /* Check if there are no transactions actively awaiting ACKs. Returns true
+ * if the internal linked list has no entries, false otherwise.
+ */
+ bool is_empty() { return m_trx_front == NULL; }
+
};
+/*
+ Element in Repl_semi_sync_master::wait_queue to preserve the state of a
+ transaction waiting for an ACK.
+*/
+typedef struct _semisync_wait_trx {
+ const char *binlog_name;
+ my_off_t binlog_pos;
+ THD *thd;
+} semisync_wait_trx_t;
+
/**
The extension class for the master of semi-synchronous replication
*/
@@ -433,8 +477,11 @@ class Repl_semi_sync_master
void lock();
void unlock();
- void cond_broadcast();
- int cond_timewait(struct timespec *wait_time);
+
+ /* Do a cond wait on thd->LOCK_wakup_ready. If wait_time is NULL, timeout
+ * will use m_wait_timeout.
+ */
+ int cond_timewait(THD *thd, struct timespec *wait_time);
/* Is semi-sync replication on? */
bool is_on() {
@@ -482,10 +529,11 @@ class Repl_semi_sync_master
void create_timeout(struct timespec *out, struct timespec *start_arg);
/*
- Blocks the calling thread until the ack_receiver either receives an ACK
- or times out (from rpl_semi_sync_master_timeout)
+ Blocks the calling thread until the ack_receiver either receives ACKs for
+ all transactions awaiting ACKs, or times out (from
+ rpl_semi_sync_master_timeout)
*/
- void await_slave_reply();
+ void await_all_slave_replies();
/*set the ACK point, after binlog sync or after transaction commit*/
void set_wait_point(unsigned long ack_point)
@@ -544,26 +592,56 @@ class Repl_semi_sync_master
* all other transaction would not wait either.
*
* Input: (the transaction events' ending binlog position)
- * trx_wait_binlog_name - (IN) ending position's file name
- * trx_wait_binlog_pos - (IN) ending position's file offset
+ * trx_wait_binlog_name - (IN) ending position's file name
+ * trx_wait_binlog_pos - (IN) ending position's file offset
+ * unmark_thd_awaiting_ack - (IN) Whether or not to unmark
+ * thd->is_awaiting_semisync_ack after receiving
+ * an ACK from the replica. If using wait_point
+ * AFTER_SYNC with binlog_group_commit, only the
+ * last transaction written to binlog in the
+ * group should negate the boolean, because the
+ * same thread (i.e. leader thread) will wait for
+ * all transaction ACKs. Negating it too early
+ * would break SHUTDOWN WAIT FOR ALL SLAVES, as
+ * that is the condition tested to bypass killing
+ * threads in phase 1. In all other situations,
+ * the boolean should be negated immediately.
*
* Return:
* 0: success; non-zero: error
*/
int commit_trx(const char* trx_wait_binlog_name,
- my_off_t trx_wait_binlog_pos);
+ my_off_t trx_wait_binlog_pos,
+ bool unmark_thd_awaiting_ack=TRUE);
- /*Wait for ACK after writing/sync binlog to file*/
- int wait_after_sync(const char* log_file, my_off_t log_pos);
+ /* Wait for ACK after writing/sync binlog to file
+ * For details on parameters, see commit_trx() function declaration comment.
+ */
+ int wait_after_sync(const char *log_file, my_off_t log_pos,
+ bool unmark_thd_awaiting_ack= TRUE);
/*Wait for ACK after commting the transaction*/
int wait_after_commit(THD* thd, bool all);
/*Wait after the transaction is rollback*/
int wait_after_rollback(THD *thd, bool all);
- /*Store the current binlog position in m_active_tranxs. This position should
- * be acked by slave*/
- int report_binlog_update(THD *thd, const char *log_file,my_off_t log_pos);
+ /* Store the current binlog position in m_active_tranxs. This position should
+ * be acked by slave.
+ *
+ * Inputs:
+ * trans_thd Thread of the transaction which is executing the
+ * transaction.
+ * waiter_thd Thread that will wait for the ACK from the replica,
+ * which depends on the semi-sync wait point. If AFTER_SYNC,
+ * and also using binlog group commit, this will be the leader
+ * thread of the binlog commit. Otherwise, it is the thread that
+ * is executing the transaction, i.e. the same as trans_thd.
+ * log_file Name of the binlog file that the transaction is written into
+ * log_pos Offset within the binlog file that the transaction is written
+ * at
+ */
+ int report_binlog_update(THD *trans_thd, THD *waiter_thd,
+ const char *log_file, my_off_t log_pos);
int dump_start(THD* thd,
const char *log_file,
@@ -609,13 +687,19 @@ class Repl_semi_sync_master
* semi-sync is on
*
* Input: (the transaction events' ending binlog position)
+ * THD - (IN) thread that will wait for an ACK. This can be the
+ * binlog leader thread when using wait_point
+ * AFTER_SYNC with binlog group commit. In all other
+ * cases, this is the user thread executing the
+ * transaction.
* log_file_name - (IN) transaction ending position's file name
* log_file_pos - (IN) transaction ending position's file offset
*
* Return:
* 0: success; non-zero: error
*/
- int write_tranx_in_binlog(const char* log_file_name, my_off_t log_file_pos);
+ int write_tranx_in_binlog(THD *thd, const char *log_file_name,
+ my_off_t log_file_pos);
/* Read the slave's reply so that we know how much progress the slave makes
* on receive replication events.
@@ -634,9 +718,9 @@ class Repl_semi_sync_master
int before_reset_master();
/*
- Determines if the given thread is currently awaiting a semisync_ack. Note
- that the thread's value is protected by this class's LOCK_binlog, so this
- function (indirectly) provides safe access.
+ Determines if the given thread is currently awaiting (or queued to await) a
+ semisync_ack. Note that the thread's value is protected by this class's
+ LOCK_binlog, so this function (indirectly) provides safe access.
*/
my_bool is_thd_awaiting_semisync_ack(THD *thd)
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4c6005416e1..35d72d61d48 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5318,8 +5318,18 @@ class THD: public THD_count, /* this must be first */
Flag, mutex and condition for a thread to wait for a signal from another
thread.
- Currently used to wait for group commit to complete, can also be used for
- other purposes.
+ Currently used to wait for group commit to complete, and COND_wakeup_ready
+ is used for threads to wait on semi-sync ACKs (though is protected by
+ Repl_semi_sync_master::LOCK_binlog). Note the following relationships
+ between these two use-cases when using
+ rpl_semi_sync_master_wait_point=AFTER_SYNC during group commit:
+ 1) Non-leader threads use COND_wakeup_ready to wait for the leader thread
+ to complete binlog commit.
+ 2) The leader thread uses COND_wakeup_ready to await ACKs from the
+ replica before signalling the non-leader threads to wake up.
+
+ With wait_point=AFTER_COMMIT, there is no overlap as binlogging has
+ finished, so COND_wakeup_ready is safe to re-use.
*/
bool wakeup_ready;
mysql_mutex_t LOCK_wakeup_ready;
--
2.30.2
1
0
[PATCH] MDEV-24622: Replication does not support bulk insert into empty table
by Kristian Nielsen 08 Mar '24
by Kristian Nielsen 08 Mar '24
08 Mar '24
Remove work-around that disables bulk insert optimization in replication
The root cause of the original problem is now fixed (MDEV-33475). Though the
bulk insert optimization will still be disabled in replication, as it is
only enabled in special circumstances meant for loading a mysqldump.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
sql/sql_class.cc | 8 --------
storage/innobase/row/row0ins.cc | 9 +--------
2 files changed, 1 insertion(+), 16 deletions(-)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0433156ef40..f8ebc513744 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5317,14 +5317,6 @@ extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd)
return thd->get_command();
}
-#ifdef HAVE_REPLICATION /* Working around MDEV-24622 */
-/** @return whether the current thread is for applying binlog in a replica */
-extern "C" int thd_is_slave(const MYSQL_THD thd)
-{
- return thd && thd->slave_thread;
-}
-#endif /* HAVE_REPLICATION */
-
/* Returns high resolution timestamp for the start
of the current query. */
extern "C" unsigned long long thd_start_utime(const MYSQL_THD thd)
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 5d75e88227e..990c14d1a8f 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -2565,12 +2565,6 @@ row_ins_index_entry_big_rec(
return(error);
}
-#ifdef HAVE_REPLICATION /* Working around MDEV-24622 */
-extern "C" int thd_is_slave(const MYSQL_THD thd);
-#else
-# define thd_is_slave(thd) 0
-#endif
-
#if defined __aarch64__&&defined __GNUC__&&__GNUC__==4&&!defined __clang__
/* Avoid GCC 4.8.5 internal compiler error due to srw_mutex::wr_unlock().
We would only need this for row_ins_clust_index_entry_low(),
@@ -2722,8 +2716,7 @@ row_ins_clust_index_entry_low(
&& !index->table->skip_alter_undo
&& !index->table->n_rec_locks
&& !index->table->is_active_ddl()
- && !index->table->versioned()
- && !thd_is_slave(trx->mysql_thd) /* FIXME: MDEV-24622 */) {
+ && !index->table->versioned()) {
DEBUG_SYNC_C("empty_root_page_insert");
if (!index->table->is_temporary()) {
--
2.30.2
1
0
[PATCH] MDEV-33475: --gtid-ignore-duplicate can double-apply event in case of parallel replication retry
by Kristian Nielsen 08 Mar '24
by Kristian Nielsen 08 Mar '24
08 Mar '24
When rolling back and retrying a transaction in parallel replication, don't
release the domain ownership (for --gtid-ignore-duplicates) as part of the
rollback. Otherwise another master connection could grab the ownership and
double-apply the transaction in parallel with the retry.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
.../gtid_ignore_duplicates.result | 108 +++++++++++++++++-
.../multi_source/gtid_ignore_duplicates.test | 68 ++++++++++-
sql/rpl_parallel.cc | 8 +-
sql/rpl_rli.cc | 4 +-
sql/rpl_rli.h | 2 +-
5 files changed, 178 insertions(+), 12 deletions(-)
diff --git a/mysql-test/suite/multi_source/gtid_ignore_duplicates.result b/mysql-test/suite/multi_source/gtid_ignore_duplicates.result
index e142ff8b981..88b525e21ff 100644
--- a/mysql-test/suite/multi_source/gtid_ignore_duplicates.result
+++ b/mysql-test/suite/multi_source/gtid_ignore_duplicates.result
@@ -174,6 +174,105 @@ a
10
11
12
+*** MDEV-33475: --gtid-ignore-duplicate can double-apply event in case of parallel replication retry
+connection server_2;
+STOP SLAVE "c2b";
+SET default_master_connection = "c2b";
+include/wait_for_slave_to_stop.inc
+STOP SLAVE "a2b";
+SET default_master_connection = "a2b";
+include/wait_for_slave_to_stop.inc
+connection server_1;
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+BEGIN;
+INSERT INTO t2 VALUES (0, 0);
+INSERT INTO t2 VALUES (1, 0);
+INSERT INTO t2 VALUES (2, 0);
+INSERT INTO t2 VALUES (3, 0);
+INSERT INTO t2 VALUES (4, 0);
+INSERT INTO t2 VALUES (5, 0);
+INSERT INTO t2 VALUES (6, 0);
+INSERT INTO t2 VALUES (7, 0);
+INSERT INTO t2 VALUES (8, 0);
+INSERT INTO t2 VALUES (9, 0);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (0+10, 100);
+UPDATE t2 SET b=0 WHERE a<10;
+INSERT INTO t2 VALUES (0+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (1+10, 100);
+UPDATE t2 SET b=1 WHERE a<10;
+INSERT INTO t2 VALUES (1+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (2+10, 100);
+UPDATE t2 SET b=2 WHERE a<10;
+INSERT INTO t2 VALUES (2+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (3+10, 100);
+UPDATE t2 SET b=3 WHERE a<10;
+INSERT INTO t2 VALUES (3+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (4+10, 100);
+UPDATE t2 SET b=4 WHERE a<10;
+INSERT INTO t2 VALUES (4+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (5+10, 100);
+UPDATE t2 SET b=5 WHERE a<10;
+INSERT INTO t2 VALUES (5+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (6+10, 100);
+UPDATE t2 SET b=6 WHERE a<10;
+INSERT INTO t2 VALUES (6+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (7+10, 100);
+UPDATE t2 SET b=7 WHERE a<10;
+INSERT INTO t2 VALUES (7+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (8+10, 100);
+UPDATE t2 SET b=8 WHERE a<10;
+INSERT INTO t2 VALUES (8+20, 200);
+COMMIT;
+BEGIN;
+INSERT INTO t2 VALUES (9+10, 100);
+UPDATE t2 SET b=9 WHERE a<10;
+INSERT INTO t2 VALUES (9+20, 200);
+COMMIT;
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+COUNT(*) SUM(a) SUM(b)
+30 435 3090
+include/save_master_gtid.inc
+connection server_2;
+SET @old_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode=aggressive;
+SET default_master_connection = "a2b";
+START SLAVE;
+include/wait_for_slave_to_start.inc
+SET default_master_connection = "c2b";
+START SLAVE;
+include/wait_for_slave_to_start.inc
+include/sync_with_master_gtid.inc
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+COUNT(*) SUM(a) SUM(b)
+30 435 3090
+connection server_3;
+include/sync_with_master_gtid.inc
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+COUNT(*) SUM(a) SUM(b)
+30 435 3090
+connection server_4;
+include/sync_with_master_gtid.inc
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+COUNT(*) SUM(a) SUM(b)
+30 435 3090
*** Test also with not using parallel replication.
connection server_1;
SET default_master_connection = "b2a";
@@ -474,6 +573,7 @@ Warnings:
Note 1938 SLAVE 'a2b' stopped
Note 1938 SLAVE 'c2b' stopped
SET GLOBAL slave_parallel_threads= @old_parallel;
+SET GLOBAL slave_parallel_mode= @old_mode;
SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
connection server_3;
SET GLOBAL gtid_domain_id=0;
@@ -491,22 +591,22 @@ Note 1938 SLAVE 'a2d' stopped
SET GLOBAL slave_parallel_threads= @old_parallel;
SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
connection server_1;
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
include/reset_master_slave.inc
disconnect server_1;
connection server_2;
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
include/reset_master_slave.inc
disconnect server_2;
connection server_3;
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
include/reset_master_slave.inc
disconnect server_3;
connection server_4;
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
include/reset_master_slave.inc
disconnect server_4;
diff --git a/mysql-test/suite/multi_source/gtid_ignore_duplicates.test b/mysql-test/suite/multi_source/gtid_ignore_duplicates.test
index 3d2d151bd0d..cbc06920b41 100644
--- a/mysql-test/suite/multi_source/gtid_ignore_duplicates.test
+++ b/mysql-test/suite/multi_source/gtid_ignore_duplicates.test
@@ -173,6 +173,65 @@ SET default_master_connection = "a2b";
SELECT * FROM t1 WHERE a >= 10 ORDER BY a;
+--echo *** MDEV-33475: --gtid-ignore-duplicate can double-apply event in case of parallel replication retry
+
+# Create a bunch of transactions that will cause conflicts and retries.
+# The bug was that the retry code was not handling the --gtid-ignore-duplicates
+# option, so events could be doubly-applied.
+
+--connection server_2
+STOP SLAVE "c2b";
+SET default_master_connection = "c2b";
+--source include/wait_for_slave_to_stop.inc
+STOP SLAVE "a2b";
+SET default_master_connection = "a2b";
+--source include/wait_for_slave_to_stop.inc
+
+--connection server_1
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+BEGIN;
+--let $i= 0
+while ($i < 10) {
+ eval INSERT INTO t2 VALUES ($i, 0);
+ inc $i;
+}
+COMMIT;
+
+--let $i= 0
+while ($i < 10) {
+ BEGIN;
+ eval INSERT INTO t2 VALUES ($i+10, 100);
+ eval UPDATE t2 SET b=$i WHERE a<10;
+ eval INSERT INTO t2 VALUES ($i+20, 200);
+ COMMIT;
+ inc $i;
+}
+
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+--source include/save_master_gtid.inc
+
+--connection server_2
+SET @old_mode= @@GLOBAL.slave_parallel_mode;
+SET GLOBAL slave_parallel_mode=aggressive;
+SET default_master_connection = "a2b";
+START SLAVE;
+--source include/wait_for_slave_to_start.inc
+SET default_master_connection = "c2b";
+START SLAVE;
+--source include/wait_for_slave_to_start.inc
+
+--source include/sync_with_master_gtid.inc
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+
+--connection server_3
+--source include/sync_with_master_gtid.inc
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+
+--connection server_4
+--source include/sync_with_master_gtid.inc
+SELECT COUNT(*), SUM(a), SUM(b) FROM t2;
+
+
--echo *** Test also with not using parallel replication.
--connection server_1
@@ -414,6 +473,7 @@ SET GLOBAL gtid_domain_id=0;
--sorted_result
STOP ALL SLAVES;
SET GLOBAL slave_parallel_threads= @old_parallel;
+SET GLOBAL slave_parallel_mode= @old_mode;
SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
--connection server_3
@@ -431,25 +491,25 @@ SET GLOBAL slave_parallel_threads= @old_parallel;
SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates;
--connection server_1
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
--source include/reset_master_slave.inc
--disconnect server_1
--connection server_2
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
--source include/reset_master_slave.inc
--disconnect server_2
--connection server_3
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
--source include/reset_master_slave.inc
--disconnect server_3
--connection server_4
-DROP TABLE t1;
+DROP TABLE t1, t2;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
--source include/reset_master_slave.inc
--disconnect server_4
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index ac96d92eb5d..1c7f4dd1f93 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -868,7 +868,13 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt,
});
#endif
- rgi->cleanup_context(thd, 1);
+ /*
+ We are still applying the event group, even though we will roll it back
+ and retry it. So for --gtid-ignore-duplicates, keep ownership of the
+ domain during the retry so another master connection will not try to take
+ over and duplicate apply the same event group (MDEV-33475).
+ */
+ rgi->cleanup_context(thd, 1, 1 /* keep_domain_owner */);
wait_for_pending_deadlock_kill(thd, rgi);
thd->reset_killed();
thd->clear_error();
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 95566b2f6c7..1af38be1787 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -2248,7 +2248,7 @@ delete_or_keep_event_post_apply(rpl_group_info *rgi,
}
-void rpl_group_info::cleanup_context(THD *thd, bool error)
+void rpl_group_info::cleanup_context(THD *thd, bool error, bool keep_domain_owner)
{
DBUG_ENTER("rpl_group_info::cleanup_context");
DBUG_PRINT("enter", ("error: %d", (int) error));
@@ -2298,7 +2298,7 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
Ensure we always release the domain for others to process, when using
--gtid-ignore-duplicates.
*/
- if (gtid_ignore_duplicate_state != GTID_DUPLICATE_NULL)
+ if (gtid_ignore_duplicate_state != GTID_DUPLICATE_NULL && !keep_domain_owner)
rpl_global_gtid_slave_state->release_domain_owner(this);
}
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 9fc1a384355..91628bee3c7 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -917,7 +917,7 @@ struct rpl_group_info
}
void clear_tables_to_lock();
- void cleanup_context(THD *, bool);
+ void cleanup_context(THD *, bool, bool keep_domain_owner= false);
void slave_close_thread_tables(THD *);
void mark_start_commit_no_lock();
void mark_start_commit();
--
2.30.2
1
0
08 Mar '24
Remove incorrect deprecation.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
.../suite/binlog_encryption/rpl_gtid_basic.result | 6 ------
.../suite/engines/funcs/r/rpl_change_master.result | 2 --
.../galera/r/galera_query_cache_invalidate.result | 2 --
mysql-test/suite/rpl/r/rpl_change_master.result | 5 -----
mysql-test/suite/rpl/r/rpl_gtid_basic.result | 6 ------
mysql-test/suite/rpl/r/rpl_gtid_errorhandling.result | 2 --
mysql-test/suite/rpl/r/rpl_gtid_mdev4820.result | 4 ----
.../suite/rpl/r/rpl_perfschema_connect_config.result | 2 --
mysql-test/suite/rpl/r/rpl_start_alter_options.result | 10 ----------
mysql-test/suite/rpl/r/rpl_using_gtid_default.result | 2 --
mysql-test/suite/rpl/t/rpl_change_master.test | 5 -----
sql/sql_repl.cc | 6 ------
12 files changed, 52 deletions(-)
diff --git a/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result b/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result
index 07ef909d8a6..0e066fc0418 100644
--- a/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result
+++ b/mysql-test/suite/binlog_encryption/rpl_gtid_basic.result
@@ -69,8 +69,6 @@ INSERT INTO t2 VALUES (5, "i1a");
connection server_4;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT,
MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
SELECT * FROM t1 ORDER BY a;
a b
@@ -91,8 +89,6 @@ connection server_2;
include/stop_slave.inc
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
connection server_4;
UPDATE t2 SET b="j1a" WHERE a=5;
@@ -121,8 +117,6 @@ include/save_master_gtid.inc
connection server_3;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
include/sync_with_master_gtid.inc
SELECT * FROM t2 ORDER BY a;
diff --git a/mysql-test/suite/engines/funcs/r/rpl_change_master.result b/mysql-test/suite/engines/funcs/r/rpl_change_master.result
index 88801b07bba..0713d8ef15b 100644
--- a/mysql-test/suite/engines/funcs/r/rpl_change_master.result
+++ b/mysql-test/suite/engines/funcs/r/rpl_change_master.result
@@ -28,7 +28,5 @@ MASTER_SSL_KEY='', MASTER_SSL_CRL='', MASTER_SSL_CRLPATH='';
CHANGE MASTER TO MASTER_USER='root', MASTER_PASSWORD='', MASTER_SSL=0;
"Usage of CURRENT_POS in CHANGE MASTER MASTER_USE_GTID is dreprecated.
CHANGE MASTER TO MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS;
include/rpl_end.inc
diff --git a/mysql-test/suite/galera/r/galera_query_cache_invalidate.result b/mysql-test/suite/galera/r/galera_query_cache_invalidate.result
index 4a6b61e4d80..fc23c0f1caf 100644
--- a/mysql-test/suite/galera/r/galera_query_cache_invalidate.result
+++ b/mysql-test/suite/galera/r/galera_query_cache_invalidate.result
@@ -8,8 +8,6 @@ connection node_4;
call mtr.add_suppression("WSREP: Ignoring server id for non bootstrap node.");
connection node_3;
CHANGE MASTER TO master_host='127.0.0.1', master_user='root', master_port=NODE_MYPORT_1, master_use_gtid=current_pos;;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
START SLAVE;
include/wait_for_slave_to_start.inc
connection node_1;
diff --git a/mysql-test/suite/rpl/r/rpl_change_master.result b/mysql-test/suite/rpl/r/rpl_change_master.result
index 88801b07bba..48cec72d917 100644
--- a/mysql-test/suite/rpl/r/rpl_change_master.result
+++ b/mysql-test/suite/rpl/r/rpl_change_master.result
@@ -26,9 +26,4 @@ connection master;
CHANGE MASTER TO MASTER_USER='root', MASTER_SSL=0, MASTER_SSL_CA='', MASTER_SSL_CERT='',
MASTER_SSL_KEY='', MASTER_SSL_CRL='', MASTER_SSL_CRLPATH='';
CHANGE MASTER TO MASTER_USER='root', MASTER_PASSWORD='', MASTER_SSL=0;
-"Usage of CURRENT_POS in CHANGE MASTER MASTER_USE_GTID is dreprecated.
-CHANGE MASTER TO MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
-CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS;
include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_gtid_basic.result b/mysql-test/suite/rpl/r/rpl_gtid_basic.result
index fc7505e144f..32df09789cc 100644
--- a/mysql-test/suite/rpl/r/rpl_gtid_basic.result
+++ b/mysql-test/suite/rpl/r/rpl_gtid_basic.result
@@ -69,8 +69,6 @@ INSERT INTO t2 VALUES (5, "i1a");
connection server_4;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT,
MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
SELECT * FROM t1 ORDER BY a;
a b
@@ -91,8 +89,6 @@ connection server_2;
include/stop_slave.inc
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
connection server_4;
UPDATE t2 SET b="j1a" WHERE a=5;
@@ -121,8 +117,6 @@ include/save_master_gtid.inc
connection server_3;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_4,
MASTER_USE_GTID=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
include/sync_with_master_gtid.inc
SELECT * FROM t2 ORDER BY a;
diff --git a/mysql-test/suite/rpl/r/rpl_gtid_errorhandling.result b/mysql-test/suite/rpl/r/rpl_gtid_errorhandling.result
index a7cb710cc07..4c35d42d90a 100644
--- a/mysql-test/suite/rpl/r/rpl_gtid_errorhandling.result
+++ b/mysql-test/suite/rpl/r/rpl_gtid_errorhandling.result
@@ -75,8 +75,6 @@ INSERT INTO t1 VALUES (2);
SET sql_log_bin = 1;
INSERT INTO t1 VALUES (3);
CHANGE MASTER TO master_use_gtid=current_pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
BEGIN;
SET GLOBAL gtid_slave_pos = "100-100-100";
ERROR 25000: You are not allowed to execute this command in a transaction
diff --git a/mysql-test/suite/rpl/r/rpl_gtid_mdev4820.result b/mysql-test/suite/rpl/r/rpl_gtid_mdev4820.result
index cea5aaaeacd..665fc536df6 100644
--- a/mysql-test/suite/rpl/r/rpl_gtid_mdev4820.result
+++ b/mysql-test/suite/rpl/r/rpl_gtid_mdev4820.result
@@ -45,8 +45,6 @@ SET GLOBAL gtid_slave_pos= '0-2-10';
connection server_1;
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_2,
master_user= 'root', master_use_gtid=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
START SLAVE;
connection server_2;
INSERT INTO t1 VALUES (11);
@@ -76,8 +74,6 @@ connection server_2;
INSERT INTO t1 VALUES (22);
CHANGE MASTER TO master_host = '127.0.0.1', master_port = SERVER_MYPORT_1,
master_user= 'root', master_use_gtid=CURRENT_POS;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
START SLAVE;
SET sql_log_bin= 0;
CALL mtr.add_suppression("which is not in the master's binlog. Since the master's binlog contains GTIDs with higher sequence numbers, it probably means that the slave has diverged");
diff --git a/mysql-test/suite/rpl/r/rpl_perfschema_connect_config.result b/mysql-test/suite/rpl/r/rpl_perfschema_connect_config.result
index 27cb29d3968..4ace84ffac4 100644
--- a/mysql-test/suite/rpl/r/rpl_perfschema_connect_config.result
+++ b/mysql-test/suite/rpl/r/rpl_perfschema_connect_config.result
@@ -87,8 +87,6 @@ include/assert.inc [Value returned by SSS and PS table for Using_Gtid should be
change master to
master_user = 'root',
master_use_gtid= CURRENT_POS;
-Warnings:
-Warning #### 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/assert.inc [Value returned by SSS and PS table for Using_Gtid should be same.]
# 3) Test for Auto_position= SLAVE_POS
diff --git a/mysql-test/suite/rpl/r/rpl_start_alter_options.result b/mysql-test/suite/rpl/r/rpl_start_alter_options.result
index 4c6135aaf5e..30854b12be1 100644
--- a/mysql-test/suite/rpl/r/rpl_start_alter_options.result
+++ b/mysql-test/suite/rpl/r/rpl_start_alter_options.result
@@ -3,8 +3,6 @@ include/master-slave.inc
connection slave;
stop slave;
change master to master_use_gtid= current_pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
SET GLOBAL slave_parallel_threads=4;
set global slave_parallel_mode=optimistic;
set global gtid_strict_mode=1;
@@ -96,8 +94,6 @@ include/start_slave.inc
connection slave;
stop slave;
change master to master_use_gtid= current_pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
SET GLOBAL slave_parallel_threads=4;
set global slave_parallel_mode=optimistic;
set global gtid_strict_mode=1;
@@ -189,8 +185,6 @@ include/start_slave.inc
connection slave;
stop slave;
change master to master_use_gtid= current_pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
SET GLOBAL slave_parallel_threads=4;
set global slave_parallel_mode=optimistic;
set global gtid_strict_mode=1;
@@ -321,8 +315,6 @@ include/start_slave.inc
connection slave;
stop slave;
change master to master_use_gtid= current_pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
SET GLOBAL slave_parallel_threads=4;
set global slave_parallel_mode=optimistic;
set global gtid_strict_mode=1;
@@ -414,8 +406,6 @@ include/start_slave.inc
connection slave;
stop slave;
change master to master_use_gtid= current_pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
SET GLOBAL slave_parallel_threads=4;
set global slave_parallel_mode=optimistic;
set global gtid_strict_mode=1;
diff --git a/mysql-test/suite/rpl/r/rpl_using_gtid_default.result b/mysql-test/suite/rpl/r/rpl_using_gtid_default.result
index e077bcd91a4..c0e9b3add00 100644
--- a/mysql-test/suite/rpl/r/rpl_using_gtid_default.result
+++ b/mysql-test/suite/rpl/r/rpl_using_gtid_default.result
@@ -58,8 +58,6 @@ include/start_slave.inc
# to its default of Slave_Pos after RESET SLAVE.
include/stop_slave.inc
CHANGE MASTER TO MASTER_USE_GTID=Current_Pos;
-Warnings:
-Warning 1681 'master_use_gtid=current_pos' is deprecated and will be removed in a future release. Please use master_demote_to_slave=1 instead
include/start_slave.inc
include/stop_slave.inc
RESET SLAVE;
diff --git a/mysql-test/suite/rpl/t/rpl_change_master.test b/mysql-test/suite/rpl/t/rpl_change_master.test
index 2758f9d6e27..992e23906e5 100644
--- a/mysql-test/suite/rpl/t/rpl_change_master.test
+++ b/mysql-test/suite/rpl/t/rpl_change_master.test
@@ -109,9 +109,4 @@ CHANGE MASTER TO MASTER_USER='root', MASTER_SSL=0, MASTER_SSL_CA='', MASTER_SSL_
CHANGE MASTER TO MASTER_USER='root', MASTER_PASSWORD='', MASTER_SSL=0;
-# MDEV-20122: Deprecate MASTER_USE_GTID=Current_Pos to favor new MASTER_DEMOTE_TO_SLAVE option
---echo "Usage of CURRENT_POS in CHANGE MASTER MASTER_USE_GTID is dreprecated.
-CHANGE MASTER TO MASTER_USE_GTID=CURRENT_POS;
-CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS;
-
--source include/rpl_end.inc
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index dc27ab9ff8b..c9fb3c6fd1d 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3826,13 +3826,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_SLAVE_POS)
mi->using_gtid= Master_info::USE_GTID_SLAVE_POS;
else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_CURRENT_POS)
- {
mi->using_gtid= Master_info::USE_GTID_CURRENT_POS;
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT,
- ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
- "master_use_gtid=current_pos", "master_demote_to_slave=1");
- }
else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_NO ||
lex_mi->log_file_name || lex_mi->pos ||
lex_mi->relay_log_name || lex_mi->relay_log_pos)
--
2.30.2
1
0
08 Mar '24
The patch for MDEV-15530 incorrectly added a column in the middle of SHOW
SLAVE STATUS output. This is wrong, as it breaks backwards compatibility
with existing applications and scripts. In this case, it even broke
mariadb-dump, which is included in the server source tree!
Revert the incorrect change, putting the new Replicate_Rewrite_DB at the end
of SHOW SLAVE STATUS output.
Add a testcase for the mariadb-dump --dump-slave wrong output problem. Also
add a testcase rpl.rpl_show_slave_status to hopefully prevent any future
incorrect additions to SHOW SLAVE STATUS.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
mysql-test/include/check-testcase.test | 12 ++-
mysql-test/include/search_pattern_in_file.inc | 5 ++
mysql-test/main/rpl_mysqldump_slave.result | 4 +
mysql-test/main/rpl_mysqldump_slave.test | 16 ++++
.../suite/multi_source/info_logs.result | 12 +--
.../multi_source_slave_alias_replica.result | 4 +-
.../suite/multi_source/reset_slave.result | 8 +-
mysql-test/suite/multi_source/simple.result | 14 ++--
mysql-test/suite/multi_source/syntax.result | 6 +-
.../suite/rpl/r/rpl_show_slave_status.result | 75 +++++++++++++++++++
.../suite/rpl/t/rpl_show_slave_status.test | 27 +++++++
sql/slave.cc | 20 ++++-
12 files changed, 175 insertions(+), 28 deletions(-)
create mode 100644 mysql-test/suite/rpl/r/rpl_show_slave_status.result
create mode 100644 mysql-test/suite/rpl/t/rpl_show_slave_status.test
diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test
index 078f6572bed..b43dffbfa06 100644
--- a/mysql-test/include/check-testcase.test
+++ b/mysql-test/include/check-testcase.test
@@ -32,7 +32,6 @@ if ($tmp)
--echo Relay_Master_Log_File #
--echo Slave_IO_Running No
--echo Slave_SQL_Running No
- --echo Replicate_Rewrite_DB #
--echo Replicate_Do_DB #
--echo Replicate_Ignore_DB #
--echo Replicate_Do_Table #
@@ -74,13 +73,22 @@ if ($tmp)
--echo Slave_DDL_Groups #
--echo Slave_Non_Transactional_Groups #
--echo Slave_Transactional_Groups #
+ --echo Replicate_Rewrite_DB #
}
if (!$tmp) {
# Note: after WL#5177, fields 13-18 shall not be filtered-out.
- --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 19 # 23 # 24 # 25 # 26 # 27 # 41 # 42 # 43 # 45 # 52 # 53 # 54 #
+ --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 22 # 23 # 24 # 25 # 26 # 40 # 41 # 42 # 44 # 51 # 52 # 53 # 54 #
query_vertical
SHOW SLAVE STATUS;
}
+#
+# Note, we must never, _ever_, add extra rows to this output of SHOW SLAVE
+# STATUS, except at the very end, as this breaks backwards compatibility
+# with applications or scripts that parse the output. This also means that
+# we cannot add _any_ new rows in a GA version if a different row was
+# already added in a later MariaDB version, as this would make it impossible
+# to merge the change up while preserving the order of rows.
+#
#
# Ensure that we don't get warnings from mysql.proc (used by check_mysqld)
diff --git a/mysql-test/include/search_pattern_in_file.inc b/mysql-test/include/search_pattern_in_file.inc
index 3105f7f9077..aef4f68a91d 100644
--- a/mysql-test/include/search_pattern_in_file.inc
+++ b/mysql-test/include/search_pattern_in_file.inc
@@ -25,6 +25,7 @@
# Supported formats:
# - (default) : "FOUND n /pattern/ in FILE " or "NOT FOUND ..."
# - "matches" : Each match is printed, on a separate line
+# - "count" : "FOUND n matches in FILE" or "NOT FOUND ..." (omit pattern)
#
# In case of
# - SEARCH_FILE and/or SEARCH_PATTERN is not set
@@ -113,6 +114,10 @@ perl;
print $_ . "\n";
}
}
+ elsif ($ENV{SEARCH_OUTPUT} eq "count")
+ {
+ print "$res matches in $ENV{SEARCH_FILE}\n";
+ }
else
{
print "$res /$search_pattern/ in $ENV{SEARCH_FILE}\n";
diff --git a/mysql-test/main/rpl_mysqldump_slave.result b/mysql-test/main/rpl_mysqldump_slave.result
index 0d0378abd5b..190e3c26e80 100644
--- a/mysql-test/main/rpl_mysqldump_slave.result
+++ b/mysql-test/main/rpl_mysqldump_slave.result
@@ -219,4 +219,8 @@ connection master;
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=BINLOG_START;
connection slave;
include/start_slave.inc
+connection master;
+connection slave;
+connection master;
+FOUND 1 matches in MDEV-33212.sql
include/rpl_end.inc
diff --git a/mysql-test/main/rpl_mysqldump_slave.test b/mysql-test/main/rpl_mysqldump_slave.test
index 9dbee604520..75bb85dbe4b 100644
--- a/mysql-test/main/rpl_mysqldump_slave.test
+++ b/mysql-test/main/rpl_mysqldump_slave.test
@@ -198,4 +198,20 @@ if ($postdump_first_binary_log_filename != $postdump_binlog_filename)
connection slave;
--source include/start_slave.inc
+# MDEV-33212: mysqldump uses MASTER_LOG_POS with dump-slave
+# The bug was that the MASTER_LOG_POS was wrong. So check that it is correct.
+--connection master
+--let $pos= query_get_value(SHOW MASTER STATUS, Position, 1)
+--sync_slave_with_master
+--connection master
+--exec $MYSQL_DUMP_SLAVE --compact --dump-slave test >$MYSQLTEST_VARDIR/tmp/MDEV-33212.sql
+--let SEARCH_RANGE=500000000
+--let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/MDEV-33212.sql
+--let SEARCH_PATTERN= MASTER_LOG_POS=$pos
+--let SEARCH_OUTPUT=count
+--source include/search_pattern_in_file.inc
+
+--remove_file $MYSQLTEST_VARDIR/tmp/MDEV-33212.sql
+
+
--source include/rpl_end.inc
diff --git a/mysql-test/suite/multi_source/info_logs.result b/mysql-test/suite/multi_source/info_logs.result
index a35a20bdbf7..6f3fd7e7e68 100644
--- a/mysql-test/suite/multi_source/info_logs.result
+++ b/mysql-test/suite/multi_source/info_logs.result
@@ -94,17 +94,17 @@ MASTER 2.2
# EOF
#
show all slaves status;
-Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
- Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 7 0 60.000
-MASTER 2.2 Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 7 0 60.000
+Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
+ Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 7 0 60.000
+MASTER 2.2 Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000002 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 7 0 60.000
include/wait_for_slave_to_start.inc
set default_master_connection = 'MASTER 2.2';
include/wait_for_slave_to_start.inc
set default_master_connection = '';
show all slaves status;
-Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
- Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 6 0 60.000
-MASTER 2.2 Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 6 0 60.000
+Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
+ Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> relay.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space1> None 0 No 0 No 0 0 1 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 6 0 60.000
+MASTER 2.2 Slave has read all relay log; waiting for more updates Waiting for master to send event 127.0.0.1 root MYPORT_2 60 master-bin.000001 <read_master_log_pos> relay-master@00202@002e2.000004 <relay_log_pos> master-bin.000001 Yes Yes 0 0 <read_master_log_pos> <relay_log_space2> None 0 No 0 No 0 0 2 No optimistic 0 NULL Slave has read all relay log; waiting for more updates 0 0 0 0 1073741824 6 0 60.000
#
# List of files matching '*info*' pattern
# after slave server restart
diff --git a/mysql-test/suite/multi_source/multi_source_slave_alias_replica.result b/mysql-test/suite/multi_source/multi_source_slave_alias_replica.result
index 355919def5a..ce6efc26b84 100644
--- a/mysql-test/suite/multi_source/multi_source_slave_alias_replica.result
+++ b/mysql-test/suite/multi_source/multi_source_slave_alias_replica.result
@@ -34,7 +34,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -76,6 +75,7 @@ Slave_SQL_Running_State Slave has read all relay log; waiting for more updates
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
@@ -96,7 +96,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -138,6 +137,7 @@ Slave_SQL_Running_State Slave has read all relay log; waiting for more updates
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
diff --git a/mysql-test/suite/multi_source/reset_slave.result b/mysql-test/suite/multi_source/reset_slave.result
index 2e9ce5e896f..6ff1f5a9d23 100644
--- a/mysql-test/suite/multi_source/reset_slave.result
+++ b/mysql-test/suite/multi_source/reset_slave.result
@@ -13,15 +13,15 @@ insert into t1 values (1),(2);
connection slave;
stop slave 'master1';
show slave 'master1' status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups
- 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-master1.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space> None 0 No NULL No 0 0 1 Slave_Pos 0-1-3 optimistic 0 NULL 2 1 0
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB
+ 127.0.0.1 root MYPORT_1 60 master-bin.000001 <read_master_log_pos> mysqld-relay-bin-master1.000002 <relay_log_pos> master-bin.000001 No No 0 0 <read_master_log_pos> <relay_log_space> None 0 No NULL No 0 0 1 Slave_Pos 0-1-3 optimistic 0 NULL 2 1 0
mysqld-relay-bin-master1.000001
mysqld-relay-bin-master1.000002
mysqld-relay-bin-master1.index
reset slave 'master1';
show slave 'master1' status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups
- 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space> None 0 No NULL No 0 0 1 Slave_Pos optimistic 0 NULL 2 1 0
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB
+ 127.0.0.1 root MYPORT_1 60 4 <relay_log_pos> No No 0 0 0 <relay_log_space> None 0 No NULL No 0 0 1 Slave_Pos optimistic 0 NULL 2 1 0
reset slave 'master1' all;
show slave 'master1' status;
ERROR HY000: There is no master connection 'master1'
diff --git a/mysql-test/suite/multi_source/simple.result b/mysql-test/suite/multi_source/simple.result
index 65c25b88e44..61932184b66 100644
--- a/mysql-test/suite/multi_source/simple.result
+++ b/mysql-test/suite/multi_source/simple.result
@@ -32,7 +32,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -74,6 +73,7 @@ Slave_SQL_Running_State Slave has read all relay log; waiting for more updates
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
@@ -94,7 +94,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -136,6 +135,7 @@ Slave_SQL_Running_State Slave has read all relay log; waiting for more updates
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
@@ -221,7 +221,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running No
Slave_SQL_Running No
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -263,6 +262,7 @@ Slave_SQL_Running_State
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
reset slave 'slave1';
show all slaves status;
Connection_name slave1
@@ -279,7 +279,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File
Slave_IO_Running No
Slave_SQL_Running No
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -321,6 +320,7 @@ Slave_SQL_Running_State
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
@@ -341,7 +341,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -383,6 +382,7 @@ Slave_SQL_Running_State Slave has read all relay log; waiting for more updates
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
@@ -405,7 +405,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -447,6 +446,7 @@ Slave_SQL_Running_State Slave has read all relay log; waiting for more updates
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
@@ -471,7 +471,6 @@ Relay_Log_Pos <relay_log_pos>
Relay_Master_Log_File master-bin.000001
Slave_IO_Running No
Slave_SQL_Running No
-Replicate_Rewrite_DB
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
@@ -513,6 +512,7 @@ Slave_SQL_Running_State
Slave_DDL_Groups 0
Slave_Non_Transactional_Groups 0
Slave_Transactional_Groups 0
+Replicate_Rewrite_DB
Retried_transactions 0
Max_relay_log_size 1073741824
Executed_log_entries 7
diff --git a/mysql-test/suite/multi_source/syntax.result b/mysql-test/suite/multi_source/syntax.result
index 3c7c91c35c8..6b214fe3644 100644
--- a/mysql-test/suite/multi_source/syntax.result
+++ b/mysql-test/suite/multi_source/syntax.result
@@ -1,11 +1,11 @@
include/master-slave.inc
[connection master]
show slave status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB
show slave '' status;
-Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB
show all slaves status;
-Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Rewrite_DB Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
+Connection_name Slave_SQL_State Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_SSL_Crl Master_SSL_Crlpath Using_Gtid Gtid_IO_Pos Replicate_Do_Domain_Ids Replicate_Ignore_Domain_Ids Parallel_Mode SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Slave_DDL_Groups Slave_Non_Transactional_Groups Slave_Transactional_Groups Replicate_Rewrite_DB Retried_transactions Max_relay_log_size Executed_log_entries Slave_received_heartbeats Slave_heartbeat_period Gtid_Slave_Pos
#
# Check error handling
#
diff --git a/mysql-test/suite/rpl/r/rpl_show_slave_status.result b/mysql-test/suite/rpl/r/rpl_show_slave_status.result
new file mode 100644
index 00000000000..e32b2f554ce
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_show_slave_status.result
@@ -0,0 +1,75 @@
+include/master-slave.inc
+[connection master]
+*
+* The purpose of this test is to prevent incorrect additions to SHOW
+* SLAVE STATUS, which has happened several times in the past.
+*
+* We must never, _ever_, add extra rows to this output of SHOW SLAVE
+* STATUS, except at the very end, as this breaks backwards compatibility
+* with applications or scripts that parse the output. This also means that
+* we cannot add _any_ new rows in a GA version if a different row was
+* already added in a later MariaDB version, as this would make it impossible
+* to merge the change up while preserving the order of rows.
+*
+connection slave;
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host #
+Master_User #
+Master_Port #
+Connect_Retry #
+Master_Log_File #
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File #
+Slave_IO_Running #
+Slave_SQL_Running #
+Replicate_Do_DB #
+Replicate_Ignore_DB #
+Replicate_Do_Table #
+Replicate_Ignore_Table #
+Replicate_Wild_Do_Table #
+Replicate_Wild_Ignore_Table #
+Last_Errno #
+Last_Error #
+Skip_Counter #
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition #
+Until_Log_File #
+Until_Log_Pos #
+Master_SSL_Allowed #
+Master_SSL_CA_File #
+Master_SSL_CA_Path #
+Master_SSL_Cert #
+Master_SSL_Cipher #
+Master_SSL_Key #
+Seconds_Behind_Master #
+Master_SSL_Verify_Server_Cert #
+Last_IO_Errno #
+Last_IO_Error #
+Last_SQL_Errno #
+Last_SQL_Error #
+Replicate_Ignore_Server_Ids #
+Master_Server_Id #
+Master_SSL_Crl #
+Master_SSL_Crlpath #
+Using_Gtid #
+Gtid_IO_Pos #
+Replicate_Do_Domain_Ids #
+Replicate_Ignore_Domain_Ids #
+Parallel_Mode #
+SQL_Delay #
+SQL_Remaining_Delay #
+Slave_SQL_Running_State #
+Slave_DDL_Groups #
+Slave_Non_Transactional_Groups #
+Slave_Transactional_Groups #
+Replicate_Rewrite_DB #
+*
+* When modifying this test after adding a column to SHOW SLAVE STATUS,
+* _only_ additions at the end are allowed, the column number of existing
+* columns must _not_ change!
+*
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_show_slave_status.test b/mysql-test/suite/rpl/t/rpl_show_slave_status.test
new file mode 100644
index 00000000000..f4bbb5faeab
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_show_slave_status.test
@@ -0,0 +1,27 @@
+--source include/have_binlog_format_mixed.inc
+--source include/master-slave.inc
+
+--echo *
+--echo * The purpose of this test is to prevent incorrect additions to SHOW
+--echo * SLAVE STATUS, which has happened several times in the past.
+--echo *
+--echo * We must never, _ever_, add extra rows to this output of SHOW SLAVE
+--echo * STATUS, except at the very end, as this breaks backwards compatibility
+--echo * with applications or scripts that parse the output. This also means that
+--echo * we cannot add _any_ new rows in a GA version if a different row was
+--echo * already added in a later MariaDB version, as this would make it impossible
+--echo * to merge the change up while preserving the order of rows.
+--echo *
+
+--connection slave
+--replace_column 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # 19 # 20 # 21 # 22 # 23 # 24 # 25 # 26 # 27 # 28 # 29 # 30 # 31 # 32 # 33 # 34 # 35 # 36 # 37 # 38 # 39 # 40 # 41 # 42 # 43 # 44 # 45 # 46 # 47 # 48 # 49 # 50 # 51 # 52 # 53 # 54 #
+query_vertical
+SHOW SLAVE STATUS;
+
+--echo *
+--echo * When modifying this test after adding a column to SHOW SLAVE STATUS,
+--echo * _only_ additions at the end are allowed, the column number of existing
+--echo * columns must _not_ change!
+--echo *
+
+--source include/rpl_end.inc
diff --git a/sql/slave.cc b/sql/slave.cc
index 27721e1b87e..1e928d7b993 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2957,9 +2957,6 @@ void show_master_info_get_fields(THD *thd, List<Item> *field_list,
field_list->push_back(new (mem_root)
Item_empty_string(thd, "Slave_SQL_Running", 3),
mem_root);
- field_list->push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Rewrite_DB", 23),
- mem_root);
field_list->push_back(new (mem_root)
Item_empty_string(thd, "Replicate_Do_DB", 20),
mem_root);
@@ -3108,6 +3105,21 @@ void show_master_info_get_fields(THD *thd, List<Item> *field_list,
Item_return_int(thd, "Slave_Transactional_Groups", 20,
MYSQL_TYPE_LONGLONG),
mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Rewrite_DB", 23),
+ mem_root);
+
+ /*
+ Note, we must never, _ever_, add extra rows to this output of SHOW SLAVE
+ STATUS, except here at the end before the extra rows of SHOW ALL SLAVES
+ STATUS. Otherwise, we break backwards compatibility with applications or
+ scripts that parse the output!
+
+ This also means that we cannot add _any_ new rows in a GA version if a
+ different row was already added in a later MariaDB version, as this would
+ make it impossible to merge the change up while preserving the order of
+ rows.
+ */
if (full)
{
@@ -3223,7 +3235,6 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
&my_charset_bin);
protocol->store(&slave_running[mi->slave_running], &my_charset_bin);
protocol->store(mi->rli.slave_running ? &msg_yes : &msg_no, &my_charset_bin);
- protocol->store(rpl_filter->get_rewrite_db());
protocol->store(rpl_filter->get_do_db());
protocol->store(rpl_filter->get_ignore_db());
@@ -3383,6 +3394,7 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
protocol->store(mi->total_ddl_groups);
protocol->store(mi->total_non_trans_groups);
protocol->store(mi->total_trans_groups);
+ protocol->store(rpl_filter->get_rewrite_db());
if (full)
{
--
2.30.2
1
0
[PATCH] MDEV-33303: slave_parallel_mode=optimistic should not report the mode's specific temporary errors
by Kristian Nielsen 08 Mar '24
by Kristian Nielsen 08 Mar '24
08 Mar '24
An earlier patch for MDEV-13577 fixed the most common instances of this, but
missed one case for tables without primary key when the scan reaches the end
of the table. This patch adds similar code to handle this case, converting
the error to HA_ERR_RECORD_CHANGED when doing optimistic parallel apply.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
.../suite/rpl/r/rpl_parallel_retry.result | 22 +++++++++++
.../suite/rpl/t/rpl_parallel_retry.test | 38 +++++++++++++++++++
sql/log_event_server.cc | 11 ++++++
3 files changed, 71 insertions(+)
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result
index 2cc4044a2cd..4c7effd737a 100644
--- a/mysql-test/suite/rpl/r/rpl_parallel_retry.result
+++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result
@@ -339,6 +339,28 @@ connection server_1;
DROP TABLE t1, t2, t3, t4;
DROP function foo;
connection server_2;
+connection server_2;
+include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=4;
+connection server_1;
+CREATE TABLE t1 (a INT, b VARCHAR(123)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES(1, 'asdf');
+UPDATE t1 SET b='zxf1' WHERE a=1;
+UPDATE t1 SET b='\n' WHERE a=1;
+connection server_2;
+SET @old_dbug=@@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,write_row_inject_sleep_before_ha_write_row";
+include/start_slave.inc
+connection server_1;
+connection server_2;
+connection server_1;
+DROP TABLE t1;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
connection server_1;
CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES(100, 100);
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test
index fe6f40d2c85..1e87c85cd6c 100644
--- a/mysql-test/suite/rpl/t/rpl_parallel_retry.test
+++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test
@@ -410,6 +410,44 @@ DROP function foo;
--sync_slave_with_master server_2
+#
+# MDEV-33303: slave_parallel_mode=optimistic should not report the mode's
+# specific temporary errors.
+#
+
+--connection server_2
+--source include/stop_slave.inc
+SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
+SET GLOBAL slave_parallel_threads=4;
+
+--connection server_1
+# The problem occurred in the code path for row-based updates in tables
+# with no primary/unique key, where a scan is needed.
+CREATE TABLE t1 (a INT, b VARCHAR(123)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES(1, 'asdf');
+UPDATE t1 SET b='zxf1' WHERE a=1;
+UPDATE t1 SET b='\n' WHERE a=1;
+
+--connection server_2
+# Inject a small sleep in the code that makes the race easier to hit.
+SET @old_dbug=@@GLOBAL.debug_dbug;
+SET GLOBAL debug_dbug="+d,write_row_inject_sleep_before_ha_write_row";
+--source include/start_slave.inc
+
+--connection server_1
+# Here, we would get errors in the slave's error log:
+# [ERROR] mariadbd: Can't find record in 't1'
+--sync_slave_with_master server_2
+
+--connection server_1
+DROP TABLE t1;
+--sync_slave_with_master server_2
+--source include/stop_slave.inc
+SET GLOBAL debug_dbug=@old_dbug;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+
#
# MDEV-12746 rpl.rpl_parallel_optimistic_nobinlog fails committing out of order at retry
#
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index 744a41ca782..bd96ce0fc1a 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -7394,6 +7394,8 @@ Rows_log_event::write_row(rpl_group_info *rgi,
TODO: Add safety measures against infinite looping.
*/
+ DBUG_EXECUTE_IF("write_row_inject_sleep_before_ha_write_row",
+ my_sleep(20000););
if (table->s->sequence)
error= update_sequence();
else while (unlikely(error= table->file->ha_write_row(table->record[0])))
@@ -7891,6 +7893,12 @@ static int row_not_found_error(rpl_group_info *rgi)
? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED;
}
+static int end_of_file_error(rpl_group_info *rgi)
+{
+ return rgi->speculation != rpl_group_info::SPECULATE_OPTIMISTIC
+ ? HA_ERR_END_OF_FILE : HA_ERR_RECORD_CHANGED;
+}
+
/**
Locate the current row in event's table.
@@ -8138,6 +8146,8 @@ int Rows_log_event::find_row(rpl_group_info *rgi)
while ((error= table->file->ha_index_next(table->record[0])))
{
DBUG_PRINT("info",("no record matching the given row found"));
+ if (error == HA_ERR_END_OF_FILE)
+ error= end_of_file_error(rgi);
table->file->print_error(error, MYF(0));
table->file->ha_index_end();
goto end;
@@ -8174,6 +8184,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi)
break;
case HA_ERR_END_OF_FILE:
+ error= end_of_file_error(rgi);
DBUG_PRINT("info", ("Record not found"));
table->file->ha_rnd_end();
goto end;
--
2.30.2
1
0
From: Brandon Nesterenko <brandon.nesterenko(a)mariadb.com>
This patch adds an MTR test to show that threads awaiting semi-sync
ACKs can be awoken before their ACK is received from the slave, due
to the ack receiver thread broadcasting on a single condition
variable for all threads. The test causes the new assertion to fail.
---
.../rpl/t/rpl_semi_sync_cond_var_per_thd.cnf | 10 +++
.../rpl/t/rpl_semi_sync_cond_var_per_thd.test | 64 +++++++++++++++++++
sql/semisync_master.cc | 8 +++
3 files changed, 82 insertions(+)
create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.cnf
create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test
diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.cnf b/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.cnf
new file mode 100644
index 00000000000..e8e03e71ec8
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.cnf
@@ -0,0 +1,10 @@
+!include ../my.cnf
+
+[mysqld.1]
+log-warnings=9
+rpl_semi_sync_master_enabled=1
+rpl_semi_sync_master_wait_point=AFTER_COMMIT
+
+[mysqld.2]
+log-warnings=9
+rpl_semi_sync_slave_enabled=1
diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test b/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test
new file mode 100644
index 00000000000..f8fa0a99d9c
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_semi_sync_cond_var_per_thd.test
@@ -0,0 +1,64 @@
+#
+# This test ensures that, when using semi-sync with the wait_point
+# AFTER_COMMIT, each thread awaiting an ACK is only woken up when its ACK (or
+# an ACK for a later commit in binlog) has been received from the slave.
+#
+# Prior to MDEV-33551, all threads would be woken up for each ACK received,
+# leading to large slowdowns, as each thread would check if the ACK was for it
+# in mutual exclusion from the others.
+#
+# To ensure this, a DBUG_ASSERT is added into
+# Repl_semi_sync_master::commit_trx() to ensure that the ACK binlog coordinate
+# is at or after the coordinate we are waiting on. Then, we use binlog group
+# commit to commit a series of transactions, such that each will await an ACK
+# concurrently.
+#
+# References:
+# MDEV-33551: Semi-sync Wait Point AFTER_COMMIT Slow on Workloads with Heavy
+# Concurrency
+#
+--source include/have_binlog_format_row.inc
+--source include/have_debug.inc
+--source include/master-slave.inc
+
+--connection master
+set @save_bgc_count= @@global.binlog_commit_wait_count;
+set @save_bgc_usec= @@global.binlog_commit_wait_usec;
+set @@global.binlog_commit_wait_count=3;
+set @@global.binlog_commit_wait_usec=10000000;
+
+--echo # Ensure semi-sync is on
+--connection slave
+let $status_var= rpl_semi_sync_slave_status;
+let $status_var_value= ON;
+source include/wait_for_status_var.inc;
+
+--connection master
+let $status_var= rpl_semi_sync_master_status;
+let $status_var_value= ON;
+source include/wait_for_status_var.inc;
+
+--echo # Create three transactions to binlog group commit together
+--connection master
+--send create table t1 (a int)
+--connection server_1
+--send create table t2 (a int)
+--connection default
+--send create table t3 (a int)
+
+--connection master
+--reap
+--connection server_1
+--reap
+--connection default
+--reap
+
+
+--echo #
+--echo # Cleanup
+--connection master
+set @@global.binlog_commit_wait_count=@save_bgc_count;
+set @@global.binlog_commit_wait_usec=@save_bgc_usec;
+drop table t1, t2, t3;
+
+--source include/rpl_end.inc
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index 8cc721e5737..0eaf0f0e0e2 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -979,6 +979,14 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name,
{
rpl_semi_sync_master_trx_wait_num++;
rpl_semi_sync_master_trx_wait_time += wait_time;
+ /*
+ Assert we have either recieved our ACK; or have timed out and are
+ awoken in an off state.
+ */
+ DBUG_ASSERT(!get_master_enabled() || !is_on() || thd->is_killed() ||
+ 0 <= Active_tranx::compare(
+ m_reply_file_name, m_reply_file_pos,
+ trx_wait_binlog_name, trx_wait_binlog_pos));
}
}
}
--
2.30.2
1
1
[PATCH] MDEV-25923: Aria parallel repair MY_THREAD_SPECIFIC mismatch in realloc
by Kristian Nielsen 01 Mar '24
by Kristian Nielsen 01 Mar '24
01 Mar '24
maria_repair_parallel() clears the MY_THREAD_SPECIFIC flag for allocations
since it uses different threads. But it does so too late, after already
allocating a couple buffers as thread-specific. This caused assertions when
such buffer was later re-allocated from a different thread.
Also fixes MDEV-33562.
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
mysql-test/suite/maria/alter.result | 26 ++++++++++++++++++++++++++
mysql-test/suite/maria/alter.test | 28 ++++++++++++++++++++++++++++
storage/maria/ma_check.c | 14 +++++++-------
3 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/mysql-test/suite/maria/alter.result b/mysql-test/suite/maria/alter.result
index cc035426745..17164343163 100644
--- a/mysql-test/suite/maria/alter.result
+++ b/mysql-test/suite/maria/alter.result
@@ -193,3 +193,29 @@ ALTER TABLE t1 DISABLE KEYS;
INSERT INTO t1 VALUES (1, 'Nine chars or more');
ALTER TABLE t1 ENABLE KEYS;
DROP TABLE t1;
+#
+# MDEV-25923 Memory not freed or Assertion `old_flags == ((my_flags &
+# 0x10000U) ? 1 : 0)' failed in my_realloc upon ALTER on Aria table
+# with GIS column
+#
+CREATE TABLE t1 (pk INT PRIMARY KEY, a POINT DEFAULT ST_GEOMFROMTEXT('Point(1 1)')) ENGINE=Aria;
+INSERT INTO t1 (pk) SELECT seq FROM seq_1_to_100;
+SET @old_threads= @@SESSION.aria_repair_threads;
+SET SESSION aria_repair_threads= 2;
+ALTER TABLE t1 ROW_FORMAT=DYNAMIC;
+DROP TABLE t1;
+#
+# MDEV-33562: Assertion `(old_flags & 1) == ((my_flags & 0x10000U) ?
+# 1 : 0)' failed in my_realloc from sort_get_next_record on INSERT
+#
+SET @old_mode= @@SESSION.sql_mode;
+SET sql_mode='';
+CREATE TEMPORARY TABLE t (b TEXT, INDEX s(b(300))) ROW_FORMAT=DYNAMIC ENGINE=Aria;
+INSERT INTO t VALUES (REPEAT ('a',10000000));
+Warnings:
+Warning 1265 Data truncated for column 'b' at row 1
+CREATE TABLE ti LIKE t;
+INSERT INTO ti SELECT * FROM t;
+DROP TABLE t, ti;
+SET SESSION aria_repair_threads= @old_threads;
+SET SESSION sql_mode= @old_mode;
diff --git a/mysql-test/suite/maria/alter.test b/mysql-test/suite/maria/alter.test
index 525cd80f3d9..a68b5f2e0d7 100644
--- a/mysql-test/suite/maria/alter.test
+++ b/mysql-test/suite/maria/alter.test
@@ -203,3 +203,31 @@ ALTER TABLE t1 DISABLE KEYS;
INSERT INTO t1 VALUES (1, 'Nine chars or more');
ALTER TABLE t1 ENABLE KEYS;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-25923 Memory not freed or Assertion `old_flags == ((my_flags &
+--echo # 0x10000U) ? 1 : 0)' failed in my_realloc upon ALTER on Aria table
+--echo # with GIS column
+--echo #
+
+CREATE TABLE t1 (pk INT PRIMARY KEY, a POINT DEFAULT ST_GEOMFROMTEXT('Point(1 1)')) ENGINE=Aria;
+INSERT INTO t1 (pk) SELECT seq FROM seq_1_to_100;
+SET @old_threads= @@SESSION.aria_repair_threads;
+SET SESSION aria_repair_threads= 2;
+ALTER TABLE t1 ROW_FORMAT=DYNAMIC;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-33562: Assertion `(old_flags & 1) == ((my_flags & 0x10000U) ?
+--echo # 1 : 0)' failed in my_realloc from sort_get_next_record on INSERT
+--echo #
+
+SET @old_mode= @@SESSION.sql_mode;
+SET sql_mode='';
+CREATE TEMPORARY TABLE t (b TEXT, INDEX s(b(300))) ROW_FORMAT=DYNAMIC ENGINE=Aria;
+INSERT INTO t VALUES (REPEAT ('a',10000000));
+CREATE TABLE ti LIKE t;
+INSERT INTO ti SELECT * FROM t;
+DROP TABLE t, ti;
+SET SESSION aria_repair_threads= @old_threads;
+SET SESSION sql_mode= @old_mode;
diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c
index 1d41fb92947..9a6cca6e409 100644
--- a/storage/maria/ma_check.c
+++ b/storage/maria/ma_check.c
@@ -4336,6 +4336,13 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
printf("Data records: %s\n", llstr(start_records, llbuff));
}
+ /*
+ We cannot mark future memory allocations as thread specific when
+ doing parallel repair as we don't have a THD for each thread. Sharing the
+ same THD this would requre mutex locks around mallocs/reallocs to ensure
+ that two threads does not use the same THD at once.
+ */
+ param->malloc_flags= 0;
bzero(&new_data_cache, sizeof(new_data_cache));
if (initialize_variables_for_repair(param, &sort_info, &tmp_sort_param, info,
rep_quick, &backup_share))
@@ -4587,13 +4594,6 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
(void) my_setstacksize(&thr_attr, (size_t)my_thread_stack_size);
- /*
- We cannot mark future memory allocations as thread specific when
- doing parallel repair as we don't have a THD for each thread. Sharing the
- same THD this would requre mutex locks around mallocs/reallocs to ensure
- that two threads does not use the same THD at once.
- */
- param->malloc_flags= 0;
for (i=0 ; i < sort_info.total_keys ; i++)
{
/*
--
2.30.2
1
0
[PATCH] Fix stack overrun crash due to missing stack check in two recursive functions
by Kristian Nielsen 15 Feb '24
by Kristian Nielsen 15 Feb '24
15 Feb '24
Signed-off-by: Kristian Nielsen <knielsen(a)knielsen-hq.org>
---
sql/item.cc | 6 +++++-
sql/sql_select.cc | 6 ++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/sql/item.cc b/sql/item.cc
index 04b689f51af..1b244afdb8a 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -27,6 +27,7 @@
#include "sp_rcontext.h"
#include "sp_head.h"
#include "sql_trigger.h"
+#include "sql_parse.h"
#include "sql_select.h"
#include "sql_show.h" // append_identifier
#include "sql_view.h" // VIEW_ANY_SQL
@@ -485,7 +486,10 @@ void Item::print_parenthesised(String *str, enum_query_type query_type,
bool need_parens= precedence() < parent_prec;
if (need_parens)
str->append('(');
- print(str, query_type);
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, NULL))
+ str->append("<STACK OVERRUN>");
+ else
+ print(str, query_type);
if (need_parens)
str->append(')');
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a871faec99e..68a83d9877e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -17657,6 +17657,12 @@ Item_cond::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool and_level= functype() == Item_func::COND_AND_FUNC;
List<Item> *cond_arg_list= argument_list();
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, NULL))
+ {
+ *cond_value= Item::COND_FALSE;
+ return (COND*) 0; // Fatal error flag is set!
+ }
+
if (and_level)
{
/*
--
2.30.2
1
0