Skip to content

Commit 381e9ad

Browse files
montywivuvova
authored andcommitted
MDEV-34150 Assertion failure in Diagnostics_area::set_error_status upon binary logging hitting tmp space limit
- Moved writing to binlog_cache from close_thread_tables() to binlog_commit(). - In select_create() delete cached row events instead of flushing them to disk. This was done to avoid possible disk write error in this code.
1 parent fcb3183 commit 381e9ad

File tree

8 files changed

+81
-45
lines changed

8 files changed

+81
-45
lines changed

mysql-test/include/show_binlog_events.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#
2121
# $binlog_start
2222
# Position for the 'FROM' clause of SHOW BINLOG EVENTS. If none
23-
# given, starts right after the Binlog_checkpoint_log_even.
23+
# given, starts right after the Binlog_checkpoint_log_event.
2424
#
2525
# $binlog_limit
2626
# Limit for the 'LIMIT' clause of SHOW BINLOG EVENTS, i.e.:

mysql-test/suite/binlog/r/binlog_unsafe.result

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,11 +2542,7 @@ master-bin.000001 # Annotate_rows # # insert into t2(a) values(new.a)
25422542
master-bin.000001 # Table_map # # table_id: # (test.t1)
25432543
master-bin.000001 # Table_map # # table_id: # (test.t3)
25442544
master-bin.000001 # Table_map # # table_id: # (test.t2)
2545-
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
2546-
master-bin.000001 # Annotate_rows # # insert into t3(a) values(new.a)
2547-
master-bin.000001 # Table_map # # table_id: # (test.t1)
2548-
master-bin.000001 # Table_map # # table_id: # (test.t3)
2549-
master-bin.000001 # Table_map # # table_id: # (test.t2)
2545+
master-bin.000001 # Write_rows_v1 # # table_id: #
25502546
master-bin.000001 # Write_rows_v1 # # table_id: #
25512547
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
25522548
master-bin.000001 # Query # # COMMIT

sql/log.cc

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,28 @@ class binlog_cache_mngr {
437437
binlog_cache_mngr(const binlog_cache_mngr& info);
438438
};
439439

440+
441+
/*
442+
Remove all row event from all binlog caches and clear all caches.
443+
This is only called from CREATE .. SELECT, in which case it safe to delete
444+
also events from the statement cache.
445+
*/
446+
447+
void THD::binlog_remove_rows_events()
448+
{
449+
binlog_cache_mngr *cache_mngr= binlog_get_cache_mngr();
450+
DBUG_ENTER("THD::binlog_remove_rows_events");
451+
452+
if (!cache_mngr ||
453+
(!WSREP_EMULATE_BINLOG_NNULL(this) && !mysql_bin_log.is_open()))
454+
DBUG_VOID_RETURN;
455+
456+
MYSQL_BIN_LOG::remove_pending_rows_event(this, &cache_mngr->stmt_cache);
457+
MYSQL_BIN_LOG::remove_pending_rows_event(this, &cache_mngr->trx_cache);
458+
cache_mngr->reset(1,1);
459+
DBUG_VOID_RETURN;
460+
}
461+
440462
/**
441463
The function handles the first phase of two-phase binlogged ALTER.
442464
On master binlogs START ALTER when that is configured to do so.
@@ -1897,20 +1919,19 @@ binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
18971919
static int
18981920
binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
18991921
{
1922+
int error=0;
19001923
DBUG_ENTER("binlog_truncate_trx_cache");
19011924

19021925
if(!WSREP_EMULATE_BINLOG_NNULL(thd) && !mysql_bin_log.is_open())
19031926
DBUG_RETURN(0);
19041927

1905-
int error=0;
1906-
19071928
DBUG_PRINT("info", ("thd->options={ %s %s}, transaction: %s",
19081929
FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT),
19091930
FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
19101931
all ? "all" : "stmt"));
19111932

1912-
auto &trx_cache= cache_mngr->trx_cache;
1913-
MYSQL_BIN_LOG::remove_pending_rows_event(thd, &trx_cache);
1933+
binlog_cache_data *trx_cache= &cache_mngr->trx_cache;
1934+
MYSQL_BIN_LOG::remove_pending_rows_event(thd, trx_cache);
19141935
thd->reset_binlog_for_next_statement();
19151936

19161937
/*
@@ -1919,7 +1940,7 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
19191940
*/
19201941
if (ending_trans(thd, all))
19211942
{
1922-
if (trx_cache.has_incident())
1943+
if (trx_cache->has_incident())
19231944
error= mysql_bin_log.write_incident(thd);
19241945

19251946
DBUG_ASSERT(thd->binlog_table_maps == 0);
@@ -1931,9 +1952,9 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
19311952
transaction cache to remove the statement.
19321953
*/
19331954
else
1934-
trx_cache.restore_prev_position();
1955+
trx_cache->restore_prev_position();
19351956

1936-
DBUG_ASSERT(trx_cache.pending() == NULL);
1957+
DBUG_ASSERT(trx_cache->pending() == NULL);
19371958
DBUG_RETURN(error);
19381959
}
19391960

