diff options
author | unknown <kevin.lewis@oracle.com> | 2011-12-08 13:32:19 -0600 |
---|---|---|
committer | unknown <kevin.lewis@oracle.com> | 2011-12-08 13:32:19 -0600 |
commit | 7532976dd99ab89061d6f39910d25a760908c44b (patch) | |
tree | a28ae3cb32a73274c8dd8f9183f38a2b3962f417 /storage | |
parent | 8bb893f5c31b7b61abdea998cab5bed73dce6c9a (diff) | |
download | mariadb-git-7532976dd99ab89061d6f39910d25a760908c44b.tar.gz |
Bug #13116225 LIVE DOWNGRADE CRASHES WITH INNODB_PAGE_SIZE=4K
This bug ensures that a live downgrade from an InnoDB 5.6 with WL5756 and
a database created with innodb-page-size=8k or 4k will make a version 5.5
installation politely refuse to start. Instead of crashing or giving some
indication about a corrupted database, it will indicate the page size
difference.
This patch takes only that part of the Wl5756 patch that is needed to
protect against opening a tablespace that is stamped with a different
page size.
It also contains the change in dict_index_find_on_id_low() just in case
a database with another page size is created by recompiling a pre-WL5756
InnoDB.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/dict/dict0dict.c | 5 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.c | 36 | ||||
-rw-r--r-- | storage/innobase/fsp/fsp0fsp.c | 67 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 17 | ||||
-rw-r--r-- | storage/innobase/include/fsp0fsp.h | 102 | ||||
-rw-r--r-- | storage/innobase/include/fsp0fsp.ic | 34 | ||||
-rw-r--r-- | storage/innobase/srv/srv0start.c | 24 |
7 files changed, 193 insertions, 92 deletions
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 19f1e145085..9dc3cef229e 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -911,6 +911,11 @@ dict_index_find_on_id_low( dict_table_t* table; dict_index_t* index; + /* This can happen if the system tablespace is the wrong page size */ + if (dict_sys == NULL) { + return(NULL); + } + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); while (table) { diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 196f4bd3f42..2e4c6aeeb60 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -1803,36 +1803,44 @@ fil_write_flushed_lsn_to_data_files( } /*******************************************************************//** -Reads the flushed lsn and arch no fields from a data file at database -startup. */ +Reads the flushed lsn, arch no, and tablespace flag fields from a data +file at database startup. */ UNIV_INTERN void -fil_read_flushed_lsn_and_arch_log_no( -/*=================================*/ +fil_read_first_page( +/*================*/ os_file_t data_file, /*!< in: open data file */ ibool one_read_already, /*!< in: TRUE if min and max parameters below already contain sensible data */ + ulint* flags, /*!< out: tablespace flags */ #ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< in/out: */ - ulint* max_arch_log_no, /*!< in/out: */ + ulint* min_arch_log_no, /*!< out: min of archived + log numbers in data files */ + ulint* max_arch_log_no, /*!< out: max of archived + log numbers in data files */ #endif /* UNIV_LOG_ARCHIVE */ - ib_uint64_t* min_flushed_lsn, /*!< in/out: */ - ib_uint64_t* max_flushed_lsn) /*!< in/out: */ + ib_uint64_t* min_flushed_lsn, /*!< out: min of flushed + lsn values in data files */ + ib_uint64_t* max_flushed_lsn) /*!< out: max of flushed + lsn values in data files */ { byte* buf; - byte* buf2; + page_t* page; ib_uint64_t flushed_lsn; - buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); + buf = ut_malloc(2 * UNIV_PAGE_SIZE); /* Align the memory for a possible read from a raw device */ - buf = ut_align(buf2, UNIV_PAGE_SIZE); + page = ut_align(buf, UNIV_PAGE_SIZE); - os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); + os_file_read(data_file, page, 0, 0, UNIV_PAGE_SIZE); - flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN); + *flags = mach_read_from_4(page + + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS); - ut_free(buf2); + flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); + + ut_free(buf); if (!one_read_already) { *min_flushed_lsn = flushed_lsn; diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 3f09732a676..2d626405c5c 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -50,67 +50,6 @@ Created 11/29/1995 Heikki Tuuri #include "dict0mem.h" -#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header - within a file page */ - -/* The data structures in files are defined just as byte strings in C */ -typedef byte fsp_header_t; -typedef byte xdes_t; - -/* SPACE HEADER - ============ - -File space header data structure: this data structure is contained in the -first page of a space. The space for this header is reserved in every extent -descriptor page, but used only in the first. */ - -/*-------------------------------------*/ -#define FSP_SPACE_ID 0 /* space id */ -#define FSP_NOT_USED 4 /* this field contained a value up to - which we know that the modifications - in the database have been flushed to - the file space; not used now */ -#define FSP_SIZE 8 /* Current size of the space in - pages */ -#define FSP_FREE_LIMIT 12 /* Minimum page number for which the - free list has not been initialized: - the pages >= this limit are, by - definition, free; note that in a - single-table tablespace where size - < 64 pages, this number is 64, i.e., - we have initialized the space - about the first extent, but have not - physically allocted those pages to the - file */ -#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */ -#define FSP_FRAG_N_USED 20 /* number of used pages in the - FSP_FREE_FRAG list */ -#define FSP_FREE 24 /* list of free extents */ -#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE) - /* list of partially free extents not - belonging to any segment */ -#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE) - /* list of full extents not belonging - to any segment */ -#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE) - /* 8 bytes which give the first unused - segment id */ -#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE) - /* list of pages containing segment - headers, where all the segment inode - slots are reserved */ -#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE) - /* list of pages containing segment - headers, where not all the segment - header slots are reserved */ -/*-------------------------------------*/ -/* File space header size */ -#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE) - -#define FSP_FREE_ADD 4 /* this many free extents are added - to the free list from above - FSP_FREE_LIMIT at a time */ - /* FILE SEGMENT INODE ================== diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 3a6336f1a01..d50b0cb4162 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -328,18 +328,23 @@ Reads the flushed lsn and arch no fields from a data file at database startup. */ UNIV_INTERN void -fil_read_flushed_lsn_and_arch_log_no( -/*=================================*/ +fil_read_first_page( +/*================*/ os_file_t data_file, /*!< in: open data file */ ibool one_read_already, /*!< in: TRUE if min and max parameters below already contain sensible data */ + ulint* flags, /*!< out: tablespace flags */ #ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< in/out: */ - ulint* max_arch_log_no, /*!< in/out: */ + ulint* min_arch_log_no, /*!< out: min of archived + log numbers in data files */ + ulint* max_arch_log_no, /*!< out: max of archived + log numbers in data files */ #endif /* UNIV_LOG_ARCHIVE */ - ib_uint64_t* min_flushed_lsn, /*!< in/out: */ - ib_uint64_t* max_flushed_lsn); /*!< in/out: */ + ib_uint64_t* min_flushed_lsn, /*!< out: min of flushed + lsn values in data files */ + ib_uint64_t* max_flushed_lsn); /*!< out: max of flushed + lsn values in data files */ /*******************************************************************//** Increments the count of pending insert buffer page merges, if space is not being deleted. diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 7abd3914eda..d5e235aa870 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -34,6 +34,90 @@ Created 12/18/1995 Heikki Tuuri #include "page0types.h" #include "fsp0types.h" +/* @defgroup fsp_flags InnoDB Tablespace Flag Constants @{ */ + +/** Number of flag bits used to indicate the tablespace page size */ +#define FSP_FLAGS_WIDTH_PAGE_SSIZE 4 +/** Zero relative shift position of the PAGE_SSIZE field */ +#define FSP_FLAGS_POS_PAGE_SSIZE 6 +/** Bit mask of the PAGE_SSIZE field */ +#define FSP_FLAGS_MASK_PAGE_SSIZE \ + ((~(~0 << FSP_FLAGS_WIDTH_PAGE_SSIZE)) \ + << FSP_FLAGS_POS_PAGE_SSIZE) +/** Return the value of the PAGE_SSIZE field */ +#define FSP_FLAGS_GET_PAGE_SSIZE(flags) \ + ((flags & FSP_FLAGS_MASK_PAGE_SSIZE) \ + >> FSP_FLAGS_POS_PAGE_SSIZE) + +/* @} */ + +/* @defgroup Tablespace Header Constants (moved from fsp0fsp.c) @{ */ + +/** Offset of the space header within a file page */ +#define FSP_HEADER_OFFSET FIL_PAGE_DATA + +/* The data structures in files are defined just as byte strings in C */ +typedef byte fsp_header_t; +typedef byte xdes_t; + +/* SPACE HEADER + ============ + +File space header data structure: this data structure is contained in the +first page of a space. The space for this header is reserved in every extent +descriptor page, but used only in the first. */ + +/*-------------------------------------*/ +#define FSP_SPACE_ID 0 /* space id */ +#define FSP_NOT_USED 4 /* this field contained a value up to + which we know that the modifications + in the database have been flushed to + the file space; not used now */ +#define FSP_SIZE 8 /* Current size of the space in + pages */ +#define FSP_FREE_LIMIT 12 /* Minimum page number for which the + free list has not been initialized: + the pages >= this limit are, by + definition, free; note that in a + single-table tablespace where size + < 64 pages, this number is 64, i.e., + we have initialized the space + about the first extent, but have not + physically allocted those pages to the + file */ +#define FSP_SPACE_FLAGS 16 /* fsp_space_t.flags, similar to + dict_table_t::flags */ +#define FSP_FRAG_N_USED 20 /* number of used pages in the + FSP_FREE_FRAG list */ +#define FSP_FREE 24 /* list of free extents */ +#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE) + /* list of partially free extents not + belonging to any segment */ +#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE) + /* list of full extents not belonging + to any segment */ +#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE) + /* 8 bytes which give the first unused + segment id */ +#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE) + /* list of pages containing segment + headers, where all the segment inode + slots are reserved */ +#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE) + /* list of pages containing segment + headers, where not all the segment + header slots are reserved */ +/*-------------------------------------*/ +/* File space header size */ +#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE) + +#define FSP_FREE_ADD 4 /* this many free extents are added + to the free list from above + FSP_FREE_LIMIT at a time */ +/* @} */ + +/* @} */ + /**********************************************************************//** Initializes the file space system. */ UNIV_INTERN @@ -352,6 +436,18 @@ fseg_print( mtr_t* mtr); /*!< in: mtr */ #endif /* UNIV_BTR_PRINT */ +/********************************************************************//** +Extract the page size from tablespace flags. +This feature, storing the page_ssize into the tablespace flags, is added +to InnoDB 5.6.4. This is here only to protect against a crash if a newer +database is opened with this code branch. +@return page size of the tablespace in bytes */ +UNIV_INLINE +ulint +fsp_flags_get_page_size( +/*====================*/ + ulint flags); /*!< in: tablespace flags */ + #ifndef UNIV_NONINL #include "fsp0fsp.ic" #endif diff --git a/storage/innobase/include/fsp0fsp.ic b/storage/innobase/include/fsp0fsp.ic index 434c370b527..c92111a9d89 100644 --- a/storage/innobase/include/fsp0fsp.ic +++ b/storage/innobase/include/fsp0fsp.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -43,3 +43,31 @@ fsp_descr_page( return(UNIV_UNLIKELY((page_no & (zip_size - 1)) == FSP_XDES_OFFSET)); } +/********************************************************************//** +Extract the page size from tablespace flags. +This feature, storing the page_ssize into the tablespace flags, is added +to InnoDB 5.6.4. This is here only to protect against a crash if a newer +database is opened with this code branch. +@return page size of the tablespace in bytes */ +UNIV_INLINE +ulint +fsp_flags_get_page_size( +/*====================*/ + ulint flags) /*!< in: tablespace flags */ +{ + ulint page_size = 0; + ulint ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags); + + /* Convert from a 'log2 minus 9' to a page size in bytes. */ + if (UNIV_UNLIKELY(ssize)) { + page_size = (512 << ssize); + + ut_ad(page_size <= UNIV_PAGE_SIZE); + } else { + /* If the page size was not stored, then it is the + original 16k. */ + page_size = UNIV_PAGE_SIZE; + } + + return(page_size); +} diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index cf11e75b8e0..edc655e93b9 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -733,6 +733,7 @@ open_or_create_data_files( ibool one_created = FALSE; ulint size; ulint size_high; + ulint flags; ulint rounded_size_pages; char name[10000]; @@ -914,12 +915,31 @@ open_or_create_data_files( return(DB_ERROR); } skip_size_check: - fil_read_flushed_lsn_and_arch_log_no( - files[i], one_opened, + fil_read_first_page( + files[i], one_opened, &flags, #ifdef UNIV_LOG_ARCHIVE min_arch_log_no, max_arch_log_no, #endif /* UNIV_LOG_ARCHIVE */ min_flushed_lsn, max_flushed_lsn); + + if (UNIV_PAGE_SIZE + != fsp_flags_get_page_size(flags)) { + + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: data file %s" + " uses page size %lu,\n", + name, + fsp_flags_get_page_size(flags)); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: but the only supported" + " page size in this release is=%lu\n", + (ulong) UNIV_PAGE_SIZE); + + return(DB_ERROR); + } + one_opened = TRUE; } else { /* We created the data file and now write it full of |