1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-34705: Binlog-in-engine: Fix hang with event group of specific size

If the event group fitted in the binlog cache without the GTID event but not
with, the code would attempt to spill part of the GTID event as out-of-band
data, which is not correct. In release builds this would hang the server as
the spilling would try to lock an already owned mutex.

Fix by checking if the GTID event fits, and spilling any non-GTID data as
oob if it does not.

Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
Kristian Nielsen
2025-06-01 21:46:52 +02:00
parent 36b559fe7d
commit baec2064a1
6 changed files with 101 additions and 20 deletions

View File

@@ -3262,6 +3262,40 @@ public:
};
#ifdef MYSQL_SERVER
/*
This is used to compute a compile-time constant max for the size (in bytes)
of a GTID event (Gtid_log_event::max_size).
It is carefully written to take boolean parameters corresponding directly
to each conditional in Gtid_log_event::write(), so that the calculation here
will match the actual length computed by write().
Please ensure that that any new conditionals added in write() that affect
the event length are similarly extended with a boolean parameter for this
function so future code changes do not introduce incorrect result of this
function.
*/
static constexpr uint32_t
cap_gtid_event_size(uint32_t proposed_size)
{
/* This just because std::min is not constexpr in c++11. */
return LOG_EVENT_HEADER_LEN +
(proposed_size < GTID_HEADER_LEN ? GTID_HEADER_LEN : proposed_size);
}
static constexpr uint32_t
get_gtid_event_size(bool fl_commit_id, bool fl_xa, bool fl_extra,
bool fl_multi_engine, bool fl_alter,
int bq_size, int gt_size)
{
return cap_gtid_event_size((fl_commit_id ? GTID_HEADER_LEN + 2 : 13) +
(fl_xa ? 6 + bq_size + gt_size : 0) +
(fl_extra ? 1 : 0) +
(fl_multi_engine ? 1 : 0) +
(fl_alter ? 8 : 0));
}
#endif
/**
@class Gtid_log_event
@@ -3392,12 +3426,19 @@ public:
involving multiple storage engines. No flag and extra data are added
to the event when the transaction involves only one engine.
*/
static const uchar FL_EXTRA_MULTI_ENGINE_E1= 1;
static const uchar FL_START_ALTER_E1= 2;
static const uchar FL_COMMIT_ALTER_E1= 4;
static const uchar FL_ROLLBACK_ALTER_E1= 8;
static constexpr uchar FL_EXTRA_MULTI_ENGINE_E1= 1;
static constexpr uchar FL_START_ALTER_E1= 2;
static constexpr uchar FL_COMMIT_ALTER_E1= 4;
static constexpr uchar FL_ROLLBACK_ALTER_E1= 8;
#ifdef MYSQL_SERVER
static constexpr uint32_t max_size=
get_gtid_event_size(FL_GROUP_COMMIT_ID,
(bool)(FL_PREPARED_XA|FL_COMPLETED_XA),
true, FL_EXTRA_MULTI_ENGINE_E1,
(bool)(FL_COMMIT_ALTER_E1|FL_ROLLBACK_ALTER_E1),
MAXBQUALSIZE, MAXGTRIDSIZE);
Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
uint16 flags, bool is_transactional, uint64 commit_id,
bool has_xid= false, bool is_ro_1pc= false);
@@ -3430,6 +3471,7 @@ public:
}
#ifdef MYSQL_SERVER
uint32_t get_size() const noexcept;
bool write(Log_event_writer *writer) override;
static int make_compatible_event(String *packet, bool *need_dummy_event,
ulong ev_offset, enum_binlog_checksum_alg checksum_alg);