MDEV-33464 Crash when innodb_max_undo_log_size is set to innodb_page_size*4294967296

purge_sys_t::truncating_tablespace(): Clamp the
innodb_max_undo_log_size to the maximum number of pages
before converting the result into a 32-bit unsigned integer.

This fixes up commit f8c88d905b (MDEV-33213).

In later major versions, we would use 32-bit unsigned integer here
due to commit ca501ffb04
and the code would crash also on 64-bit processors.

Reviewed by: Debarun Banerjee
This commit is contained in:
Marko Mäkelä 2024-02-15 12:34:04 +02:00
parent 691f923906
commit 53c6c823dc
3 changed files with 9 additions and 1 deletions

View file

@ -25,6 +25,7 @@ delete from t1;
connection con2; connection con2;
delete from t2; delete from t2;
connection con1; connection con1;
SET GLOBAL innodb_max_undo_log_size = @@GLOBAL.innodb_page_size * 4294967296;
SET GLOBAL innodb_undo_log_truncate = 1; SET GLOBAL innodb_undo_log_truncate = 1;
commit; commit;
disconnect con1; disconnect con1;
@ -33,6 +34,8 @@ commit;
disconnect con2; disconnect con2;
connection default; connection default;
SET GLOBAL innodb_max_purge_lag_wait=0; SET GLOBAL innodb_max_purge_lag_wait=0;
SET GLOBAL innodb_max_undo_log_size=DEFAULT;
SET GLOBAL innodb_max_purge_lag_wait=0;
set global innodb_fast_shutdown=0; set global innodb_fast_shutdown=0;
# restart # restart
drop table t1, t2; drop table t1, t2;

View file

@ -42,6 +42,7 @@ connection con1; reap; send delete from t1;
connection con2; reap; delete from t2; connection con2; reap; delete from t2;
connection con1; reap; connection con1; reap;
SET GLOBAL innodb_max_undo_log_size = @@GLOBAL.innodb_page_size * 4294967296;
SET GLOBAL innodb_undo_log_truncate = 1; SET GLOBAL innodb_undo_log_truncate = 1;
commit; disconnect con1; commit; disconnect con1;
connection con2; commit; disconnect con2; connection con2; commit; disconnect con2;
@ -52,6 +53,8 @@ connection default;
let $trx_before= `SHOW ENGINE INNODB STATUS`; let $trx_before= `SHOW ENGINE INNODB STATUS`;
let $trx_before= `select substr('$trx_before',9)+2`; let $trx_before= `select substr('$trx_before',9)+2`;
SET GLOBAL innodb_max_purge_lag_wait=0;
SET GLOBAL innodb_max_undo_log_size=DEFAULT;
SET GLOBAL innodb_max_purge_lag_wait=0; SET GLOBAL innodb_max_purge_lag_wait=0;
set global innodb_fast_shutdown=0; set global innodb_fast_shutdown=0;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc

View file

@ -669,7 +669,9 @@ fil_space_t *purge_sys_t::truncating_tablespace()
if (space || srv_undo_tablespaces_active < 2 || !srv_undo_log_truncate) if (space || srv_undo_tablespaces_active < 2 || !srv_undo_log_truncate)
return space; return space;
const ulint size= ulint(srv_max_undo_log_size >> srv_page_size_shift); const uint32_t size=
uint32_t(std::min(ulonglong{std::numeric_limits<uint32_t>::max()},
srv_max_undo_log_size >> srv_page_size_shift));
for (ulint i= truncate_undo_space.last, j= i;; ) for (ulint i= truncate_undo_space.last, j= i;; )
{ {
if (fil_space_t *s= undo_truncate_try(srv_undo_space_id_start + i, size)) if (fil_space_t *s= undo_truncate_try(srv_undo_space_id_start + i, size))