@@ -2190,6 +2211,11 @@ int binlog_commit(THD *thd, bool all, bool ro_1pc)
21902211
cache_mngr->need_unlog= false;
21912212
}
21922213
}
2214+
else if (thd->lock)
2215+
{
2216+
/* If not in LOCK TABLES, flush the transaction log */
2217+
error= thd->binlog_flush_pending_rows_event(TRUE, TRUE);
2218+
}
21932219
/*
21942220
This is part of the stmt rollback.
21952221
*/
@@ -6583,6 +6609,26 @@ int binlog_flush_pending_rows_event(THD *thd, bool stmt_end,
65836609
}
65846610

65856611

6612+
/*
6613+
Check if there are pending row events in the binlog cache
6614+
6615+
@return 0 no
6616+
@return 1 rows in stmt_cache
6617+
@return 2 rows in trx_cache
6618+
@return 3 rows in both
6619+
*/
6620+
6621+
uint THD::has_pending_row_events()
6622+
{
6623+
binlog_cache_mngr *cache_mngr;
6624+
if (!mysql_bin_log.is_open() ||
6625+
!(cache_mngr= binlog_get_cache_mngr()))
6626+
return 0;
6627+
return ((cache_mngr->stmt_cache.pending() ? 1 : 0) |
6628+
(cache_mngr->trx_cache.pending() ? 2 : 0));
6629+
}
6630+
6631+
65866632
/**
65876633
This function removes the pending rows event, discarding any outstanding
65886634
rows. If there is no pending rows event available, this is effectively a

sql/online_alter.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ int online_alter_end_trans(Online_alter_cache_list &cache_list, THD *thd,
222222
{
223223
// Do not set STMT_END for last event to leave table open in altering thd
224224
error= binlog_flush_pending_rows_event(thd, false, true, binlog, &cache);
225+
if (error)
226+
do_commit= commit= 0;
225227
}
226228

227229
if (do_commit)

sql/sql_base.cc

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ int close_thread_tables(THD *thd)
933933
934934
Note that even if we are in LTM_LOCK_TABLES mode and statement
935935
requires prelocking (e.g. when we are closing tables after
936-
failing ot "open" all tables required for statement execution)
936+
failing at "open" all tables required for statement execution)
937937
we will exit this function a few lines below.
938938
*/
939939
if (! thd->lex->requires_prelocking())
@@ -964,16 +964,13 @@ int close_thread_tables(THD *thd)
964964
if (thd->lock)
965965
{
966966
/*
967-
For RBR we flush the pending event just before we unlock all the
968-
tables. This means that we are at the end of a topmost
969-
statement, so we ensure that the STMT_END_F flag is set on the
970-
pending event. For statements that are *inside* stored
971-
functions, the pending event will not be flushed: that will be
972-
handled either before writing a query log event (inside
973-
binlog_query()) or when preparing a pending event.
974-
*/
975-
(void)thd->binlog_flush_pending_rows_event(TRUE);
976-
error= mysql_unlock_tables(thd, thd->lock);
967+
Ensure binlog caches has been flushed in binlog_query() or
968+
binlog_commit().
969+
*/
970+
DBUG_ASSERT((thd->state_flags & Open_tables_state::BACKUPS_AVAIL) ||
971+
!thd->has_pending_row_events());
972+
if (mysql_unlock_tables(thd, thd->lock))
973+
error= 1;
977974
thd->lock=0;
978975
}
979976
/*

sql/sql_class.cc

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7553,11 +7553,12 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
75537553
if (variables.option_bits & OPTION_GTID_BEGIN)
75547554
is_transactional= 1;
75557555

7556-
auto *cache_mngr= binlog_get_cache_mngr();
7556+
binlog_cache_mngr *cache_mngr= binlog_get_cache_mngr();
75577557
if (!cache_mngr)
75587558
DBUG_RETURN(0);
7559-
auto *cache= binlog_get_cache_data(cache_mngr,
7560-
use_trans_cache(this, is_transactional));
7559+
binlog_cache_data *cache=
7560+
binlog_get_cache_data(cache_mngr,
7561+
use_trans_cache(this, is_transactional));
75617562

75627563
int error=
75637564
::binlog_flush_pending_rows_event(this, stmt_end, is_transactional,
@@ -7852,22 +7853,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
78527853
}
78537854

78547855
/*
7855-
If we are not in prelocked mode, mysql_unlock_tables() will be
7856-
called after this binlog_query(), so we have to flush the pending
7857-
rows event with the STMT_END_F set to unlock all tables at the
7858-
slave side as well.
7859-
7860-
If we are in prelocked mode, the flushing will be done inside the
7861-
top-most close_thread_tables().
7856+
We should not flush row events for sub-statements, like a trigger or
7857+
function. The main statement will take care of the flushing when
7858+
calling binlog_query().
78627859
*/
7863-
if (this->locked_tables_mode <= LTM_LOCK_TABLES)
7860+
if (!in_sub_stmt)
78647861
{
7865-
int error;
7866-
if (unlikely(error= binlog_flush_pending_rows_event(TRUE, is_trans)))
7867-
{
7868-
DBUG_ASSERT(error > 0);
7869-
DBUG_RETURN(error);
7870-
}
7862+
if (unlikely(binlog_flush_pending_rows_event(TRUE, is_trans)))
7863+
DBUG_RETURN(my_errno); // Return error code as required
78717864
}
78727865

