Commit 61a33895 authored by calvin's avatar calvin

branches/zip:

Implement the system tablespace tagging described on the wiki:
https://svn.innodb.com/innobase/InnoDB_version_and_feature_compatibility

A brief description of the changes:

* The file format tag will be saved in the trx system page, starting at
  (UNIV_PAGE_SIZE - 16) for 8 bytes.
* The configuration parameter innodb_file_format_check is introduced.
  This variable can be set to on/off and any of the supported file
  formats in the configuration file, but can only be set to any of
  the supported file formats during runtime. The default is on.
* During table create/open, check the current file format against
  the max in file_format_max. If the current file format is newer,
  update file_format_max and tag the system tablespace with the
  newer one in a normal mtr.
* During startup, write the tag to the error log and check it against
  DICT_TF_FORMAT_MAX. Refuse to start with error, if
  -- DICT_TF_FORMAT_MAX < the tag, and
  -- innodb_file_format_check is ON
  Print out a warning , if
  -- DICT_TF_FORMAT_MAX < the tag, but
  -- innodb_file_format_check is off
* The system tablespace tag is re-settable using:
  set innodb_file_format_check = <file_format>

Approved by:	Sunny
parent 719cc1c2
This diff is collapsed.
...@@ -61,7 +61,9 @@ extern char* srv_arch_dir; ...@@ -61,7 +61,9 @@ extern char* srv_arch_dir;
dictionary tables are in the system tablespace 0 */ dictionary tables are in the system tablespace 0 */
extern my_bool srv_file_per_table; extern my_bool srv_file_per_table;
/* The file format to use on new *.ibd files. */ /* The file format to use on new *.ibd files. */
extern uint srv_file_format; extern ulint srv_file_format;
/* Whether to check file format during startup.*/
extern ulint srv_check_file_format_at_startup;
/* Place locks to records only i.e. do not use next-key locking except /* Place locks to records only i.e. do not use next-key locking except
on duplicate key checking and foreign key checking */ on duplicate key checking and foreign key checking */
extern ibool srv_locks_unsafe_for_binlog; extern ibool srv_locks_unsafe_for_binlog;
......
...@@ -389,6 +389,8 @@ or row lock! */ ...@@ -389,6 +389,8 @@ or row lock! */
trx_i_s_cache_t::rw_lock */ trx_i_s_cache_t::rw_lock */
#define SYNC_TRX_I_S_LAST_READ 1900 /* Used for #define SYNC_TRX_I_S_LAST_READ 1900 /* Used for
trx_i_s_cache_t::last_read_mutex */ trx_i_s_cache_t::last_read_mutex */
#define SYNC_FILE_FORMAT_TAG 1200 /* Used to serialize access to the
file format tag */
#define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve #define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve
this in X-mode, implicit or backround this in X-mode, implicit or backround
operations purge, rollback, foreign operations purge, rollback, foreign
......
...@@ -298,7 +298,59 @@ UNIV_INTERN ...@@ -298,7 +298,59 @@ UNIV_INTERN
void void
trx_sys_print_mysql_master_log_pos(void); trx_sys_print_mysql_master_log_pos(void);
/*====================================*/ /*====================================*/
/*********************************************************************
Initializes the tablespace tag system. */
UNIV_INTERN
void
trx_sys_file_format_init(void);
/*==========================*/
/*********************************************************************
Closes the tablespace tag system. */
UNIV_INTERN
void
trx_sys_file_format_close(void);
/*===========================*/
/*********************************************************************
Get the name representation of the file format from its id. */
UNIV_INTERN
const char*
trx_sys_file_format_id_to_name(
/*===========================*/
/* out: pointer to the name */
const uint id); /* in: id of the file format */
/*********************************************************************
Set the file format tag unconditonally. */
UNIV_INTERN
ibool
trx_sys_file_format_max_set(
/*===========================*/
/* out: TRUE if value updated */
ulint file_format, /* in: file format id */
char** name); /* out: max format name */
/*********************************************************************
Get the name representation of the file format from its id. */
UNIV_INTERN
const char*
trx_sys_file_format_max_get(void);
/*=============================*/
/* out: pointer to the max format name */
/*********************************************************************
Check for the max file format tag stored on disk. */
UNIV_INTERN
ulint
trx_sys_file_format_max_check(
/*==========================*/
/* out: DB_SUCCESS or error code */
ulint max_format_id); /* in: the max format id to check */
/************************************************************************
Update the file format tag in the tablespace to the max value. */
UNIV_INTERN
ibool
trx_sys_file_format_max_update(
/*===========================*/
/* out: TRUE if value updated */
uint flags, /* in: flags of the table */
char** name); /* out: max format name */
/* The automatically created system rollback segment has this id */ /* The automatically created system rollback segment has this id */
#define TRX_SYS_SYSTEM_RSEG_ID 0 #define TRX_SYS_SYSTEM_RSEG_ID 0
...@@ -397,6 +449,15 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ ...@@ -397,6 +449,15 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
#define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE #define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE
/* The offset of the file format tag on the trx system header page */
#define TRX_SYS_FILE_FORMAT_TAG (UNIV_PAGE_SIZE - 16)
/* We use these random constants to reduce the probability of reading
garbage (from previous versions) that maps to an actual format id. We
use these as bit masks at the time of reading and writing from/to disk. */
#define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW 3645922177UL
#define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH 2745987765UL
/* Doublewrite control struct */ /* Doublewrite control struct */
struct trx_doublewrite_struct{ struct trx_doublewrite_struct{
mutex_t mutex; /* mutex protecting the first_free field and mutex_t mutex; /* mutex protecting the first_free field and
......
...@@ -358,3 +358,36 @@ drop table t8, t9; ...@@ -358,3 +358,36 @@ drop table t8, t9;
set global innodb_file_per_table=0; set global innodb_file_per_table=0;
set global innodb_file_format=Antelope; set global innodb_file_format=Antelope;
set innodb_strict_mode=0; set innodb_strict_mode=0;
set global innodb_file_per_table=on;
set global innodb_file_format=`Barracuda`;
set global innodb_file_format_check=`Antelope`;
create table normal_table (
c1 int
) engine = innodb;
select @@innodb_file_format_check;
@@innodb_file_format_check
Antelope
create table zip_table (
c1 int
) engine = innodb key_block_size = 8;
select @@innodb_file_format_check;
@@innodb_file_format_check
Barracuda
set global innodb_file_format_check=`Antelope`;
select @@innodb_file_format_check;
@@innodb_file_format_check
Antelope
show table status;
select @@innodb_file_format_check;
@@innodb_file_format_check
Barracuda
set global innodb_file_format_check=`Cheetah`;
ERROR HY000: Incorrect arguments to SET
set global innodb_file_format_check=`on`;
ERROR HY000: Incorrect arguments to SET
set global innodb_file_format_check=`off`;
ERROR HY000: Incorrect arguments to SET
select @@innodb_file_format_check;
@@innodb_file_format_check
Barracuda
drop table normal_table, zip_table;
...@@ -270,3 +270,33 @@ drop table t8, t9; ...@@ -270,3 +270,33 @@ drop table t8, t9;
eval set global innodb_file_per_table=$per_table; eval set global innodb_file_per_table=$per_table;
eval set global innodb_file_format=$format; eval set global innodb_file_format=$format;
eval set innodb_strict_mode=$mode; eval set innodb_strict_mode=$mode;
#
# Testing of tablespace tagging
#
-- disable_info
set global innodb_file_per_table=on;
set global innodb_file_format=`Barracuda`;
set global innodb_file_format_check=`Antelope`;
create table normal_table (
c1 int
) engine = innodb;
select @@innodb_file_format_check;
create table zip_table (
c1 int
) engine = innodb key_block_size = 8;
select @@innodb_file_format_check;
set global innodb_file_format_check=`Antelope`;
select @@innodb_file_format_check;
-- disable_result_log
show table status;
-- enable_result_log
select @@innodb_file_format_check;
-- error ER_WRONG_ARGUMENTS
set global innodb_file_format_check=`Cheetah`;
-- error ER_WRONG_ARGUMENTS
set global innodb_file_format_check=`on`;
-- error ER_WRONG_ARGUMENTS
set global innodb_file_format_check=`off`;
select @@innodb_file_format_check;
drop table normal_table, zip_table;
-- disable_result_log
...@@ -89,7 +89,12 @@ UNIV_INTERN char* srv_arch_dir = NULL; ...@@ -89,7 +89,12 @@ UNIV_INTERN char* srv_arch_dir = NULL;
dictionary tables are in the system tablespace 0 */ dictionary tables are in the system tablespace 0 */
UNIV_INTERN my_bool srv_file_per_table; UNIV_INTERN my_bool srv_file_per_table;
/* The file format to use on new *.ibd files. */ /* The file format to use on new *.ibd files. */
UNIV_INTERN uint srv_file_format = 0; UNIV_INTERN ulint srv_file_format = 0;
/* Whether to check file format during startup a value of
DICT_TF_FORMAT_MAX + 1 means no checking ie. FALSE. The default is to
set it to the highest format we support. */
UNIV_INTERN ulint srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX;
#if DICT_TF_FORMAT_51 #if DICT_TF_FORMAT_51
# error "DICT_TF_FORMAT_51 must be 0!" # error "DICT_TF_FORMAT_51 must be 0!"
#endif #endif
......
...@@ -1408,6 +1408,8 @@ innobase_start_or_create_for_mysql(void) ...@@ -1408,6 +1408,8 @@ innobase_start_or_create_for_mysql(void)
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
} }
trx_sys_file_format_init();
if (create_new_db) { if (create_new_db) {
mtr_start(&mtr); mtr_start(&mtr);
fsp_header_init(0, sum_of_new_sizes, &mtr); fsp_header_init(0, sum_of_new_sizes, &mtr);
...@@ -1444,6 +1446,16 @@ innobase_start_or_create_for_mysql(void) ...@@ -1444,6 +1446,16 @@ innobase_start_or_create_for_mysql(void)
recv_recovery_from_archive_finish(); recv_recovery_from_archive_finish();
#endif /* UNIV_LOG_ARCHIVE */ #endif /* UNIV_LOG_ARCHIVE */
} else { } else {
/* Check if we support the max format that is stamped
on the system tablespace. */
err = trx_sys_file_format_max_check(
srv_check_file_format_at_startup);
if (err != DB_SUCCESS) {
return(err);
}
/* We always try to do a recovery, even if the database had /* We always try to do a recovery, even if the database had
been shut down normally: this is the normal startup path */ been shut down normally: this is the normal startup path */
...@@ -1873,6 +1885,8 @@ innobase_shutdown_for_mysql(void) ...@@ -1873,6 +1885,8 @@ innobase_shutdown_for_mysql(void)
srv_misc_tmpfile = 0; srv_misc_tmpfile = 0;
} }
trx_sys_file_format_close();
mutex_free(&srv_monitor_file_mutex); mutex_free(&srv_monitor_file_mutex);
mutex_free(&srv_dict_tmpfile_mutex); mutex_free(&srv_dict_tmpfile_mutex);
mutex_free(&srv_misc_tmpfile_mutex); mutex_free(&srv_misc_tmpfile_mutex);
......
...@@ -1055,6 +1055,7 @@ sync_thread_add_level( ...@@ -1055,6 +1055,7 @@ sync_thread_add_level(
case SYNC_THR_LOCAL: case SYNC_THR_LOCAL:
case SYNC_ANY_LATCH: case SYNC_ANY_LATCH:
case SYNC_TRX_SYS_HEADER: case SYNC_TRX_SYS_HEADER:
case SYNC_FILE_FORMAT_TAG:
case SYNC_DOUBLEWRITE: case SYNC_DOUBLEWRITE:
case SYNC_BUF_POOL: case SYNC_BUF_POOL:
case SYNC_SEARCH_SYS: case SYNC_SEARCH_SYS:
......
...@@ -22,6 +22,17 @@ Created 3/26/1996 Heikki Tuuri ...@@ -22,6 +22,17 @@ Created 3/26/1996 Heikki Tuuri
#include "log0log.h" #include "log0log.h"
#include "os0file.h" #include "os0file.h"
/* The file format tag structure with id and name. */
struct file_format_struct{
uint id; /* id of the file format */
const char* name; /* text representation of the
file format */
mutex_t mutex; /* covers changes to the above
fields */
};
typedef struct file_format_struct file_format_t;
/* The transaction system */ /* The transaction system */
UNIV_INTERN trx_sys_t* trx_sys = NULL; UNIV_INTERN trx_sys_t* trx_sys = NULL;
UNIV_INTERN trx_doublewrite_t* trx_doublewrite = NULL; UNIV_INTERN trx_doublewrite_t* trx_doublewrite = NULL;
...@@ -53,6 +64,44 @@ InnoDB. */ ...@@ -53,6 +64,44 @@ InnoDB. */
UNIV_INTERN char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; UNIV_INTERN char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1; UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1;
/* List of animal names representing file format. */
static const char* file_format_name_map[] = {
"Antelope",
"Barracuda",
"Cheetah",
"Dragon",
"Elk",
"Fox",
"Gazelle",
"Hornet",
"Impala",
"Jaguar",
"Kangaroo",
"Leopard",
"Moose",
"Nautilus",
"Ocelot",
"Porpoise",
"Quail",
"Rabbit",
"Shark",
"Tiger",
"Urchin",
"Viper",
"Whale",
"Xenops",
"Yak",
"Zebra"
};
/* The number of elements in the file format name array. */
static const ulint FILE_FORMAT_NAME_N =
sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
/* This is used to track the maximum file format id known to InnoDB. It's
updated via SET GLOBAL innodb_file_format_check = 'x' or when we open
or create a table. */
static file_format_t file_format_max;
/******************************************************************** /********************************************************************
Determines if a page number is located inside the doublewrite buffer. */ Determines if a page number is located inside the doublewrite buffer. */
...@@ -1008,3 +1057,246 @@ trx_sys_create(void) ...@@ -1008,3 +1057,246 @@ trx_sys_create(void)
trx_sys_init_at_db_start(); trx_sys_init_at_db_start();
} }
/*********************************************************************
Update the file format tag. */
static
ibool
trx_sys_file_format_max_write(
/*==========================*/
/* out: always TRUE */
ulint format_id, /* in: file format id */
char** name) /* out: max file format name, can
be NULL */
{
mtr_t mtr;
byte* ptr;
buf_block_t* block;
ulint tag_value_low;
mtr_start(&mtr);
block = buf_page_get(
TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
file_format_max.id = format_id;
file_format_max.name = trx_sys_file_format_id_to_name(format_id);
ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
tag_value_low = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW;
if (name) {
*name = (char*) file_format_max.name;
}
mlog_write_dulint(
ptr,
ut_dulint_create(TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH,
tag_value_low),
&mtr);
mtr_commit(&mtr);
return(TRUE);
}
/*********************************************************************
Read the file format tag. */
static
ulint
trx_sys_file_format_max_read(void)
/*==============================*/
/* out: the file format */
{
mtr_t mtr;
const byte* ptr;
const buf_block_t* block;
ulint format_id;
dulint file_format_id;
/* Since this is called during the startup phase it's safe to
read the value without a covering mutex. */
mtr_start(&mtr);
block = buf_page_get(
TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
file_format_id = mach_read_from_8(ptr);
mtr_commit(&mtr);
format_id = file_format_id.low - TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW;
if (file_format_id.high != TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH
|| format_id >= FILE_FORMAT_NAME_N) {
/* Either it has never been tagged, or garbage in it.
Reset the tag in either case. */
format_id = DICT_TF_FORMAT_51;
trx_sys_file_format_max_write(format_id, NULL);
}
return(format_id);
}
/*********************************************************************
Get the name representation of the file format from its id. */
UNIV_INTERN
const char*
trx_sys_file_format_id_to_name(
/*===========================*/
/* out: pointer to the name */
const uint id) /* in: id of the file format */
{
ut_a(id < FILE_FORMAT_NAME_N);
return(file_format_name_map[id]);
}
/*********************************************************************
Check for the max file format tag stored on disk. Note: If max_format_id
is == DICT_TF_FORMAT_MAX + 1 then we only print a warning. */
UNIV_INTERN
ulint
trx_sys_file_format_max_check(
/*==========================*/
/* out: DB_SUCCESS or error code */
ulint max_format_id) /* in: max format id to check */
{
ulint format_id;
/* Check the file format in the tablespace. Do not try to
recover if the file format is not supported by the engine
unless forced by the user. */
format_id = trx_sys_file_format_max_read();
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: highest supported file format is %s.\n",
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
if (format_id > DICT_TF_FORMAT_MAX) {
ut_a(format_id < FILE_FORMAT_NAME_N);
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: %s: the system tablespace is in a file "
"format that this version doesn't support - %s\n",
((max_format_id <= DICT_TF_FORMAT_MAX)
? "Error" : "Warning"),
trx_sys_file_format_id_to_name(format_id));
if (max_format_id <= DICT_TF_FORMAT_MAX) {
return(DB_ERROR);
}
}
format_id = (format_id > max_format_id) ? format_id : max_format_id;
/* We don't need a mutex here, as this function should only
be called once at start up. */
file_format_max.id = format_id;
file_format_max.name = trx_sys_file_format_id_to_name(format_id);
return(DB_SUCCESS);
}
/*********************************************************************
Set the file format id unconditionally except if it's already the
same value. */
UNIV_INTERN
ibool
trx_sys_file_format_max_set(
/*========================*/
/* out: TRUE if value updated */
ulint format_id, /* in: file format id */
char** name) /* out: max file format name */
{
ibool ret = FALSE;
ut_a(name);
ut_a(format_id <= DICT_TF_FORMAT_MAX);
mutex_enter(&file_format_max.mutex);
/* Only update if not already same value. */
if (format_id != file_format_max.id) {
ret = trx_sys_file_format_max_write(format_id, name);
}
mutex_exit(&file_format_max.mutex);
return(ret);
}
/************************************************************************
Update the file format tag in the tablespace only if the given format id
is greater than the known max id. */
UNIV_INTERN
ibool
trx_sys_file_format_max_update(
/*===========================*/
uint flags, /* in: flags of the table.*/
char** name) /* out: max file format name */
{
ulint format_id;
ibool ret = FALSE;
format_id = (flags & DICT_TF_FORMAT_MASK) >> DICT_TF_FORMAT_SHIFT;
ut_a(name);
ut_a(file_format_max.name != NULL);
ut_a(format_id <= DICT_TF_FORMAT_MAX);
mutex_enter(&file_format_max.mutex);
if (format_id > file_format_max.id) {
ret = trx_sys_file_format_max_write(format_id, name);
}
mutex_exit(&file_format_max.mutex);
return(ret);
}
/*********************************************************************
Get the name representation of the file format from its id. */
UNIV_INTERN
const char*
trx_sys_file_format_max_get(void)
/*=============================*/
/* out: pointer to the max format name */
{
return(file_format_max.name);
}
/*********************************************************************
Initializes the tablespace tag system. */
UNIV_INTERN
void
trx_sys_file_format_init(void)
/*==========================*/
{
mutex_create(&file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
/* We don't need a mutex here, as this function should only
be called once at start up. */
file_format_max.id = DICT_TF_FORMAT_51;
file_format_max.name = trx_sys_file_format_id_to_name(
file_format_max.id);
}
/*********************************************************************
Closes the tablespace tag system. */
UNIV_INTERN
void
trx_sys_file_format_close(void)
/*===========================*/
{
/* Does nothing at the moment */
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment