Skip to content

Commit 112b21d

Browse files
author
Jan Lindström
committed
MDEV-12600: crash during install_db with innodb_page_size=32K and ibdata1=3M;
Problem was that all doublewrite buffer pages must fit to first system datafile. Ported commit 27a34df7882b1f8ed283f22bf83e8bfc523cbfde Author: Shaohua Wang <shaohua.wang@oracle.com> Date: Wed Aug 12 15:55:19 2015 +0800 BUG#21551464 - SEGFAULT WHILE INITIALIZING DATABASE WHEN INNODB_DATA_FILE SIZE IS SMALL To 10.1 (with extended error printout). btr_create(): If ibuf header page allocation fails report error and return FIL_NULL. Similarly if root page allocation fails return a error. dict_build_table_def_step: If fsp_header_init fails return error code. fsp_header_init: returns true if header initialization succeeds and false if not. fseg_create_general: report error if segment or page allocation fails. innobase_init: If first datafile is smaller than 3M and could not contain all doublewrite buffer pages report error and fail to initialize InnoDB plugin. row_truncate_table_for_mysql: report error if fsp header init fails. srv_init_abort: New function to report database initialization errors. srv_undo_tablespaces_init, innobase_start_or_create_for_mysql: If database initialization fails report error and abort. trx_rseg_create: If segment header creation fails return.
1 parent 6b69871 commit 112b21d

File tree

19 files changed

+319
-89
lines changed

19 files changed

+319
-89
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
--loose-innodb-sys-indexes
2-
--innodb-data-file-path=ibdata1:1M:autoextend
2+
--innodb-data-file-path=ibdata1:3M:autoextend

storage/innobase/btr/btr0btr.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,12 @@ btr_create(
17011701
space, 0,
17021702
IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
17031703

1704+
if (ibuf_hdr_block == NULL) {
1705+
ib_logf(IB_LOG_LEVEL_ERROR,
1706+
"Allocation of the first ibuf header page failed.");
1707+
return (FIL_NULL);
1708+
}
1709+
17041710
buf_block_dbg_add_level(
17051711
ibuf_hdr_block, SYNC_IBUF_TREE_NODE_NEW);
17061712

@@ -1714,6 +1720,11 @@ btr_create(
17141720
+ IBUF_HEADER + IBUF_TREE_SEG_HEADER,
17151721
IBUF_TREE_ROOT_PAGE_NO,
17161722
FSP_UP, mtr);
1723+
1724+
if (!block) {
1725+
ib_logf(IB_LOG_LEVEL_ERROR,
1726+
"Allocation of the tree root page segment failed.");
1727+
}
17171728
ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO);
17181729
} else {
17191730
#ifdef UNIV_BLOB_DEBUG
@@ -1726,6 +1737,12 @@ btr_create(
17261737
#endif /* UNIV_BLOB_DEBUG */
17271738
block = fseg_create(space, 0,
17281739
PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
1740+
1741+
if (!block) {
1742+
ib_logf(IB_LOG_LEVEL_ERROR,
1743+
"Allocation of the btree segment failed.");
1744+
}
1745+
17291746
}
17301747

17311748
if (block == NULL) {
@@ -1754,6 +1771,8 @@ btr_create(
17541771
segment before return. */
17551772
btr_free_root(space, zip_size, page_no, mtr);
17561773

1774+
ib_logf(IB_LOG_LEVEL_ERROR,
1775+
"Allocation of the non-ibuf tree segment for leaf pages failed.");
17571776
return(FIL_NULL);
17581777
}
17591778

storage/innobase/dict/dict0crea.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,13 @@ dict_build_table_def_step(
321321

322322
mtr_start(&mtr);
323323

324-
fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
324+
bool res = fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
325325

326326
mtr_commit(&mtr);
327+
328+
if (!res) {
329+
return (DB_ERROR);
330+
}
327331
} else {
328332
/* Create in the system tablespace: disallow Barracuda
329333
features by keeping only the first bit which says whether

storage/innobase/fil/fil0fil.cc

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5812,19 +5812,21 @@ fil_report_invalid_page_access(
58125812
ulint len, /*!< in: I/O length */
58135813
ulint type) /*!< in: I/O type */
58145814
{
5815-
fprintf(stderr,
5816-
"InnoDB: Error: trying to access page number %lu"
5817-
" in space %lu,\n"
5818-
"InnoDB: space name %s,\n"
5819-
"InnoDB: which is outside the tablespace bounds.\n"
5820-
"InnoDB: Byte offset %lu, len %lu, i/o type %lu.\n"
5821-
"InnoDB: If you get this error at mysqld startup,"
5822-
" please check that\n"
5823-
"InnoDB: your my.cnf matches the ibdata files"
5824-
" that you have in the\n"
5825-
"InnoDB: MySQL server.\n",
5826-
(ulong) block_offset, (ulong) space_id, space_name,
5827-
(ulong) byte_offset, (ulong) len, (ulong) type);
5815+
ib_logf(IB_LOG_LEVEL_ERROR,
5816+
"Trying to access page number " ULINTPF
5817+
" in space " ULINTPF
5818+
" space name %s,"
5819+
" which is outside the tablespace bounds."
5820+
" Byte offset " ULINTPF ", len " ULINTPF " i/o type " ULINTPF ".",
5821+
block_offset, space_id, space_name,
5822+
byte_offset, len, type);
5823+
5824+
ib_logf(IB_LOG_LEVEL_FATAL,
5825+
"If you get this error at mysqld startup,"
5826+
" please check that"
5827+
" your my.cnf matches the ibdata files"
5828+
" that you have in the"
5829+
" MySQL server.");
58285830
}
58295831

58305832
/********************************************************************//**
@@ -6043,11 +6045,10 @@ fil_io(
60436045
mutex_exit(&fil_system->mutex);
60446046
return(DB_ERROR);
60456047
}
6048+
60466049
fil_report_invalid_page_access(
60476050
block_offset, space_id, space->name,
60486051
byte_offset, len, type);
6049-
6050-
ut_error;
60516052
}
60526053

60536054
/* Open file if closed */
@@ -6059,10 +6060,11 @@ fil_io(
60596060
ib_logf(IB_LOG_LEVEL_ERROR,
60606061
"Trying to do i/o to a tablespace which "
60616062
"exists without .ibd data file. "
6062-
"i/o type %lu, space id %lu, page no %lu, "
6063-
"i/o length %lu bytes",
6064-
(ulong) type, (ulong) space_id,
6065-
(ulong) block_offset, (ulong) len);
6063+
"i/o type " ULINTPF ", space id "
6064+
ULINTPF ", page no " ULINTPF ", "
6065+
"i/o length " ULINTPF " bytes",
6066+
type, space_id,
6067+
block_offset, len);
60666068

60676069
return(DB_TABLESPACE_DELETED);
60686070
}
@@ -6082,8 +6084,6 @@ fil_io(
60826084
fil_report_invalid_page_access(
60836085
block_offset, space_id, space->name, byte_offset,
60846086
len, type);
6085-
6086-
ut_error;
60876087
}
60886088

60896089
/* Now we have made the changes in the data structures of fil_system */

storage/innobase/fsp/fsp0fsp.cc

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -670,16 +670,18 @@ fsp_header_init_fields(
670670
}
671671

672672
#ifndef UNIV_HOTBACKUP
673-
/**********************************************************************//**
674-
Initializes the space header of a new created space and creates also the
675-
insert buffer tree root if space == 0. */
673+
/** Initializes the space header of a new created space and creates also the
674+
insert buffer tree root if space == 0.
675+
@param[in] space_id space id
676+
@param[in] size current size in blocks
677+
@param[in,out] mtr min-transaction
678+
@return true on success, otherwise false. */
676679
UNIV_INTERN
677-
void
680+
bool
678681
fsp_header_init(
679-
/*============*/
680-
ulint space_id, /*!< in: space id */
681-
ulint size, /*!< in: current size in blocks */
682-
mtr_t* mtr) /*!< in/out: mini-transaction */
682+
ulint space_id,
683+
ulint size,
684+
mtr_t* mtr)
683685
{
684686
fsp_header_t* header;
685687
buf_block_t* block;
@@ -722,11 +724,15 @@ fsp_header_init(
722724
flst_init(header + FSP_SEG_INODES_FREE, mtr);
723725

724726
mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
727+
725728
if (space_id == 0) {
726729
fsp_fill_free_list(FALSE, space_id, header, mtr);
727-
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
730+
731+
if (btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
728732
0, 0, DICT_IBUF_ID_MIN + space_id,
729-
dict_ind_redundant, mtr);
733+
dict_ind_redundant, mtr) == FIL_NULL) {
734+
return (false);
735+
}
730736
} else {
731737
fsp_fill_free_list(TRUE, space_id, header, mtr);
732738
}
@@ -739,6 +745,8 @@ fsp_header_init(
739745
}
740746

741747
fil_space_release(space);
748+
749+
return (true);
742750
}
743751

744752
#endif /* !UNIV_HOTBACKUP */
@@ -2057,6 +2065,10 @@ fseg_create_general(
20572065
success = fsp_reserve_free_extents(&n_reserved, space, 2,
20582066
FSP_NORMAL, mtr);
20592067
if (!success) {
2068+
ib_logf(IB_LOG_LEVEL_ERROR,
2069+
"Reserving %d free extents failed"
2070+
" could reserve only " ULINTPF " extents.",
2071+
2, n_reserved);
20602072
return(NULL);
20612073
}
20622074
}
@@ -2066,6 +2078,8 @@ fseg_create_general(
20662078
inode = fsp_alloc_seg_inode(space_header, mtr);
20672079

20682080
if (inode == NULL) {
2081+
ib_logf(IB_LOG_LEVEL_ERROR,
2082+
"Allocation of a new file segment inode page failed.");
20692083

20702084
goto funct_exit;
20712085
}
@@ -2095,6 +2109,9 @@ fseg_create_general(
20952109
inode, 0, FSP_UP, mtr, mtr);
20962110

20972111
if (block == NULL) {
2112+
ib_logf(IB_LOG_LEVEL_ERROR,
2113+
"Allocation of a free page from space " ULINTPF " failed.",
2114+
space);
20982115

20992116
fsp_free_seg_inode(space, zip_size, inode, mtr);
21002117

storage/innobase/handler/ha_innodb.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,6 +3353,7 @@ innobase_init(
33533353
char *default_path;
33543354
uint format_id;
33553355
ulong num_pll_degree;
3356+
ulint min_size = 0;
33563357

33573358
DBUG_ENTER("innobase_init");
33583359
handlerton *innobase_hton= (handlerton*) p;
@@ -3563,6 +3564,19 @@ innobase_init(
35633564
goto error;
35643565
}
35653566

3567+
/* All doublewrite buffer pages must fit to first system
3568+
datafile and first datafile must be at least 3M. */
3569+
min_size = ut_max((3*1024*1024U), (192U*UNIV_PAGE_SIZE));
3570+
3571+
if ((srv_data_file_sizes[0]*1024*1024) < min_size) {
3572+
sql_print_error(
3573+
"InnoDB: first datafile is too small current=" ULINTPF
3574+
"M it should be at least " ULINTPF "M.",
3575+
srv_data_file_sizes[0],
3576+
min_size / (1024 * 1024));
3577+
goto mem_free_and_error;
3578+
}
3579+
35663580
/* -------------- All log files ---------------------------*/
35673581

35683582
/* The default dir for log files is the datadir of MySQL */

storage/innobase/include/fsp0fsp.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -520,16 +520,20 @@ fsp_header_init_fields(
520520
ulint space_id, /*!< in: space id */
521521
ulint flags); /*!< in: tablespace flags (FSP_SPACE_FLAGS):
522522
0, or table->flags if newer than COMPACT */
523-
/**********************************************************************//**
524-
Initializes the space header of a new created space and creates also the
525-
insert buffer tree root if space == 0. */
523+
/** Initializes the space header of a new created space and creates also the
524+
insert buffer tree root if space == 0.
525+
@param[in] space_id space id
526+
@param[in] size current size in blocks
527+
@param[in,out] mtr min-transaction
528+
@return true on success, otherwise false. */
526529
UNIV_INTERN
527-
void
530+
bool
528531
fsp_header_init(
529-
/*============*/
530-
ulint space, /*!< in: space id */
531-
ulint size, /*!< in: current size in blocks */
532-
mtr_t* mtr); /*!< in/out: mini-transaction */
532+
ulint space_id,
533+
ulint size,
534+
mtr_t* mtr)
535+
MY_ATTRIBUTE((warn_unused_result));
536+
533537
/**********************************************************************//**
534538
Increases the space size field of a space. */
535539
UNIV_INTERN

storage/innobase/row/row0mysql.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3590,9 +3590,15 @@ row_truncate_table_for_mysql(
35903590
} while (index);
35913591

35923592
mtr_start_trx(&mtr, trx);
3593-
fsp_header_init(space_id,
3593+
bool ret = fsp_header_init(space_id,
35943594
FIL_IBD_FILE_INITIAL_SIZE, &mtr);
35953595
mtr_commit(&mtr);
3596+
3597+
if (!ret) {
3598+
table->file_unreadable = true;
3599+
err = DB_ERROR;
3600+
goto funct_exit;
3601+
}
35963602
}
35973603
} else {
35983604
/* Lock all index trees for this table, as we will

storage/innobase/srv/srv0start.cc

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,39 @@ UNIV_INTERN mysql_pfs_key_t srv_master_thread_key;
188188
UNIV_INTERN mysql_pfs_key_t srv_purge_thread_key;
189189
#endif /* UNIV_PFS_THREAD */
190190

191+
/** Innobase start-up aborted. Perform cleanup actions.
192+
@param[in] create_new_db TRUE if new db is being created
193+
@param[in] file File name
194+
@param[in] line Line number
195+
@param[in] err Reason for aborting InnoDB startup
196+
@return DB_SUCCESS or error code. */
197+
static
198+
dberr_t
199+
srv_init_abort(
200+
bool create_new_db,
201+
const char* file,
202+
ulint line,
203+
dberr_t err)
204+
{
205+
if (create_new_db) {
206+
ib_logf(IB_LOG_LEVEL_ERROR,
207+
"Database creation was aborted"
208+
" at %s [" ULINTPF "]"
209+
" with error %s. You may need"
210+
" to delete the ibdata1 file before trying to start"
211+
" up again.",
212+
file, line, ut_strerr(err));
213+
} else {
214+
ib_logf(IB_LOG_LEVEL_ERROR,
215+
"Plugin initialization aborted"
216+
" at %s [" ULINTPF "]"
217+
" with error %s.",
218+
file, line, ut_strerr(err));
219+
}
220+
221+
return(err);
222+
}
223+
191224
/*********************************************************************//**
192225
Convert a numeric string that optionally ends in G or M or K, to a number
193226
containing megabytes.
@@ -1528,18 +1561,26 @@ srv_undo_tablespaces_init(
15281561

15291562
if (create_new_db) {
15301563
mtr_t mtr;
1564+
bool ret=true;
15311565

15321566
mtr_start(&mtr);
15331567

15341568
/* The undo log tablespace */
15351569
for (i = 0; i < n_undo_tablespaces; ++i) {
15361570

1537-
fsp_header_init(
1571+
ret = fsp_header_init(
15381572
undo_tablespace_ids[i],
15391573
SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr);
1574+
if (!ret) {
1575+
break;
1576+
}
15401577
}
15411578

15421579
mtr_commit(&mtr);
1580+
1581+
if (!ret) {
1582+
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
1583+
}
15431584
}
15441585

15451586
return(DB_SUCCESS);
@@ -2378,10 +2419,14 @@ innobase_start_or_create_for_mysql(void)
23782419

23792420
mtr_start(&mtr);
23802421

2381-
fsp_header_init(0, sum_of_new_sizes, &mtr);
2422+
bool ret = fsp_header_init(0, sum_of_new_sizes, &mtr);
23822423

23832424
mtr_commit(&mtr);
23842425

2426+
if (!ret) {
2427+
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
2428+
}
2429+
23852430
/* To maintain backward compatibility we create only
23862431
the first rollback segment before the double write buffer.
23872432
All the remaining rollback segments will be created later,
@@ -2809,6 +2854,9 @@ innobase_start_or_create_for_mysql(void)
28092854
/* Can only happen if server is read only. */
28102855
ut_a(srv_read_only_mode);
28112856
srv_undo_logs = ULONG_UNDEFINED;
2857+
} else if (srv_available_undo_logs < srv_undo_logs) {
2858+
/* Should due to out of file space. */
2859+
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
28122860
}
28132861

28142862
if (!srv_read_only_mode) {

0 commit comments

Comments
 (0)