Commit 3fd214c8 authored by Nirbhay Choubey's avatar Nirbhay Choubey

MDEV-9423: cannot add new node to the cluser: Binlog..

.. file '/var/log/mysql/mariadb-bin.000001' not found in binlog
index, needed for recovery. Aborting.

In Galera cluster, while preparing for rsync/xtrabackup based
SST, the donor node takes an FTWRL followed by (REFRESH_ENGINE_LOG
in rsync based state transfer and) REFRESH_BINARY_LOG. The latter
rotates the binary log and logs Binlog_checkpoint_log_event
corresponding to the penultimate binary log file into the new file.
The checkpoint event for the current file is later logged
synchronously by binlog_background_thread.

Now, since in rsync/xtrabackup based snapshot state transfer methods,
only the last binary log file is transferred to the joiner node; the
file could get transferred even before the checkpoint event for the
same file gets written to it. As a result, the joiner node would fail
to start complaining about the missing binlog file needed for recovery.

In order to fix this, a mechanism has been put in place to make
REFRESH_BINARY_LOG operation wait for Binlog_checkpoint_log_event
to be logged for the current binary log file if the node is part of
a Galera cluster. As further safety, during rsync based state transfer
the donor node now acquires and owns LOCK_log for the duration of file
transfer during SST.
parent 33492ec8
...@@ -3690,7 +3690,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name, ...@@ -3690,7 +3690,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
new_xid_list_entry->binlog_id= current_binlog_id; new_xid_list_entry->binlog_id= current_binlog_id;
/* Remove any initial entries with no pending XIDs. */ /* Remove any initial entries with no pending XIDs. */
while ((b= binlog_xid_count_list.head()) && b->xid_count == 0) while ((b= binlog_xid_count_list.head()) && b->xid_count == 0)
{
my_free(binlog_xid_count_list.get()); my_free(binlog_xid_count_list.get());
}
mysql_cond_broadcast(&COND_xid_list);
binlog_xid_count_list.push_back(new_xid_list_entry); binlog_xid_count_list.push_back(new_xid_list_entry);
mysql_mutex_unlock(&LOCK_xid_list); mysql_mutex_unlock(&LOCK_xid_list);
...@@ -4227,6 +4230,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log, ...@@ -4227,6 +4230,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log,
DBUG_ASSERT(b->xid_count == 0); DBUG_ASSERT(b->xid_count == 0);
my_free(binlog_xid_count_list.get()); my_free(binlog_xid_count_list.get());
} }
mysql_cond_broadcast(&COND_xid_list);
reset_master_pending--; reset_master_pending--;
mysql_mutex_unlock(&LOCK_xid_list); mysql_mutex_unlock(&LOCK_xid_list);
} }
...@@ -4237,6 +4241,26 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log, ...@@ -4237,6 +4241,26 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log,
} }
void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
{
mysql_mutex_lock(&LOCK_xid_list);
for (;;)
{
if (binlog_xid_count_list.is_last(binlog_xid_count_list.head()))
break;
mysql_cond_wait(&COND_xid_list, &LOCK_xid_list);
}
mysql_mutex_unlock(&LOCK_xid_list);
/*
LOCK_xid_list and LOCK_log are chained, so the LOCK_log will only be
obtained after mark_xid_done() has written the last checkpoint event.
*/
mysql_mutex_lock(&LOCK_log);
mysql_mutex_unlock(&LOCK_log);
}
/** /**
Delete relay log files prior to rli->group_relay_log_name Delete relay log files prior to rli->group_relay_log_name
(i.e. all logs which are not involved in a non-finished group (i.e. all logs which are not involved in a non-finished group
...@@ -9394,7 +9418,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint) ...@@ -9394,7 +9418,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
*/ */
if (unlikely(reset_master_pending)) if (unlikely(reset_master_pending))
{ {
mysql_cond_signal(&COND_xid_list); mysql_cond_broadcast(&COND_xid_list);
mysql_mutex_unlock(&LOCK_xid_list); mysql_mutex_unlock(&LOCK_xid_list);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -9432,8 +9456,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint) ...@@ -9432,8 +9456,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
mysql_mutex_lock(&LOCK_log); mysql_mutex_lock(&LOCK_log);
mysql_mutex_lock(&LOCK_xid_list); mysql_mutex_lock(&LOCK_xid_list);
--mark_xid_done_waiting; --mark_xid_done_waiting;
if (unlikely(reset_master_pending)) mysql_cond_broadcast(&COND_xid_list);
mysql_cond_signal(&COND_xid_list);
/* We need to reload current_binlog_id due to release/re-take of lock. */ /* We need to reload current_binlog_id due to release/re-take of lock. */
current= current_binlog_id; current= current_binlog_id;
......
...@@ -788,6 +788,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG ...@@ -788,6 +788,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
bool reset_logs(THD* thd, bool create_new_log, bool reset_logs(THD* thd, bool create_new_log,
rpl_gtid *init_state, uint32 init_state_len, rpl_gtid *init_state, uint32 init_state_len,
ulong next_log_number); ulong next_log_number);
void wait_for_last_checkpoint_event();
void close(uint exiting); void close(uint exiting);
void clear_inuse_flag_when_closing(File file); void clear_inuse_flag_when_closing(File file);
......
...@@ -155,6 +155,12 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, ...@@ -155,6 +155,12 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
{ {
if (mysql_bin_log.rotate_and_purge(true)) if (mysql_bin_log.rotate_and_purge(true))
*write_to_binlog= -1; *write_to_binlog= -1;
if (WSREP_ON)
{
/* Wait for last binlog checkpoint event to be logged. */
mysql_bin_log.wait_for_last_checkpoint_event();
}
} }
} }
if (options & REFRESH_RELAY_LOG) if (options & REFRESH_RELAY_LOG)
......
...@@ -1120,6 +1120,16 @@ static void* sst_donor_thread (void* a) ...@@ -1120,6 +1120,16 @@ static void* sst_donor_thread (void* a)
if (!err) if (!err)
{ {
sst_disallow_writes (thd.ptr, true); sst_disallow_writes (thd.ptr, true);
/*
Lets also keep statements that modify binary logs (like RESET LOGS,
RESET MASTER) from proceeding until the files have been transferred
to the joiner node.
*/
if (mysql_bin_log.is_open())
{
mysql_mutex_lock(mysql_bin_log.get_log_lock());
}
locked= true; locked= true;
goto wait_signal; goto wait_signal;
} }
...@@ -1128,6 +1138,11 @@ static void* sst_donor_thread (void* a) ...@@ -1128,6 +1138,11 @@ static void* sst_donor_thread (void* a)
{ {
if (locked) if (locked)
{ {
if (mysql_bin_log.is_open())
{
mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
mysql_mutex_unlock(mysql_bin_log.get_log_lock());
}
sst_disallow_writes (thd.ptr, false); sst_disallow_writes (thd.ptr, false);
thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
locked= false; locked= false;
...@@ -1160,6 +1175,11 @@ static void* sst_donor_thread (void* a) ...@@ -1160,6 +1175,11 @@ static void* sst_donor_thread (void* a)
if (locked) // don't forget to unlock server before return if (locked) // don't forget to unlock server before return
{ {
if (mysql_bin_log.is_open())
{
mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
mysql_mutex_unlock(mysql_bin_log.get_log_lock());
}
sst_disallow_writes (thd.ptr, false); sst_disallow_writes (thd.ptr, false);
thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment