Cleanup of MDEV-12600: crash during install_db with innodb_page_size=32K and ibdata1=3M

The doublewrite buffer pages must fit in the first InnoDB system
tablespace data file. The checks that were added in the initial patch
(commit 112b21da37dad0fbb28bc65f9ab5a3ba6c0c2186)
were at too high level and did not cover all cases.

innodb.log_data_file_size: Test all innodb_page_size combinations.

fsp_header_init(): Never return an error. Move the change buffer creation
to the only caller that needs to do it.

btr_create(): Clean up the logic. Remove the error log messages.

buf_dblwr_create(): Try to return an error on non-fatal failure.
Check that the first data file is big enough for creating the
doublewrite buffers.

buf_dblwr_process(): Check if the doublewrite buffer is available.
Display the message only if it is available.

recv_recovery_from_checkpoint_start_func(): Remove a redundant message
about FIL_PAGE_FILE_FLUSH_LSN mismatch when crash recovery has already
been initiated.

fil_report_invalid_page_access(): Simplify the message.

fseg_create_general(): Do not emit messages to the error log.

innobase_init(): Revert the changes.

trx_rseg_create(): Refactor (no functional change).
This commit is contained in:
Marko Mäkelä 2017-06-06 14:59:42 +03:00
parent 68890fe7d4
commit fbeb9489cd
30 changed files with 323 additions and 433 deletions

View File

@ -231,6 +231,7 @@ set global innodb_buf_flush_list_now = 1;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
FOUND /\[ERROR\] InnoDB: .* in tablespace.*test.t1.*/ in mysqld.1.err
select f1, f2 from t1;
f1 f2
1 ############
@ -238,6 +239,13 @@ f1 f2
3 ////////////
4 ------------
5 ............
# Test End
# ---------------------------------------------------------------
drop table t1;
#
# MDEV-12600 crash during install_db with innodb_page_size=32K
# and ibdata1=3M
#
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND /\[ERROR\] InnoDB: Cannot create doublewrite buffer/ in mysqld.1.err

View File

@ -4,7 +4,7 @@
--echo # PAGE OF SYSTEM TABLESPACE
--echo #
--source include/have_innodb.inc
--source include/innodb_page_size.inc
--source include/have_debug.inc
--source include/not_embedded.inc
@ -15,12 +15,17 @@ call mtr.add_suppression("space header page consists of zero bytes.*test.t1");
call mtr.add_suppression("checksum mismatch in tablespace.*test.t1");
call mtr.add_suppression("Current page size .* != page size on page");
call mtr.add_suppression("innodb-page-size mismatch in tablespace.*test.t1");
call mtr.add_suppression("Trying to recover page.*from the doublewrite buffer");
call mtr.add_suppression("InnoDB: New log files created");
call mtr.add_suppression("InnoDB: Cannot create doublewrite buffer: the first file in innodb_data_file_path must be at least (3|6|12)M\\.");
call mtr.add_suppression("InnoDB: Database creation was aborted");
call mtr.add_suppression("Plugin 'InnoDB' (init function returned error|registration as a STORAGE ENGINE failed)");
--enable_query_log
--source include/restart_mysqld.inc
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
let MYSQLD_DATADIR=`select @@datadir`;
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
let SEARCH_RANGE= -50000;
show variables like 'innodb_doublewrite';
show variables like 'innodb_fil_make_page_dirty_debug';
@ -393,9 +398,38 @@ EOF
--source include/start_mysqld.inc
check table t1;
--let SEARCH_PATTERN= \[ERROR\] InnoDB: .* in tablespace.*test.t1.*
--source include/search_pattern_in_file.inc
select f1, f2 from t1;
--echo # Test End
--echo # ---------------------------------------------------------------
drop table t1;
--echo #
--echo # MDEV-12600 crash during install_db with innodb_page_size=32K
--echo # and ibdata1=3M
--echo #
let bugdir= $MYSQLTEST_VARDIR/tmp/doublewrite;
--mkdir $bugdir
let $check_no_innodb=SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
--let $ibp=--innodb-log-group-home-dir=$bugdir --innodb-data-home-dir=$bugdir
--let $ibd=$ibp --innodb-undo-tablespaces=0 --innodb-log-files-in-group=2
--let $ibp=$ibp --innodb-data-file-path=ibdata1:1M;ibdata2:1M:autoextend
--let $restart_parameters= $ibp
--source include/restart_mysqld.inc
eval $check_no_innodb;
--let SEARCH_PATTERN= \[ERROR\] InnoDB: Cannot create doublewrite buffer
--source include/search_pattern_in_file.inc
--let $restart_parameters=
--source include/restart_mysqld.inc
--remove_file $bugdir/ibdata1
--remove_file $bugdir/ibdata2
--remove_file $bugdir/ib_logfile0
--remove_file $bugdir/ib_logfile1
--rmdir $bugdir

View File

@ -1,2 +1,2 @@
--loose-innodb-sys-indexes
--innodb-data-file-path=ibdata1:3M:autoextend
--innodb-data-file-path=ibdata1:1M:autoextend

View File

@ -1,4 +1,4 @@
--source include/have_innodb.inc
--source include/innodb_page_size.inc
--source include/not_embedded.inc
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;

View File

@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, 2017, MariaDB Corporation
Copyright (c) 2014, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1684,9 +1684,7 @@ btr_create(
dict_index_t* index, /*!< in: index */
mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint page_no;
buf_block_t* block;
buf_frame_t* frame;
page_t* page;
page_zip_des_t* page_zip;
@ -1702,9 +1700,7 @@ btr_create(
IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
if (ibuf_hdr_block == NULL) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the first ibuf header page failed.");
return (FIL_NULL);
return(FIL_NULL);
}
buf_block_dbg_add_level(
@ -1721,11 +1717,16 @@ btr_create(
IBUF_TREE_ROOT_PAGE_NO,
FSP_UP, mtr);
if (!block) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the tree root page segment failed.");
if (block == NULL) {
return(FIL_NULL);
}
ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO);
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
flst_init(block->frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
mtr);
} else {
#ifdef UNIV_BLOB_DEBUG
if ((type & DICT_CLUSTERED) && !index->blobs) {
@ -1738,41 +1739,18 @@ btr_create(
block = fseg_create(space, 0,
PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
if (!block) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the btree segment failed.");
if (block == NULL) {
return(FIL_NULL);
}
}
if (block == NULL) {
return(FIL_NULL);
}
page_no = buf_block_get_page_no(block);
frame = buf_block_get_frame(block);
if (type & DICT_IBUF) {
/* It is an insert buffer tree: initialize the free list */
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
} else {
/* It is a non-ibuf tree: create a file segment for leaf
pages */
buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
if (!fseg_create(space, page_no,
if (!fseg_create(space, buf_block_get_page_no(block),
PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
/* Not enough space for new segment, free root
segment before return. */
btr_free_root(space, zip_size, page_no, mtr);
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the non-ibuf tree segment for leaf pages failed.");
btr_free_root(space, zip_size,
buf_block_get_page_no(block), mtr);
return(FIL_NULL);
}
@ -1816,7 +1794,7 @@ btr_create(
ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE);
return(page_no);
return(buf_block_get_page_no(block));
}
/************************************************************//**

View File

@ -175,13 +175,14 @@ buf_dblwr_init(
mem_zalloc(buf_size * sizeof(void*)));
}
/****************************************************************//**
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */
/** Create the doublewrite buffer if the doublewrite buffer header
is not present in the TRX_SYS page.
@return whether the operation succeeded
@retval true if the doublewrite buffer exists or was created
@retval false if the creation failed (too small first data file) */
UNIV_INTERN
void
buf_dblwr_create(void)
/*==================*/
bool
buf_dblwr_create()
{
buf_block_t* block2;
buf_block_t* new_block;
@ -194,8 +195,7 @@ buf_dblwr_create(void)
if (buf_dblwr) {
/* Already inited */
return;
return(true);
}
start_again:
@ -213,39 +213,59 @@ start_again:
mtr_commit(&mtr);
buf_dblwr_being_created = FALSE;
return;
return(true);
}
ib_logf(IB_LOG_LEVEL_INFO,
"Doublewrite buffer not found: creating new");
if (buf_pool_get_curr_size()
< ((TRX_SYS_DOUBLEWRITE_BLOCKS * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
+ FSP_EXTENT_SIZE / 2 + 100)
* UNIV_PAGE_SIZE)) {
ib_logf(IB_LOG_LEVEL_FATAL,
"Cannot create doublewrite buffer: you must "
"increase your buffer pool size. Cannot continue "
"operation.");
ib_logf(IB_LOG_LEVEL_ERROR,
"Cannot create doublewrite buffer: "
"innodb_buffer_pool_size is too small.");
mtr_commit(&mtr);
return(false);
} else {
fil_space_t* space = fil_space_acquire(TRX_SYS_SPACE);
const bool fail = UT_LIST_GET_FIRST(space->chain)->size
< 3 * FSP_EXTENT_SIZE;
fil_space_release(space);
if (fail) {
goto too_small;
}
}
block2 = fseg_create(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
TRX_SYS_DOUBLEWRITE
+ TRX_SYS_DOUBLEWRITE_FSEG, &mtr);
if (block2 == NULL) {
too_small:
ib_logf(IB_LOG_LEVEL_ERROR,
"Cannot create doublewrite buffer: "
"the first file in innodb_data_file_path"
" must be at least %luM.",
3 * (FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) >> 20);
mtr_commit(&mtr);
return(false);
}
ib_logf(IB_LOG_LEVEL_INFO,
"Doublewrite buffer not found: creating new");
/* FIXME: After this point, the doublewrite buffer creation
is not atomic. The doublewrite buffer should not exist in
the InnoDB system tablespace file in the first place.
It could be located in separate optional file(s) in a
user-specified location. */
/* fseg_create acquires a second latch on the page,
therefore we must declare it: */
buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK);
if (block2 == NULL) {
ib_logf(IB_LOG_LEVEL_FATAL,
"Cannot create doublewrite buffer: you must "
"increase your tablespace size. "
"Cannot continue operation.");
}
fseg_header = doublewrite + TRX_SYS_DOUBLEWRITE_FSEG;
prev_page_no = 0;
@ -482,6 +502,14 @@ buf_dblwr_process()
byte* unaligned_read_buf;
recv_dblwr_t& recv_dblwr = recv_sys->dblwr;
if (!buf_dblwr) {
return;
}
ib_logf(IB_LOG_LEVEL_INFO,
"Restoring possible half-written data pages "
"from the doublewrite buffer...");
unaligned_read_buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
read_buf = static_cast<byte*>(

View File

@ -321,13 +321,9 @@ dict_build_table_def_step(
mtr_start(&mtr);
bool res = fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
mtr_commit(&mtr);
if (!res) {
return (DB_ERROR);
}
} else {
/* Create in the system tablespace: disallow Barracuda
features by keeping only the first bit which says whether

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2014, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -5812,21 +5812,19 @@ fil_report_invalid_page_access(
ulint len, /*!< in: I/O length */
ulint type) /*!< in: I/O type */
{
ib_logf(IB_LOG_LEVEL_ERROR,
ib_logf(IB_LOG_LEVEL_FATAL,
"Trying to access page number " ULINTPF
" in space " ULINTPF
" space name %s,"
" which is outside the tablespace bounds."
" Byte offset " ULINTPF ", len " ULINTPF " i/o type " ULINTPF ".",
" Byte offset " ULINTPF ", len " ULINTPF
" i/o type " ULINTPF ".%s",
block_offset, space_id, space_name,
byte_offset, len, type);
ib_logf(IB_LOG_LEVEL_FATAL,
"If you get this error at mysqld startup,"
" please check that"
" your my.cnf matches the ibdata files"
" that you have in the"
" MySQL server.");
byte_offset, len, type,
space_id == 0 && !srv_was_started
? "Please check that the configuration matches"
" the InnoDB system tablespace location (ibdata files)"
: "");
}
/********************************************************************//**

View File

@ -670,18 +670,13 @@ fsp_header_init_fields(
}
#ifndef UNIV_HOTBACKUP
/** Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0.
/** Initialize a tablespace header.
@param[in] space_id space id
@param[in] size current size in blocks
@param[in,out] mtr min-transaction
@return true on success, otherwise false. */
@param[in,out] mtr mini-transaction */
UNIV_INTERN
bool
fsp_header_init(
ulint space_id,
ulint size,
mtr_t* mtr)
void
fsp_header_init(ulint space_id, ulint size, mtr_t* mtr)
{
fsp_header_t* header;
buf_block_t* block;
@ -725,17 +720,7 @@ fsp_header_init(
mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
if (space_id == 0) {
fsp_fill_free_list(FALSE, space_id, header, mtr);
if (btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
0, 0, DICT_IBUF_ID_MIN + space_id,
dict_ind_redundant, mtr) == FIL_NULL) {
return (false);
}
} else {
fsp_fill_free_list(TRUE, space_id, header, mtr);
}
fsp_fill_free_list(space_id != TRX_SYS_SPACE, space_id, header, mtr);
fil_space_t* space = fil_space_acquire(space_id);
ut_ad(space);
@ -745,8 +730,6 @@ fsp_header_init(
}
fil_space_release(space);
return (true);
}
#endif /* !UNIV_HOTBACKUP */
@ -2065,10 +2048,6 @@ fseg_create_general(
success = fsp_reserve_free_extents(&n_reserved, space, 2,
FSP_NORMAL, mtr);
if (!success) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Reserving %d free extents failed"
" could reserve only " ULINTPF " extents.",
2, n_reserved);
return(NULL);
}
}
@ -2078,9 +2057,6 @@ fseg_create_general(
inode = fsp_alloc_seg_inode(space_header, mtr);
if (inode == NULL) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of a new file segment inode page failed.");
goto funct_exit;
}
@ -2109,9 +2085,6 @@ fseg_create_general(
inode, 0, FSP_UP, mtr, mtr);
if (block == NULL) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of a free page from space " ULINTPF " failed.",
space);
fsp_free_seg_inode(space, zip_size, inode, mtr);

View File

@ -3353,7 +3353,6 @@ innobase_init(
char *default_path;
uint format_id;
ulong num_pll_degree;
ulint min_size = 0;
DBUG_ENTER("innobase_init");
handlerton *innobase_hton= (handlerton*) p;
@ -3564,19 +3563,6 @@ mem_free_and_error:
goto error;
}
/* All doublewrite buffer pages must fit to first system
datafile and first datafile must be at least 3M. */
min_size = ut_max((3*1024*1024U), (192U*UNIV_PAGE_SIZE));
if ((srv_data_file_sizes[0]*1024*1024) < min_size) {
sql_print_error(
"InnoDB: first datafile is too small current=" ULINTPF
"M it should be at least " ULINTPF "M.",
srv_data_file_sizes[0],
min_size / (1024 * 1024));
goto mem_free_and_error;
}
/* -------------- All log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -39,13 +39,15 @@ extern buf_dblwr_t* buf_dblwr;
/** Set to TRUE when the doublewrite buffer is being created */
extern ibool buf_dblwr_being_created;
/****************************************************************//**
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */
/** Create the doublewrite buffer if the doublewrite buffer header
is not present in the TRX_SYS page.
@return whether the operation succeeded
@retval true if the doublewrite buffer exists or was created
@retval false if the creation failed (too small first data file) */
UNIV_INTERN
void
buf_dblwr_create(void);
/*==================*/
bool
buf_dblwr_create()
MY_ATTRIBUTE((warn_unused_result));
/****************************************************************//**
At a database startup initializes the doublewrite buffer memory structure if

View File

@ -520,19 +520,13 @@ fsp_header_init_fields(
ulint space_id, /*!< in: space id */
ulint flags); /*!< in: tablespace flags (FSP_SPACE_FLAGS):
0, or table->flags if newer than COMPACT */
/** Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0.
/** Initialize a tablespace header.
@param[in] space_id space id
@param[in] size current size in blocks
@param[in,out] mtr min-transaction
@return true on success, otherwise false. */
@param[in,out] mtr mini-transaction */
UNIV_INTERN
bool
fsp_header_init(
ulint space_id,
ulint size,
mtr_t* mtr)
MY_ATTRIBUTE((warn_unused_result));
void
fsp_header_init(ulint space_id, ulint size, mtr_t* mtr);
/**********************************************************************//**
Increases the space size field of a space. */

View File

@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -124,13 +125,13 @@ trx_rseg_mem_free(
/*==============*/
trx_rseg_t* rseg); /*!< in, own: instance to free */
/*********************************************************************
Creates a rollback segment. */
/** Create a rollback segment.
@param[in] space undo tablespace ID
@return pointer to new rollback segment
@retval NULL on failure */
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(
/*============*/
ulint space); /*!< in: id of UNDO tablespace */
trx_rseg_create(ulint space);
/********************************************************************
Get the number of unique rollback tablespaces in use except space id 0.

View File

@ -2914,11 +2914,6 @@ recv_init_crash_recovery(void)
possible */
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
ib_logf(IB_LOG_LEVEL_INFO,
"Restoring possible half-written data pages "
"from the doublewrite buffer...");
buf_dblwr_process();
/* Spawn the background thread to flush dirty pages
@ -3179,24 +3174,6 @@ recv_recovery_from_checkpoint_start_func(
user about recovery: */
if (checkpoint_lsn != flushed_lsn) {
if (checkpoint_lsn < flushed_lsn) {
ib_logf(IB_LOG_LEVEL_WARN,
"The log sequence number "
"in the ibdata files is higher "
"than the log sequence number "
"in the ib_logfiles! Are you sure "
"you are using the right "
"ib_logfiles to start up the database. "
"Log sequence number in the "
"ib_logfiles is " LSN_PF ", log"
"sequence number stamped "
"to ibdata file header is " LSN_PF ".",
checkpoint_lsn,
flushed_lsn);
}
if (!recv_needed_recovery) {
ib_logf(IB_LOG_LEVEL_INFO,
"The log sequence number "

View File

@ -3590,15 +3590,9 @@ row_truncate_table_for_mysql(
} while (index);
mtr_start_trx(&mtr, trx);
bool ret = fsp_header_init(space_id,
fsp_header_init(space_id,
FIL_IBD_FILE_INITIAL_SIZE, &mtr);
mtr_commit(&mtr);
if (!ret) {
table->file_unreadable = true;
err = DB_ERROR;
goto funct_exit;
}
}
} else {
/* Lock all index trees for this table, as we will

View File

@ -1561,26 +1561,18 @@ srv_undo_tablespaces_init(
if (create_new_db) {
mtr_t mtr;
bool ret=true;
mtr_start(&mtr);
/* The undo log tablespace */
for (i = 0; i < n_undo_tablespaces; ++i) {
ret = fsp_header_init(
fsp_header_init(
undo_tablespace_ids[i],
SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr);
if (!ret) {
break;
}
}
mtr_commit(&mtr);
if (!ret) {
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
}
}
return(DB_SUCCESS);
@ -2419,14 +2411,24 @@ files_checked:
mtr_start(&mtr);
bool ret = fsp_header_init(0, sum_of_new_sizes, &mtr);
fsp_header_init(0, sum_of_new_sizes, &mtr);
compile_time_assert(TRX_SYS_SPACE == 0);
compile_time_assert(IBUF_SPACE_ID == 0);
ulint ibuf_root = btr_create(
DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
0, 0, DICT_IBUF_ID_MIN,
dict_ind_redundant, &mtr);
mtr_commit(&mtr);
if (!ret) {
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
if (ibuf_root == FIL_NULL) {
return(srv_init_abort(true, __FILE__, __LINE__,
DB_ERROR));
}
ut_ad(ibuf_root == IBUF_TREE_ROOT_PAGE_NO);
/* To maintain backward compatibility we create only
the first rollback segment before the double write buffer.
All the remaining rollback segments will be created later,
@ -2812,10 +2814,9 @@ files_checked:
/* fprintf(stderr, "Max allowed record size %lu\n",
page_get_free_space_of_empty() / 2); */
if (buf_dblwr == NULL) {
/* Create the doublewrite buffer to a new tablespace */
buf_dblwr_create();
if (!buf_dblwr_create()) {
return(srv_init_abort(create_new_db, __FILE__, __LINE__,
DB_ERROR));
}
/* Here the double write buffer has already been created and so

View File

@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -293,14 +294,13 @@ trx_rseg_create_instance(
}
}
/*********************************************************************
Creates a rollback segment.
@return pointer to new rollback segment if create successful */
/** Create a rollback segment.
@param[in] space undo tablespace ID
@return pointer to new rollback segment
@retval NULL on failure */
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(
/*============*/
ulint space) /*!< in: id of UNDO tablespace */
trx_rseg_create(ulint space)
{
mtr_t mtr;
ulint slot_no;
@ -323,25 +323,21 @@ trx_rseg_create(
page_no = trx_rseg_header_create(
space, 0, ULINT_MAX, slot_no, &mtr);
if (page_no == FIL_NULL) {
mtr_commit(&mtr);
return (rseg);
if (page_no != FIL_NULL) {
sys_header = trx_sysf_get(&mtr);
id = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
ut_a(id == space);
zip_size = space ? fil_space_get_zip_size(space) : 0;
rseg = trx_rseg_mem_create(
slot_no, space, zip_size, page_no,
purge_sys->ib_bh, &mtr);
}
sys_header = trx_sysf_get(&mtr);
id = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
ut_a(id == space);
zip_size = space ? fil_space_get_zip_size(space) : 0;
rseg = trx_rseg_mem_create(
slot_no, space, zip_size, page_no,
purge_sys->ib_bh, &mtr);
}
mtr_commit(&mtr);
return(rseg);
}

View File

@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, 2017, MariaDB Corporation
Copyright (c) 2014, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1703,9 +1703,7 @@ btr_create(
dict_index_t* index, /*!< in: index */
mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint page_no;
buf_block_t* block;
buf_frame_t* frame;
page_t* page;
page_zip_des_t* page_zip;
@ -1721,9 +1719,7 @@ btr_create(
IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
if (ibuf_hdr_block == NULL) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the first ibuf header page failed.");
return (FIL_NULL);
return(FIL_NULL);
}
buf_block_dbg_add_level(
@ -1740,11 +1736,16 @@ btr_create(
IBUF_TREE_ROOT_PAGE_NO,
FSP_UP, mtr);
if (!block) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the tree root page segment failed.");
if (block == NULL) {
return(FIL_NULL);
}
ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO);
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
flst_init(block->frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
mtr);
} else {
#ifdef UNIV_BLOB_DEBUG
if ((type & DICT_CLUSTERED) && !index->blobs) {
@ -1757,41 +1758,18 @@ btr_create(
block = fseg_create(space, 0,
PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
if (!block) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the btree segment failed.");
if (block == NULL) {
return(FIL_NULL);
}
}
if (block == NULL) {
return(FIL_NULL);
}
page_no = buf_block_get_page_no(block);
frame = buf_block_get_frame(block);
if (type & DICT_IBUF) {
/* It is an insert buffer tree: initialize the free list */
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
} else {
/* It is a non-ibuf tree: create a file segment for leaf
pages */
buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
if (!fseg_create(space, page_no,
if (!fseg_create(space, buf_block_get_page_no(block),
PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
/* Not enough space for new segment, free root
segment before return. */
btr_free_root(space, zip_size, page_no, mtr);
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of the non-ibuf tree segment for leaf pages failed.");
btr_free_root(space, zip_size,
buf_block_get_page_no(block), mtr);
return(FIL_NULL);
}
@ -1835,7 +1813,7 @@ btr_create(
ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE);
return(page_no);
return(buf_block_get_page_no(block));
}
/************************************************************//**

View File

@ -175,13 +175,14 @@ buf_dblwr_init(
mem_zalloc(buf_size * sizeof(void*)));
}
/****************************************************************//**
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */
/** Create the doublewrite buffer if the doublewrite buffer header
is not present in the TRX_SYS page.
@return whether the operation succeeded
@retval true if the doublewrite buffer exists or was created
@retval false if the creation failed (too small first data file) */
UNIV_INTERN
void
buf_dblwr_create(void)
/*==================*/
bool
buf_dblwr_create()
{
buf_block_t* block2;
buf_block_t* new_block;
@ -194,8 +195,7 @@ buf_dblwr_create(void)
if (buf_dblwr) {
/* Already inited */
return;
return(true);
}
start_again:
@ -213,39 +213,59 @@ start_again:
mtr_commit(&mtr);
buf_dblwr_being_created = FALSE;
return;
return(true);
}
ib_logf(IB_LOG_LEVEL_INFO,
"Doublewrite buffer not found: creating new");
if (buf_pool_get_curr_size()
< ((TRX_SYS_DOUBLEWRITE_BLOCKS * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
+ FSP_EXTENT_SIZE / 2 + 100)
* UNIV_PAGE_SIZE)) {
ib_logf(IB_LOG_LEVEL_FATAL,
"Cannot create doublewrite buffer: you must "
"increase your buffer pool size. Cannot continue "
"operation.");
ib_logf(IB_LOG_LEVEL_ERROR,
"Cannot create doublewrite buffer: "
"innodb_buffer_pool_size is too small.");
mtr_commit(&mtr);
return(false);
} else {
fil_space_t* space = fil_space_acquire(TRX_SYS_SPACE);
const bool fail = UT_LIST_GET_FIRST(space->chain)->size
< 3 * FSP_EXTENT_SIZE;
fil_space_release(space);
if (fail) {
goto too_small;
}
}
block2 = fseg_create(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
TRX_SYS_DOUBLEWRITE
+ TRX_SYS_DOUBLEWRITE_FSEG, &mtr);
if (block2 == NULL) {
too_small:
ib_logf(IB_LOG_LEVEL_ERROR,
"Cannot create doublewrite buffer: "
"the first file in innodb_data_file_path"
" must be at least %luM.",
3 * (FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) >> 20);
mtr_commit(&mtr);
return(false);
}
ib_logf(IB_LOG_LEVEL_INFO,
"Doublewrite buffer not found: creating new");
/* FIXME: After this point, the doublewrite buffer creation
is not atomic. The doublewrite buffer should not exist in
the InnoDB system tablespace file in the first place.
It could be located in separate optional file(s) in a
user-specified location. */
/* fseg_create acquires a second latch on the page,
therefore we must declare it: */
buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK);
if (block2 == NULL) {
ib_logf(IB_LOG_LEVEL_FATAL,
"Cannot create doublewrite buffer: you must "
"increase your tablespace size. "
"Cannot continue operation.");
}
fseg_header = doublewrite + TRX_SYS_DOUBLEWRITE_FSEG;
prev_page_no = 0;
@ -482,6 +502,14 @@ buf_dblwr_process()
byte* unaligned_read_buf;
recv_dblwr_t& recv_dblwr = recv_sys->dblwr;
if (!buf_dblwr) {
return;
}
ib_logf(IB_LOG_LEVEL_INFO,
"Restoring possible half-written data pages "
"from the doublewrite buffer...");
unaligned_read_buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
read_buf = static_cast<byte*>(

View File

@ -323,13 +323,9 @@ dict_build_table_def_step(
mtr_start(&mtr);
bool res = fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
mtr_commit(&mtr);
if(!res) {
return (DB_ERROR);
}
} else {
/* Create in the system tablespace: disallow Barracuda
features by keeping only the first bit which says whether

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2014, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -6115,21 +6115,19 @@ fil_report_invalid_page_access(
ulint len, /*!< in: I/O length */
ulint type) /*!< in: I/O type */
{
ib_logf(IB_LOG_LEVEL_ERROR,
ib_logf(IB_LOG_LEVEL_FATAL,
"Trying to access page number " ULINTPF
" in space " ULINTPF
" space name %s,"
" which is outside the tablespace bounds."
" Byte offset " ULINTPF ", len " ULINTPF " i/o type " ULINTPF ".",
" Byte offset " ULINTPF ", len " ULINTPF
" i/o type " ULINTPF ".%s",
block_offset, space_id, space_name,
byte_offset, len, type);
ib_logf(IB_LOG_LEVEL_FATAL,
"If you get this error at mysqld startup,"
" please check that"
" your my.cnf matches the ibdata files"
" that you have in the"
" MySQL server.");
byte_offset, len, type,
space_id == 0 && !srv_was_started
? "Please check that the configuration matches"
" the InnoDB system tablespace location (ibdata files)"
: "");
}
/********************************************************************//**

View File

@ -673,18 +673,13 @@ fsp_header_init_fields(
}
#ifndef UNIV_HOTBACKUP
/** Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0.
/** Initialize a tablespace header.
@param[in] space_id space id
@param[in] size current size in blocks
@param[in,out] mtr min-transaction
@return true on success, otherwise false. */
@param[in,out] mtr mini-transaction */
UNIV_INTERN
bool
fsp_header_init(
ulint space_id,
ulint size,
mtr_t* mtr)
void
fsp_header_init(ulint space_id, ulint size, mtr_t* mtr)
{
fsp_header_t* header;
buf_block_t* block;
@ -728,17 +723,7 @@ fsp_header_init(
mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
if (space_id == 0) {
fsp_fill_free_list(FALSE, space_id, header, mtr);
if (btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
0, 0, DICT_IBUF_ID_MIN + space_id,
dict_ind_redundant, mtr) == FIL_NULL) {
return (false);
}
} else {
fsp_fill_free_list(TRUE, space_id, header, mtr);
}
fsp_fill_free_list(space_id != TRX_SYS_SPACE, space_id, header, mtr);
fil_space_t* space = fil_space_acquire(space_id);
ut_ad(space);
@ -748,8 +733,6 @@ fsp_header_init(
}
fil_space_release(space);
return (true);
}
#endif /* !UNIV_HOTBACKUP */
@ -2074,10 +2057,6 @@ fseg_create_general(
success = fsp_reserve_free_extents(&n_reserved, space, 2,
FSP_NORMAL, mtr);
if (!success) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Reserving %d free extents failed"
" could reserve only " ULINTPF " extents.",
2, n_reserved);
return(NULL);
}
}
@ -2087,9 +2066,6 @@ fseg_create_general(
inode = fsp_alloc_seg_inode(space_header, mtr);
if (inode == NULL) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of a new file segment inode page failed.");
goto funct_exit;
}
@ -2118,9 +2094,6 @@ fseg_create_general(
inode, 0, FSP_UP, mtr, mtr);
if (block == NULL) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Allocation of a free page from space " ULINTPF " failed.",
space);
fsp_free_seg_inode(space, zip_size, inode, mtr);

View File

@ -3770,7 +3770,6 @@ innobase_init(
char *default_path;
uint format_id;
ulong num_pll_degree;
ulint min_size = 0;
DBUG_ENTER("innobase_init");
handlerton *innobase_hton= (handlerton*) p;
@ -4021,19 +4020,6 @@ mem_free_and_error:
goto error;
}
/* All doublewrite buffer pages must fit to first system
datafile and first datafile must be at least 3M. */
min_size = ut_max((3*1024*1024U), (192U*UNIV_PAGE_SIZE));
if ((srv_data_file_sizes[0]*1024*1024) < min_size) {
sql_print_error(
"InnoDB: first datafile is too small current=" ULINTPF
"M it should be at least " ULINTPF "M.",
srv_data_file_sizes[0],
min_size / (1024 * 1024));
goto mem_free_and_error;
}
/* -------------- All log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -39,13 +39,15 @@ extern buf_dblwr_t* buf_dblwr;
/** Set to TRUE when the doublewrite buffer is being created */
extern ibool buf_dblwr_being_created;
/****************************************************************//**
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */
/** Create the doublewrite buffer if the doublewrite buffer header
is not present in the TRX_SYS page.
@return whether the operation succeeded
@retval true if the doublewrite buffer exists or was created
@retval false if the creation failed (too small first data file) */
UNIV_INTERN
void
buf_dblwr_create(void);
/*==================*/
bool
buf_dblwr_create()
MY_ATTRIBUTE((warn_unused_result));
/****************************************************************//**
At a database startup initializes the doublewrite buffer memory structure if

View File

@ -519,19 +519,13 @@ fsp_header_init_fields(
ulint space_id, /*!< in: space id */
ulint flags); /*!< in: tablespace flags (FSP_SPACE_FLAGS):
0, or table->flags if newer than COMPACT */
/** Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0.
/** Initialize a tablespace header.
@param[in] space_id space id
@param[in] size current size in blocks
@param[in,out] mtr min-transaction
@return true on success, otherwise false. */
@param[in,out] mtr mini-transaction */
UNIV_INTERN
bool
fsp_header_init(
ulint space_id,
ulint size,
mtr_t* mtr)
MY_ATTRIBUTE((warn_unused_result));
void
fsp_header_init(ulint space_id, ulint size, mtr_t* mtr);
/**********************************************************************//**
Increases the space size field of a space. */

View File

@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -124,13 +125,13 @@ trx_rseg_mem_free(
/*==============*/
trx_rseg_t* rseg); /*!< in, own: instance to free */
/*********************************************************************
Creates a rollback segment. */
/** Create a rollback segment.
@param[in] space undo tablespace ID
@return pointer to new rollback segment
@retval NULL on failure */
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(
/*============*/
ulint space); /*!< in: id of UNDO tablespace */
trx_rseg_create(ulint space);
/********************************************************************
Get the number of unique rollback tablespaces in use except space id 0.

View File

@ -3004,11 +3004,6 @@ recv_init_crash_recovery(void)
possible */
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
ib_logf(IB_LOG_LEVEL_INFO,
"Restoring possible half-written data pages "
"from the doublewrite buffer...");
buf_dblwr_process();
/* Spawn the background thread to flush dirty pages
@ -3276,24 +3271,6 @@ recv_recovery_from_checkpoint_start_func(
user about recovery: */
if (checkpoint_lsn != flushed_lsn) {
if (checkpoint_lsn <flushed_lsn) {
ib_logf(IB_LOG_LEVEL_WARN,
"The log sequence number "
"in the ibdata files is higher "
"than the log sequence number "
"in the ib_logfiles! Are you sure "
"you are using the right "
"ib_logfiles to start up the database. "
"Log sequence number in the "
"ib_logfiles is " LSN_PF ", log"
"sequence number stamped "
"to ibdata file header is " LSN_PF ".",
checkpoint_lsn,
flushed_lsn);
}
if (!recv_needed_recovery) {
ib_logf(IB_LOG_LEVEL_INFO,
"The log sequence number "

View File

@ -3614,15 +3614,9 @@ row_truncate_table_for_mysql(
} while (index);
mtr_start_trx(&mtr, trx);
bool ret = fsp_header_init(space_id,
fsp_header_init(space_id,
FIL_IBD_FILE_INITIAL_SIZE, &mtr);
mtr_commit(&mtr);
if (!ret) {
table->file_unreadable = true;
err = DB_ERROR;
goto funct_exit;
}
}
} else {
/* Lock all index trees for this table, as we will

View File

@ -1601,26 +1601,18 @@ srv_undo_tablespaces_init(
if (create_new_db) {
mtr_t mtr;
bool ret=true;
mtr_start(&mtr);
/* The undo log tablespace */
for (i = 0; i < n_undo_tablespaces; ++i) {
ret = fsp_header_init(
fsp_header_init(
undo_tablespace_ids[i],
SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr);
if (!ret) {
break;
}
}
mtr_commit(&mtr);
if (!ret) {
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
}
}
return(DB_SUCCESS);
@ -2507,14 +2499,24 @@ files_checked:
mtr_start(&mtr);
bool ret = fsp_header_init(0, sum_of_new_sizes, &mtr);
fsp_header_init(0, sum_of_new_sizes, &mtr);
compile_time_assert(TRX_SYS_SPACE == 0);
compile_time_assert(IBUF_SPACE_ID == 0);
ulint ibuf_root = btr_create(
DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
0, 0, DICT_IBUF_ID_MIN,
dict_ind_redundant, &mtr);
mtr_commit(&mtr);
if (!ret) {
return (srv_init_abort(create_new_db, __FILE__, __LINE__, DB_ERROR));
if (ibuf_root == FIL_NULL) {
return(srv_init_abort(true, __FILE__, __LINE__,
DB_ERROR));
}
ut_ad(ibuf_root == IBUF_TREE_ROOT_PAGE_NO);
/* To maintain backward compatibility we create only
the first rollback segment before the double write buffer.
All the remaining rollback segments will be created later,
@ -2901,10 +2903,9 @@ files_checked:
/* fprintf(stderr, "Max allowed record size %lu\n",
page_get_free_space_of_empty() / 2); */
if (buf_dblwr == NULL) {
/* Create the doublewrite buffer to a new tablespace */
buf_dblwr_create();
if (!buf_dblwr_create()) {
return(srv_init_abort(create_new_db, __FILE__, __LINE__,
DB_ERROR));
}
/* Here the double write buffer has already been created and so

View File

@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -293,14 +294,13 @@ trx_rseg_create_instance(
}
}
/*********************************************************************
Creates a rollback segment.
@return pointer to new rollback segment if create successful */
/** Create a rollback segment.
@param[in] space undo tablespace ID
@return pointer to new rollback segment
@retval NULL on failure */
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(
/*============*/
ulint space) /*!< in: id of UNDO tablespace */
trx_rseg_create(ulint space)
{
mtr_t mtr;
ulint slot_no;
@ -323,25 +323,21 @@ trx_rseg_create(
page_no = trx_rseg_header_create(
space, 0, ULINT_MAX, slot_no, &mtr);
if (page_no == FIL_NULL) {
mtr_commit(&mtr);
return (rseg);
if (page_no != FIL_NULL) {
sys_header = trx_sysf_get(&mtr);
id = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
ut_a(id == space);
zip_size = space ? fil_space_get_zip_size(space) : 0;
rseg = trx_rseg_mem_create(
slot_no, space, zip_size, page_no,
purge_sys->ib_bh, &mtr);
}
sys_header = trx_sysf_get(&mtr);
id = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
ut_a(id == space);
zip_size = space ? fil_space_get_zip_size(space) : 0;
rseg = trx_rseg_mem_create(
slot_no, space, zip_size, page_no,
purge_sys->ib_bh, &mtr);
}
mtr_commit(&mtr);
return(rseg);
}