78737866
/*

sql/sql_class.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3279,7 +3279,8 @@ class THD: public THD_count, /* this must be first */
32793279
binlog_flush_pending_rows_event(stmt_end, TRUE));
32803280
}
32813281
int binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional);
3282-
3282+
void binlog_remove_rows_events();
3283+
uint has_pending_row_events();
32833284
bool binlog_need_stmt_format(bool is_transactional) const
32843285
{
32853286
if (!log_current_statement())

sql/sql_insert.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5342,14 +5342,15 @@ void select_create::abort_result_set()
53425342
thd->transaction->stmt.modified_non_trans_table= FALSE;
53435343
thd->variables.option_bits= save_option_bits;
53445344

5345-
/* possible error of writing binary log is ignored deliberately */
5346-
(void) thd->binlog_flush_pending_rows_event(TRUE, TRUE);
5347-
53485345
if (table)
53495346
{
53505347
bool tmp_table= table->s->tmp_table;
53515348
bool table_creation_was_logged= (!tmp_table ||
53525349
table->s->table_creation_was_logged);
5350+
5351+
/* CREATE SELECT failed. Remove all row events and clear caches */
5352+
thd->binlog_remove_rows_events();
5353+
53535354
if (tmp_table)
53545355
{
53555356
DBUG_ASSERT(saved_tmp_table_share);

0 commit comments

Comments
 (0)