1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-41442: Too large InnoDB mtr with large binlog_cache_size

The binlog-in-engine code limits the maximum size of engine binlog writes by
forcing OOB-spill, eg. to avoid exceeding InnoDB max mtr size. However there
was a case missed: When the transaction is larger than binlog_max_spill_size
but smaller than the binlog_cache_size, there was no check to force
OOB-spilling, and the code would do a too large binlog write that asserts or
fails inside InnoDB.

Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
Kristian Nielsen
2026-10-13 22:16:43 +02:00
parent 18286059ce
commit ca4e698dae
3 changed files with 20 additions and 3 deletions

View File

@@ -57,6 +57,8 @@ UPDATE t3 SET b = 'tmp' WHERE id = 1;
UPDATE t3 SET a = REPEAT('y', 65535);
UPDATE t3 SET b = 'wic';
COMMIT;
SET binlog_row_image=MINIMAL;
UPDATE t3 SET a = REPEAT('y', 15000);
disconnect my_con1;
connection master;
SET GLOBAL binlog_cache_size= @old_cache_size;

View File

@@ -125,6 +125,16 @@ UPDATE t3 SET b = 'tmp' WHERE id = 1;
UPDATE t3 SET a = REPEAT('y', 65535);
UPDATE t3 SET b = 'wic';
COMMIT;
# MDEV-41442: Too large mtr when trx is larger than InnoDB max mtr size but
# smaller than binlog_cache_size.
# Use MINIMAL just to make the trx size not depend on old table data.
# We want > ~1MB but smaller than binlog_cache_size to trigger the
# bug condition.
SET binlog_row_image=MINIMAL;
UPDATE t3 SET a = REPEAT('y', 15000);
--disconnect my_con1
--connection master
SET GLOBAL binlog_cache_size= @old_cache_size;

View File

@@ -8400,13 +8400,18 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, binlog_cache_data *cache_data,
if (opt_binlog_engine_hton)
{
DBUG_ASSERT(cache_data != nullptr);
uint32_t avail= (uint32_t)(dest->write_end - dest->write_pos);
uint64_t total= my_b_tell(dest);
uint32_t avail=
unlikely(total >= binlog_max_spill_size) ? 0 :
MY_MIN((uint32_t)(dest->write_end - dest->write_pos),
(uint32_t)(binlog_max_spill_size - total));
if (unlikely(avail < Gtid_log_event::max_size) &&
avail < gtid_event.get_size())
{
/*
The GTID event doesn't fit in the cache, so we have to spill the
contents as oob event data.
The GTID event doesn't fit in the cache (or within
binlog_max_spill_size), so we have to spill the contents as oob event
data.
*/
if (my_b_flush_io_cache(dest, 0))
DBUG_RETURN(true);