Commit 7d0d7826 authored by SergeyV@selena's avatar SergeyV@selena

Fixes bug #13377. Added code to close active log files in case

of log reset condition.
parent 78504ac3
...@@ -353,7 +353,7 @@ MYSQL_LOG::MYSQL_LOG() ...@@ -353,7 +353,7 @@ MYSQL_LOG::MYSQL_LOG()
:bytes_written(0), last_time(0), query_start(0), name(0), :bytes_written(0), last_time(0), query_start(0), name(0),
file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0), file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0),
need_start_event(1), prepared_xids(0), description_event_for_exec(0), need_start_event(1), prepared_xids(0), description_event_for_exec(0),
description_event_for_queue(0) description_event_for_queue(0), readers_count(0), reset_pending(false)
{ {
/* /*
We don't want to initialize LOCK_Log here as such initialization depends on We don't want to initialize LOCK_Log here as such initialization depends on
...@@ -379,7 +379,9 @@ void MYSQL_LOG::cleanup() ...@@ -379,7 +379,9 @@ void MYSQL_LOG::cleanup()
delete description_event_for_exec; delete description_event_for_exec;
(void) pthread_mutex_destroy(&LOCK_log); (void) pthread_mutex_destroy(&LOCK_log);
(void) pthread_mutex_destroy(&LOCK_index); (void) pthread_mutex_destroy(&LOCK_index);
(void) pthread_mutex_destroy(&LOCK_readers);
(void) pthread_cond_destroy(&update_cond); (void) pthread_cond_destroy(&update_cond);
(void) pthread_cond_destroy(&reset_cond);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -424,7 +426,9 @@ void MYSQL_LOG::init_pthread_objects() ...@@ -424,7 +426,9 @@ void MYSQL_LOG::init_pthread_objects()
inited= 1; inited= 1;
(void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_readers, MY_MUTEX_INIT_SLOW);
(void) pthread_cond_init(&update_cond, 0); (void) pthread_cond_init(&update_cond, 0);
(void) pthread_cond_init(&reset_cond, 0);
} }
const char *MYSQL_LOG::generate_name(const char *log_name, const char *MYSQL_LOG::generate_name(const char *log_name,
...@@ -927,6 +931,13 @@ bool MYSQL_LOG::reset_logs(THD* thd) ...@@ -927,6 +931,13 @@ bool MYSQL_LOG::reset_logs(THD* thd)
*/ */
pthread_mutex_lock(&LOCK_log); pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_index); pthread_mutex_lock(&LOCK_index);
/*
we need one more lock to block attempts to open a log while
we are waiting untill all log files will be closed
*/
pthread_mutex_lock(&LOCK_readers);
/* /*
The following mutex is needed to ensure that no threads call The following mutex is needed to ensure that no threads call
'delete thd' as we would then risk missing a 'rollback' from this 'delete thd' as we would then risk missing a 'rollback' from this
...@@ -949,6 +960,19 @@ bool MYSQL_LOG::reset_logs(THD* thd) ...@@ -949,6 +960,19 @@ bool MYSQL_LOG::reset_logs(THD* thd)
goto err; goto err;
} }
reset_pending = true;
/*
send update signal just in case so that all reader threads waiting
for log update will leave wait condition
*/
signal_update();
/*
if there are active readers wait until all of them will
release opened files
*/
if (readers_count)
pthread_cond_wait(&reset_cond, &LOCK_log);
for (;;) for (;;)
{ {
my_delete(linfo.log_file_name, MYF(MY_WME)); my_delete(linfo.log_file_name, MYF(MY_WME));
...@@ -967,7 +991,10 @@ bool MYSQL_LOG::reset_logs(THD* thd) ...@@ -967,7 +991,10 @@ bool MYSQL_LOG::reset_logs(THD* thd)
my_free((gptr) save_name, MYF(0)); my_free((gptr) save_name, MYF(0));
err: err:
reset_pending = false;
(void) pthread_mutex_unlock(&LOCK_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count);
pthread_mutex_unlock(&LOCK_readers);
pthread_mutex_unlock(&LOCK_index); pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log); pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -2038,6 +2065,10 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave) ...@@ -2038,6 +2065,10 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave)
{ {
const char *old_msg; const char *old_msg;
DBUG_ENTER("wait_for_update"); DBUG_ENTER("wait_for_update");
if (reset_pending)
DBUG_VOID_RETURN;
old_msg= thd->enter_cond(&update_cond, &LOCK_log, old_msg= thd->enter_cond(&update_cond, &LOCK_log,
is_slave ? is_slave ?
"Has read all relay log; waiting for the slave I/O " "Has read all relay log; waiting for the slave I/O "
...@@ -2288,6 +2319,40 @@ void MYSQL_LOG::signal_update() ...@@ -2288,6 +2319,40 @@ void MYSQL_LOG::signal_update()
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
void MYSQL_LOG::readers_addref()
{
/*
currently readers_addref and readers_release are necessary
only for __WIN__ build to wait untill readers will close
opened log files before reset.
There is no necessity for this on *nix, since it allows to
delete opened files, however it is more clean way to wait
untill all files will be closed on *nix as well.
If decided, the following #ifdef section is to be removed.
*/
#ifdef __WIN__
DBUG_ENTER("MYSQL_LOG::reader_addref");
pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_readers);
readers_count++;
pthread_mutex_unlock(&LOCK_readers);
pthread_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
#endif
}
void MYSQL_LOG::readers_release()
{
#ifdef __WIN__
DBUG_ENTER("MYSQL_LOG::reader_release");
pthread_mutex_lock(&LOCK_log);
readers_count--;
if (!readers_count)
pthread_cond_broadcast(&reset_cond);
pthread_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
#endif
}
#ifdef __NT__ #ifdef __NT__
void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
......
...@@ -3615,6 +3615,15 @@ log space"); ...@@ -3615,6 +3615,15 @@ log space");
pthread_mutex_lock(&mi->run_lock); pthread_mutex_lock(&mi->run_lock);
mi->slave_running = 0; mi->slave_running = 0;
mi->io_thd = 0; mi->io_thd = 0;
/* Close log file and free buffers */
if (mi->rli.cur_log_fd >= 0)
{
end_io_cache(&mi->rli.cache_buf);
my_close(mi->rli.cur_log_fd, MYF(MY_WME));
mi->rli.cur_log_fd= -1;
}
/* Forget the relay log's format */ /* Forget the relay log's format */
delete mi->rli.relay_log.description_event_for_queue; delete mi->rli.relay_log.description_event_for_queue;
mi->rli.relay_log.description_event_for_queue= 0; mi->rli.relay_log.description_event_for_queue= 0;
...@@ -3831,6 +3840,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ ...@@ -3831,6 +3840,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
rli->cached_charset_invalidate(); rli->cached_charset_invalidate();
rli->save_temporary_tables = thd->temporary_tables; rli->save_temporary_tables = thd->temporary_tables;
/* Close log file and free buffers if it's already open */
if (rli->cur_log_fd >= 0)
{
end_io_cache(&rli->cache_buf);
my_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
}
/* /*
TODO: see if we can do this conditionally in next_event() instead TODO: see if we can do this conditionally in next_event() instead
to avoid unneeded position re-init to avoid unneeded position re-init
......
...@@ -189,8 +189,11 @@ class MYSQL_LOG: public TC_LOG ...@@ -189,8 +189,11 @@ class MYSQL_LOG: public TC_LOG
{ {
private: private:
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */ /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
pthread_mutex_t LOCK_log, LOCK_index; pthread_mutex_t LOCK_log, LOCK_index, LOCK_readers;
pthread_cond_t update_cond; pthread_cond_t update_cond;
pthread_cond_t reset_cond;
bool reset_pending;
int readers_count;
ulonglong bytes_written; ulonglong bytes_written;
time_t last_time,query_start; time_t last_time,query_start;
IO_CACHE log_file; IO_CACHE log_file;
...@@ -334,6 +337,9 @@ class MYSQL_LOG: public TC_LOG ...@@ -334,6 +337,9 @@ class MYSQL_LOG: public TC_LOG
int purge_logs_before_date(time_t purge_time); int purge_logs_before_date(time_t purge_time);
int purge_first_log(struct st_relay_log_info* rli, bool included); int purge_first_log(struct st_relay_log_info* rli, bool included);
bool reset_logs(THD* thd); bool reset_logs(THD* thd);
inline bool is_reset_pending() { return reset_pending; }
void readers_addref();
void readers_release();
void close(uint exiting); void close(uint exiting);
// iterating through the log index file // iterating through the log index file
......
...@@ -372,6 +372,11 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ...@@ -372,6 +372,11 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
goto err; goto err;
} }
/*
Call readers_addref before opening log to track count
of binlog readers
*/
mysql_bin_log.readers_addref();
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0)
{ {
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
...@@ -569,7 +574,8 @@ impossible position"; ...@@ -569,7 +574,8 @@ impossible position";
goto err; goto err;
if (!(flags & BINLOG_DUMP_NON_BLOCK) && if (!(flags & BINLOG_DUMP_NON_BLOCK) &&
mysql_bin_log.is_active(log_file_name)) mysql_bin_log.is_active(log_file_name) &&
!mysql_bin_log.is_reset_pending())
{ {
/* /*
Block until there is more data in the log Block until there is more data in the log
...@@ -683,6 +689,13 @@ impossible position"; ...@@ -683,6 +689,13 @@ impossible position";
{ {
bool loop_breaker = 0; bool loop_breaker = 0;
// need this to break out of the for loop from switch // need this to break out of the for loop from switch
// if we are going to switch log file anyway, close current log first
end_io_cache(&log);
(void) my_close(file, MYF(MY_WME));
// decrease reference count of binlog readers
mysql_bin_log.readers_release();
thd->proc_info = "Finished reading one binlog; switching to next binlog"; thd->proc_info = "Finished reading one binlog; switching to next binlog";
switch (mysql_bin_log.find_next_log(&linfo, 1)) { switch (mysql_bin_log.find_next_log(&linfo, 1)) {
case LOG_INFO_EOF: case LOG_INFO_EOF:
...@@ -691,16 +704,25 @@ impossible position"; ...@@ -691,16 +704,25 @@ impossible position";
case 0: case 0:
break; break;
default: default:
// need following call to do release on err label
mysql_bin_log.readers_addref();
errmsg = "could not find next log"; errmsg = "could not find next log";
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err; goto err;
} }
if (loop_breaker) if (loop_breaker)
break; {
// need following call to do release on end label
mysql_bin_log.readers_addref();
break;
}
end_io_cache(&log); /*
(void) my_close(file, MYF(MY_WME)); Call readers_addref before opening log to track count
of binlog readers
*/
mysql_bin_log.readers_addref();
/* /*
Call fake_rotate_event() in case the previous log (the one which Call fake_rotate_event() in case the previous log (the one which
...@@ -733,6 +755,8 @@ impossible position"; ...@@ -733,6 +755,8 @@ impossible position";
end_io_cache(&log); end_io_cache(&log);
(void)my_close(file, MYF(MY_WME)); (void)my_close(file, MYF(MY_WME));
// decrease reference count of binlog readers
mysql_bin_log.readers_release();
send_eof(thd); send_eof(thd);
thd->proc_info = "Waiting to finalize termination"; thd->proc_info = "Waiting to finalize termination";
...@@ -759,6 +783,9 @@ impossible position"; ...@@ -759,6 +783,9 @@ impossible position";
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);
if (file >= 0) if (file >= 0)
(void) my_close(file, MYF(MY_WME)); (void) my_close(file, MYF(MY_WME));
// decrease reference count of binlog readers
mysql_bin_log.readers_release();
my_message(my_errno, errmsg, MYF(0)); my_message(my_errno, errmsg, MYF(0));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
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