Skip to content

Commit c72ddee

Browse files
committed
MDEV-32364 Server crashes when starting server with high innodb_log_buffer_size
log_t::create(), log_t::attach(): Return whether the initialisation succeeded. It may fail if too large an innodb_log_buffer_size is specified. recv_sys_t::close_files(): Actually close the data files so that the test mariabackup.huge_lsn,strict_crc32 will not fail on Microsoft Windows when renaming ib_logfile101 due to a leaked file handle of ib_logfile0. recv_sys_t::find_checkpoint(): Register recv_sys.files[0] as OS_FILE_CLOSED because the file handle has already been attached to log_sys.log and we do not want to close the file twice. recv_sys_t::read(): Access the first log file via log_sys.log. This is a port of commit 6e9b421 adapted to commit 685d958 (MDEV-14425). The test case is omitted, because it would fail to fail when the log is stored in persistent memory (or "fake PMEM" on Linux /dev/shm).
1 parent 50784c8 commit c72ddee

File tree

6 files changed

+107
-29
lines changed

6 files changed

+107
-29
lines changed

extra/mariabackup/xtrabackup.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4755,7 +4755,9 @@ static bool xtrabackup_backup_func()
47554755
goto fail;
47564756
}
47574757

4758-
log_sys.create();
4758+
if (!log_sys.create()) {
4759+
goto fail;
4760+
}
47594761
/* get current checkpoint_lsn */
47604762
{
47614763
mysql_mutex_lock(&recv_sys.mutex);
@@ -6125,7 +6127,9 @@ static bool xtrabackup_prepare_func(char** argv)
61256127
}
61266128

61276129
recv_sys.create();
6128-
log_sys.create();
6130+
if (!log_sys.create()) {
6131+
goto error;
6132+
}
61296133
recv_sys.recovery_on = true;
61306134

61316135
xb_fil_io_init();

storage/innobase/include/log0log.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -356,15 +356,31 @@ typedef srw_lock log_rwlock_t;
356356
/** @return end of resize_buf */
357357
inline const byte *resize_buf_end() const noexcept
358358
{ return resize_buf + resize_target; }
359+
360+
/** Initialise the redo log subsystem. */
361+
void create_low();
362+
/** Initialise the redo log subsystem.
363+
@return whether the initialisation succeeded */
364+
bool create() { create_low(); return true; }
365+
366+
/** Attach a log file.
367+
@return whether the memory allocation succeeded */
368+
bool attach(log_file_t file, os_offset_t size);
369+
#else
370+
/** Initialise the redo log subsystem.
371+
@return whether the initialisation succeeded */
372+
bool create();
373+
/** Attach a log file. */
374+
void attach_low(log_file_t file, os_offset_t size);
375+
bool attach(log_file_t file, os_offset_t size)
376+
{ attach_low(file, size); return true; }
359377
#endif
360378

361379
#if defined __linux__ || defined _WIN32
362380
/** Try to enable or disable file system caching (update log_buffered) */
363381
void set_buffered(bool buffered);
364382
#endif
365383

366-
void attach(log_file_t file, os_offset_t size);
367-
368384
void close_file();
369385

370386
/** Calculate the checkpoint safety margins. */
@@ -421,9 +437,6 @@ typedef srw_lock log_rwlock_t;
421437
/** Make previous write_buf() durable and update flushed_to_disk_lsn. */
422438
bool flush(lsn_t lsn) noexcept;
423439

424-
/** Initialise the redo log subsystem. */
425-
void create();
426-
427440
/** Shut down the redo log subsystem. */
428441
void close();
429442

storage/innobase/include/log0recv.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ struct recv_sys_t
254254
/** The contents of the doublewrite buffer */
255255
recv_dblwr_t dblwr;
256256

257-
inline void read(os_offset_t offset, span<byte> buf);
257+
inline dberr_t read(os_offset_t offset, span<byte> buf);
258258
inline size_t files_size();
259-
void close_files() { files.clear(); files.shrink_to_fit(); }
259+
void close_files();
260260

261261
/** Advance pages_it if it matches the iterator */
262262
void pages_it_invalidate(const map::iterator &p)

storage/innobase/log/log0log.cc

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,25 +95,39 @@ void log_t::set_capacity()
9595
log_sys.max_checkpoint_age = margin;
9696
}
9797

