Skip to content

Commit 78839df

Browse files
committed
BUG#13779291: RACE CONDITION AROUND ROTATE RELAY LOGS & FLUSH LOGS
This is part 8 of the patch. Refactored MYSQL_BIN_LOG::write_incident(), added a new argument do_flush_and_sync.
1 parent 0f7f4a0 commit 78839df

File tree

4 files changed

+75
-74
lines changed

4 files changed

+75
-74
lines changed

sql/binlog.cc

Lines changed: 68 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
939939
if (ending_trans(thd, all))
940940
{
941941
if (cache_mngr->trx_cache.has_incident())
942-
error= mysql_bin_log.write_incident(thd, TRUE);
942+
error= mysql_bin_log.write_incident(thd, true/*need_lock_log=true*/);
943943

944944
thd->clear_binlog_table_maps();
945945

@@ -1094,7 +1094,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
10941094
*/
10951095
if (cache_mngr->stmt_cache.has_incident())
10961096
{
1097-
error= mysql_bin_log.write_incident(thd, TRUE);
1097+
error= mysql_bin_log.write_incident(thd, true/*need_lock_log=true*/);
10981098
cache_mngr->reset_stmt_cache();
10991099
}
11001100
else
@@ -2383,6 +2383,9 @@ bool MYSQL_BIN_LOG::open_binlog(const char *log_name,
23832383

23842384
bool write_file_name_to_index_file=0;
23852385

2386+
/* This must be before goto err. */
2387+
Format_description_log_event s(BINLOG_VERSION);
2388+
23862389
if (!my_b_filelength(&log_file))
23872390
{
23882391
/*
@@ -2398,54 +2401,51 @@ bool MYSQL_BIN_LOG::open_binlog(const char *log_name,
23982401
write_file_name_to_index_file= 1;
23992402
}
24002403

2404+
/*
2405+
don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
2406+
as we won't be able to reset it later
2407+
*/
2408+
if (io_cache_type == WRITE_CACHE)
2409+
s.flags |= LOG_EVENT_BINLOG_IN_USE_F;
2410+
s.checksum_alg= is_relay_log ?
2411+
/* relay-log */
2412+
/* inherit master's A descriptor if one has been received */
2413+
(relay_log_checksum_alg=
2414+
(relay_log_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF) ?
2415+
relay_log_checksum_alg :
2416+
/* otherwise use slave's local preference of RL events verification */
2417+
(opt_slave_sql_verify_checksum == 0) ?
2418+
(uint8) BINLOG_CHECKSUM_ALG_OFF : binlog_checksum_options):
2419+
/* binlog */
2420+
binlog_checksum_options;
2421+
DBUG_ASSERT(s.checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
2422+
if (!s.is_valid())
2423+
goto err;
2424+
s.dont_set_created= null_created_arg;
2425+
/* Set LOG_EVENT_RELAY_LOG_F flag for relay log's FD */
2426+
if (is_relay_log)
2427+
s.set_relay_log_event();
2428+
if (s.write(&log_file))
2429+
goto err;
2430+
bytes_written+= s.data_written;
2431+
/*
2432+
We need to revisit this code and improve it.
2433+
See further comments in the mysqld.
2434+
/Alfranio
2435+
*/
2436+
if (current_thd && gtid_mode > 0)
24012437
{
2402-
Format_description_log_event s(BINLOG_VERSION);
2403-
/*
2404-
don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
2405-
as we won't be able to reset it later
2406-
*/
2407-
if (io_cache_type == WRITE_CACHE)
2408-
s.flags |= LOG_EVENT_BINLOG_IN_USE_F;
2409-
s.checksum_alg= is_relay_log ?
2410-
/* relay-log */
2411-
/* inherit master's A descriptor if one has been received */
2412-
(relay_log_checksum_alg=
2413-
(relay_log_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF) ?
2414-
relay_log_checksum_alg :
2415-
/* otherwise use slave's local preference of RL events verification */
2416-
(opt_slave_sql_verify_checksum == 0) ?
2417-
(uint8) BINLOG_CHECKSUM_ALG_OFF : binlog_checksum_options):
2418-
/* binlog */
2419-
binlog_checksum_options;
2420-
DBUG_ASSERT(s.checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
2421-
if (!s.is_valid())
2422-
goto err;
2423-
s.dont_set_created= null_created_arg;
2424-
/* Set LOG_EVENT_RELAY_LOG_F flag for relay log's FD */
2425-
if (is_relay_log)
2426-
s.set_relay_log_event();
2427-
if (s.write(&log_file))
2438+
if (need_sid_lock)
2439+
global_sid_lock.wrlock();
2440+
else
2441+
global_sid_lock.assert_some_wrlock();
2442+
Previous_gtids_log_event prev_gtids_ev(previous_gtid_set);
2443+
if (need_sid_lock)
2444+
global_sid_lock.unlock();
2445+
prev_gtids_ev.checksum_alg= s.checksum_alg;
2446+
if (prev_gtids_ev.write(&log_file))
24282447
goto err;
2429-
bytes_written+= s.data_written;
2430-
/*
2431-
We need to revisit this code and improve it.
2432-
See further comments in the mysqld.
2433-
/Alfranio
2434-
*/
2435-
if (current_thd && gtid_mode > 0)
2436-
{
2437-
if (need_sid_lock)
2438-
global_sid_lock.wrlock();
2439-
else
2440-
global_sid_lock.assert_some_wrlock();
2441-
Previous_gtids_log_event prev_gtids_ev(previous_gtid_set);
2442-
if (need_sid_lock)
2443-
global_sid_lock.unlock();
2444-
prev_gtids_ev.checksum_alg= s.checksum_alg;
2445-
if (prev_gtids_ev.write(&log_file))
2446-
goto err;
2447-
bytes_written+= prev_gtids_ev.data_written;
2448-
}
2448+
bytes_written+= prev_gtids_ev.data_written;
24492449
}
24502450
if (extra_description_event &&
24512451
extra_description_event->binlog_version>=4)
@@ -3879,7 +3879,7 @@ bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
38793879

38803880
int MYSQL_BIN_LOG::new_file(Format_description_log_event *extra_description_event)
38813881
{
3882-
return new_file_impl(1, extra_description_event);
3882+
return new_file_impl(true/*need_lock_log=true*/, extra_description_event);
38833883
}
38843884

38853885
/*
@@ -3888,7 +3888,7 @@ int MYSQL_BIN_LOG::new_file(Format_description_log_event *extra_description_even
38883888
*/
38893889
int MYSQL_BIN_LOG::new_file_without_locking(Format_description_log_event *extra_description_event)
38903890
{
3891-
return new_file_impl(0, extra_description_event);
3891+
return new_file_impl(false/*need_lock_log=false*/, extra_description_event);
38923892
}
38933893

38943894

@@ -3951,9 +3951,9 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock_log, Format_description_log_even
39513951
*/
39523952
if ((error= generate_new_name(new_name, name)))
39533953
goto end;
3954-
new_name_ptr=new_name;
3955-
3954+
else
39563955
{
3956+
new_name_ptr=new_name;
39573957
/*
39583958
We log the whole file name for log file as the user may decide
39593959
to change base names at some point.
@@ -4493,7 +4493,6 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge)
44934493
DBUG_ASSERT(!is_relay_log);
44944494
mysql_mutex_assert_owner(&LOCK_log);
44954495

4496-
//todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log);
44974496
*check_purge= false;
44984497

44994498
if (force_rotate || (my_b_tell(&log_file) >= (my_off_t) max_size))
@@ -4508,7 +4507,8 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge)
45084507
We give it a shot and try to write an incident event anyway
45094508
to the current log.
45104509
*/
4511-
if (!write_incident(current_thd, FALSE))
4510+
if (!write_incident(current_thd, false/*need_lock_log=false*/,
4511+
false/*do_flush_and_sync==false*/))
45124512
flush_and_sync(0);
45134513

45144514
*check_purge= true;
@@ -4553,7 +4553,6 @@ int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate)
45534553
bool check_purge= false;
45544554

45554555
DBUG_ASSERT(!is_relay_log);
4556-
//todo: fix the macro def and restore safe_mutex_assert_not_owner(&LOCK_log);
45574556
mysql_mutex_lock(&LOCK_log);
45584557
error= rotate(force_rotate, &check_purge);
45594558
/*
@@ -4855,11 +4854,14 @@ int MYSQL_BIN_LOG::do_write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
48554854
@param ev Incident event to be written
48564855
@param need_lock_log If true, will acquire LOCK_log; otherwise the
48574856
caller should already have acquired LOCK_log.
4857+
@do_flush_and_sync If true, will call flush_and_sync(), rotate() and
4858+
purge().
48584859
48594860
@retval false error
48604861
@retval true success
48614862
*/
4862-
bool MYSQL_BIN_LOG::write_incident(Incident_log_event *ev, bool need_lock_log)
4863+
bool MYSQL_BIN_LOG::write_incident(Incident_log_event *ev, bool need_lock_log,
4864+
bool do_flush_and_sync)
48634865
{
48644866
uint error= 0;
48654867
DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
@@ -4876,26 +4878,21 @@ bool MYSQL_BIN_LOG::write_incident(Incident_log_event *ev, bool need_lock_log)
48764878

48774879
error= ev->write(&log_file);
48784880

4879-
if (need_lock_log)
4881+
if (do_flush_and_sync)
48804882
{
4881-
/**
4882-
@todo this is weird, what does need_lock_log have to do with
4883-
flush_and_sync()? Explain this or refactor. /Sven
4884-
*/
48854883
if (!error && !(error= flush_and_sync(0)))
48864884
{
48874885
bool check_purge= false;
48884886
signal_update();
48894887
error= rotate(true, &check_purge);
4890-
mysql_mutex_unlock(&LOCK_log);
48914888
if (!error && check_purge)
48924889
purge();
48934890
}
4894-
else
4895-
{
4896-
mysql_mutex_unlock(&LOCK_log);
4897-
}
48984891
}
4892+
4893+
if (need_lock_log)
4894+
mysql_mutex_unlock(&LOCK_log);
4895+
48994896
DBUG_RETURN(error);
49004897
}
49014898
/**
@@ -4910,7 +4907,8 @@ bool MYSQL_BIN_LOG::write_incident(Incident_log_event *ev, bool need_lock_log)
49104907
@retval
49114908
1 success
49124909
*/
4913-
bool MYSQL_BIN_LOG::write_incident(THD *thd, bool need_lock_log)
4910+
bool MYSQL_BIN_LOG::write_incident(THD *thd, bool need_lock_log,
4911+
bool do_flush_and_sync)
49144912
{
49154913
DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
49164914

@@ -4922,7 +4920,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool need_lock_log)
49224920
Incident incident= INCIDENT_LOST_EVENTS;
49234921
Incident_log_event ev(thd, incident, write_error_msg);
49244922

4925-
DBUG_RETURN(write_incident(&ev, need_lock_log));
4923+
DBUG_RETURN(write_incident(&ev, need_lock_log, do_flush_and_sync));
49264924
}
49274925

49284926
/**
@@ -4975,7 +4973,8 @@ bool MYSQL_BIN_LOG::write_cache(THD *thd, binlog_cache_data *cache_data,
49754973
if ((write_error= do_write_cache(cache, false, false)))
49764974
goto err;
49774975

4978-
if (incident && write_incident(thd, FALSE))
4976+
if (incident && write_incident(thd, false/*need_lock_log=false*/,
4977+
false/*do_flush_and_sync==false*/))
49794978
goto err;
49804979

49814980
bool synced= 0;

sql/binlog.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,10 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
266266

267267
void set_write_error(THD *thd, bool is_transactional);
268268
bool check_write_error(THD *thd);
269-
bool write_incident(THD *thd, bool lock);
270-
bool write_incident(Incident_log_event *ev, bool lock);
269+
bool write_incident(THD *thd, bool need_lock_log,
270+
bool do_flush_and_sync= true);
271+
bool write_incident(Incident_log_event *ev, bool need_lock_log,
272+
bool do_flush_and_sync= true);
271273

272274
void start_union_events(THD *thd, query_id_t query_id_param);
273275
void stop_union_events(THD *thd);

sql/rpl_injector.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,11 @@ void injector::new_trans(THD *thd, injector::transaction *ptr)
312312
int injector::record_incident(THD *thd, Incident incident)
313313
{
314314
Incident_log_event ev(thd, incident);
315-
return mysql_bin_log.write_incident(&ev, TRUE);
315+
return mysql_bin_log.write_incident(&ev, true/*need_lock_log=true*/);
316316
}
317317

318318
int injector::record_incident(THD *thd, Incident incident, LEX_STRING const message)
319319
{
320320
Incident_log_event ev(thd, incident, message);
321-
return mysql_bin_log.write_incident(&ev, TRUE);
321+
return mysql_bin_log.write_incident(&ev, true/*need_lock_log=true*/);
322322
}

sql/sql_parse.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3274,7 +3274,7 @@ case SQLCOM_PREPARE:
32743274
if (incident)
32753275
{
32763276
Incident_log_event ev(thd, incident);
3277-
if (mysql_bin_log.write_incident(&ev, TRUE))
3277+
if (mysql_bin_log.write_incident(&ev, true/*need_lock_log=true*/))
32783278
{
32793279
res= 1;
32803280
break;

0 commit comments

Comments
 (0)