From 6e9b421f7721b65661bb932360d2bccbcc33e10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 6 Oct 2023 14:16:01 +0300 Subject: [PATCH] MDEV-32364 Server crashes when starting server with high innodb_log_buffer_size log_t::create(): Return whether the initialisation succeeded. It may fail if too large an innodb_log_buffer_size is specified. --- extra/mariabackup/xtrabackup.cc | 9 ++++++-- .../suite/innodb/r/log_buffer_size.result | 6 +++++ .../suite/innodb/t/log_buffer_size.test | 23 +++++++++++++++++++ storage/innobase/include/log0log.h | 5 ++-- storage/innobase/log/log0log.cc | 16 ++++++++++--- storage/innobase/srv/srv0start.cc | 8 ++++++- 6 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 mysql-test/suite/innodb/r/log_buffer_size.result create mode 100644 mysql-test/suite/innodb/t/log_buffer_size.test diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 6254b8c7237..5c122ad04f2 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4613,7 +4613,10 @@ fail: goto fail; } - log_sys.create(); + if (!log_sys.create()) { + msg("Error: cannot initialize log subsystem"); + goto fail; + } log_sys.log.create(); log_sys.log.open_file(get_log_file_path()); @@ -6053,8 +6056,10 @@ static bool xtrabackup_prepare_func(char** argv) } sync_check_init(); + if (!log_sys.create()) { + goto error_cleanup; + } recv_sys.create(); - log_sys.create(); recv_sys.recovery_on = true; xb_fil_io_init(); diff --git a/mysql-test/suite/innodb/r/log_buffer_size.result b/mysql-test/suite/innodb/r/log_buffer_size.result new file mode 100644 index 00000000000..5e1c6c25cb9 --- /dev/null +++ b/mysql-test/suite/innodb/r/log_buffer_size.result @@ -0,0 +1,6 @@ +# restart: --innodb-log-buffer-size=1125899906842624 +SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS +FOUND 1 /InnoDB: Cannot allocate memory; too large innodb_log_buffer_size\?/ in mysqld.1.err +# restart diff --git a/mysql-test/suite/innodb/t/log_buffer_size.test b/mysql-test/suite/innodb/t/log_buffer_size.test new file mode 100644 index 00000000000..7fed6079de6 --- /dev/null +++ b/mysql-test/suite/innodb/t/log_buffer_size.test @@ -0,0 +1,23 @@ +--source include/have_innodb.inc +--source include/no_valgrind_without_big.inc +# the parameter is only 32-bit on Windows +--source include/not_windows.inc + +--disable_query_log +call mtr.add_suppression("\\[Warning\\] option 'innodb-log-buffer-size': unsigned value 1125899906842624 adjusted"); +call mtr.add_suppression("InnoDB: Cannot allocate memory; too large innodb_log_buffer_size\\?"); +call mtr.add_suppression("\\[ERROR\\] InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("\\[ERROR\\] Plugin 'InnoDB' registration as a STORAGE ENGINE failed"); +--enable_query_log + +--let $restart_parameters= --innodb-log-buffer-size=1125899906842624 +--source include/restart_mysqld.inc +SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); + +--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err +--let SEARCH_PATTERN=InnoDB: Cannot allocate memory; too large innodb_log_buffer_size\\? +--source include/search_pattern_in_file.inc + +--let $restart_parameters= +--source include/restart_mysqld.inc diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 4a5567ff62d..e8399ba4c96 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -681,8 +681,9 @@ public: return flushes.load(std::memory_order_relaxed); } - /** Initialise the redo log subsystem. */ - void create(); + /** Initialise the redo log subsystem. + @return whether the initialisation succeeded */ + bool create(); /** Shut down the redo log subsystem. */ void close(); diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 61b0d30fec2..58d7689894d 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -171,11 +171,10 @@ log_set_capacity(ulonglong file_size) } /** Initialize the redo log subsystem. */ -void log_t::create() +bool log_t::create() { ut_ad(this == &log_sys); ut_ad(!is_initialised()); - m_initialised= true; mysql_mutex_init(log_sys_mutex_key, &mutex, nullptr); mysql_mutex_init(log_flush_order_mutex_key, &flush_order_mutex, nullptr); @@ -191,9 +190,18 @@ void log_t::create() buf= static_cast(ut_malloc_dontdump(srv_log_buffer_size, PSI_INSTRUMENT_ME)); - TRASH_ALLOC(buf, srv_log_buffer_size); + if (!buf) + return false; flush_buf= static_cast(ut_malloc_dontdump(srv_log_buffer_size, PSI_INSTRUMENT_ME)); + if (!flush_buf) + { + ut_free_dodump(buf, srv_log_buffer_size); + buf= nullptr; + return false; + } + + TRASH_ALLOC(buf, srv_log_buffer_size); TRASH_ALLOC(flush_buf, srv_log_buffer_size); max_buf_free= srv_log_buffer_size / LOG_BUF_FLUSH_RATIO - @@ -220,6 +228,8 @@ void log_t::create() buf_free= LOG_BLOCK_HDR_SIZE; checkpoint_buf= static_cast (aligned_malloc(OS_FILE_LOG_BLOCK_SIZE, OS_FILE_LOG_BLOCK_SIZE)); + m_initialised= true; + return true; } file_os_io::file_os_io(file_os_io &&rhs) : m_fd(rhs.m_fd) diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index a507b29ffa2..cc6fed7f86c 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -99,6 +99,7 @@ Created 2/16/1996 Heikki Tuuri #include "os0event.h" #include "zlib.h" #include "ut0crc32.h" +#include "log.h" /** We are prepared for a situation that we have this many threads waiting for a semaphore inside InnoDB. srv_start() sets the value. */ @@ -1248,7 +1249,12 @@ dberr_t srv_start(bool create_new_db) } #endif /* UNIV_DEBUG */ - log_sys.create(); + if (!log_sys.create()) { + sql_print_error("InnoDB: Cannot allocate memory;" + " too large innodb_log_buffer_size?"); + return srv_init_abort(DB_ERROR); + } + recv_sys.create(); lock_sys.create(srv_lock_table_size);