98-
/** Initialize the redo log subsystem. */
99-
void log_t::create()
98+
#ifdef HAVE_PMEM
99+
void log_t::create_low()
100+
#else
101+
bool log_t::create()
102+
#endif
100103
{
101104
ut_ad(this == &log_sys);
102105
ut_ad(!is_initialised());
103106

104-
latch.SRW_LOCK_INIT(log_latch_key);
105-
init_lsn_lock();
106-
107107
/* LSN 0 and 1 are reserved; @see buf_page_t::oldest_modification_ */
108108
lsn.store(FIRST_LSN, std::memory_order_relaxed);
109109
flushed_to_disk_lsn.store(FIRST_LSN, std::memory_order_relaxed);
110110
write_lsn= FIRST_LSN;
111111

112112
#ifndef HAVE_PMEM
113113
buf= static_cast<byte*>(ut_malloc_dontdump(buf_size, PSI_INSTRUMENT_ME));
114-
TRASH_ALLOC(buf, buf_size);
114+
if (!buf)
115+
{
116+
alloc_fail:
117+
sql_print_error("InnoDB: Cannot allocate memory;"
118+
" too large innodb_log_buffer_size?");
119+
return false;
120+
}
115121
flush_buf= static_cast<byte*>(ut_malloc_dontdump(buf_size,
116122
PSI_INSTRUMENT_ME));
123+
if (!flush_buf)
124+
{
125+
ut_free_dodump(buf, buf_size);
126+
buf= nullptr;
127+
goto alloc_fail;
128+
}
129+
130+
TRASH_ALLOC(buf, buf_size);
117131
TRASH_ALLOC(flush_buf, buf_size);
118132
checkpoint_buf= static_cast<byte*>(aligned_malloc(4096, 4096));
119133
memset_aligned<4096>(checkpoint_buf, 0, 4096);
@@ -123,6 +137,9 @@ void log_t::create()
123137
ut_ad(!flush_buf);
124138
#endif
125139

140+
latch.SRW_LOCK_INIT(log_latch_key);
141+
init_lsn_lock();
142+
126143
max_buf_free= buf_size / LOG_BUF_FLUSH_RATIO - LOG_BUF_FLUSH_MARGIN;
127144
set_check_flush_or_checkpoint();
128145

@@ -136,6 +153,9 @@ void log_t::create()
136153
buf_free= 0;
137154

138155
ut_ad(is_initialised());
156+
#ifndef HAVE_PMEM
157+
return true;
158+
#endif
139159
}
140160

141161
dberr_t log_file_t::close() noexcept
@@ -201,7 +221,11 @@ static void *log_mmap(os_file_t file, os_offset_t size)
201221
}
202222
#endif
203223

204-
void log_t::attach(log_file_t file, os_offset_t size)
224+
#ifdef HAVE_PMEM
225+
bool log_t::attach(log_file_t file, os_offset_t size)
226+
#else
227+
void log_t::attach_low(log_file_t file, os_offset_t size)
228+
#endif
205229
{
206230
log= file;
207231
ut_ad(!size || size >= START_OFFSET + SIZE_OF_FILE_CHECKPOINT);
@@ -218,18 +242,33 @@ void log_t::attach(log_file_t file, os_offset_t size)
218242
log.close();
219243
mprotect(ptr, size_t(size), PROT_READ);
220244
buf= static_cast<byte*>(ptr);
221-
#if defined __linux__ || defined _WIN32
245+
# if defined __linux__ || defined _WIN32
222246
set_block_size(CPU_LEVEL1_DCACHE_LINESIZE);
223-
#endif
247+
# endif
224248
log_maybe_unbuffered= true;
225249
log_buffered= false;
226-
return;
250+
return true;
227251
}
228252
}
229253
buf= static_cast<byte*>(ut_malloc_dontdump(buf_size, PSI_INSTRUMENT_ME));
230-
TRASH_ALLOC(buf, buf_size);
254+
if (!buf)
255+
{
256+
alloc_fail:
257+
max_buf_free= 0;
258+
sql_print_error("InnoDB: Cannot allocate memory;"
259+
" too large innodb_log_buffer_size?");
260+
return false;
261+
}
231262
flush_buf= static_cast<byte*>(ut_malloc_dontdump(buf_size,
232263
PSI_INSTRUMENT_ME));
264+
if (!flush_buf)
265+
{
266+
ut_free_dodump(buf, buf_size);
267+
buf= nullptr;
268+
goto alloc_fail;
269+
}
270+
271+
TRASH_ALLOC(buf, buf_size);
233272
TRASH_ALLOC(flush_buf, buf_size);
234273
#endif
235274

@@ -244,6 +283,7 @@ void log_t::attach(log_file_t file, os_offset_t size)
244283
#ifdef HAVE_PMEM
245284
checkpoint_buf= static_cast<byte*>(aligned_malloc(block_size, block_size));
246285
memset_aligned<64>(checkpoint_buf, 0, block_size);
286+
return true;
247287
#endif
248288
}
249289

storage/innobase/log/log0recv.cc

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,12 +1201,13 @@ inline void recv_sys_t::trim(const page_id_t page_id, lsn_t lsn)
12011201
DBUG_VOID_RETURN;
12021202
}
12031203

1204-
inline void recv_sys_t::read(os_offset_t total_offset, span<byte> buf)
1204+
inline dberr_t recv_sys_t::read(os_offset_t total_offset, span<byte> buf)
12051205
{
12061206
size_t file_idx= static_cast<size_t>(total_offset / log_sys.file_size);
12071207
os_offset_t offset= total_offset % log_sys.file_size;
1208-
dberr_t err= recv_sys.files[file_idx].read(offset, buf);
1209-
ut_a(err == DB_SUCCESS);
1208+
return file_idx
1209+
? recv_sys.files[file_idx].read(offset, buf)
1210+
: log_sys.log.read(offset, buf);
12101211
}
12111212

12121213
inline size_t recv_sys_t::files_size()
@@ -1365,6 +1366,15 @@ static void fil_name_process(const char *name, ulint len, uint32_t space_id,
13651366
}
13661367
}
13671368

1369+
void recv_sys_t::close_files()
1370+
{
1371+
for (auto &file : files)
1372+
if (file.is_opened())
1373+
file.close();
1374+
files.clear();
1375+
files.shrink_to_fit();
1376+
}
1377+
13681378
/** Clean up after recv_sys_t::create() */
13691379
void recv_sys_t::close()
13701380
{
@@ -1640,7 +1650,8 @@ static dberr_t recv_log_recover_10_5(lsn_t lsn_offset)
16401650
memcpy_aligned<512>(buf, &log_sys.buf[lsn_offset & ~511], 512);
16411651
else
16421652
{
1643-
recv_sys.read(lsn_offset & ~lsn_t{4095}, {buf, 4096});
1653+
if (dberr_t err= recv_sys.read(lsn_offset & ~lsn_t{4095}, {buf, 4096}))
1654+
return err;
16441655
buf+= lsn_offset & 0xe00;
16451656
}
16461657

@@ -1691,13 +1702,17 @@ dberr_t recv_sys_t::find_checkpoint()
16911702
else if (size < log_t::START_OFFSET + SIZE_OF_FILE_CHECKPOINT)
16921703
{
16931704
too_small:
1694-
os_file_close(file);
16951705
sql_print_error("InnoDB: File %.*s is too small",
16961706
int(path.size()), path.data());
1707+
err_exit:
1708+
os_file_close(file);
16971709
return DB_ERROR;
16981710
}
1711+
else if (!log_sys.attach(file, size))
1712+
goto err_exit;
1713+
else
1714+
file= OS_FILE_CLOSED;
16991715

1700-
log_sys.attach(file, size);
17011716
recv_sys.files.emplace_back(file);
17021717
for (int i= 1; i < 101; i++)
17031718
{

storage/innobase/srv/srv0start.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,17 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn)
216216

217217
ret = os_file_set_size(logfile0.c_str(), file, srv_log_file_size);
218218
if (!ret) {
219-
os_file_close_func(file);
220219
ib::error() << "Cannot set log file " << logfile0
221220
<< " size to " << ib::bytes_iec{srv_log_file_size};
221+
close_and_exit:
222+
os_file_close_func(file);
222223
goto err_exit;
223224
}
224225

225226
log_sys.set_latest_format(srv_encrypt_log);
226-
log_sys.attach(file, srv_log_file_size);
227+
if (!log_sys.attach(file, srv_log_file_size)) {
228+
goto close_and_exit;
229+
}
227230
if (!fil_system.sys_space->open(create_new_db)) {
228231
goto err_exit;
229232
}
@@ -1054,7 +1057,10 @@ dberr_t srv_start(bool create_new_db)
10541057
}
10551058
#endif /* UNIV_DEBUG */
10561059

1057-
log_sys.create();
1060+
if (!log_sys.create()) {
1061+
return srv_init_abort(DB_ERROR);
1062+
}
1063+
10581064
recv_sys.create();
10591065
lock_sys.create(srv_lock_table_size);
10601066

0 commit comments

Comments
 (0)