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
......@@ -115,36 +115,6 @@ static const long AUTOINC_OLD_STYLE_LOCKING = 0;
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
static const long AUTOINC_NO_LOCKING = 2;
/* List of animal names representing file format. */
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"
};
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_buffer_size,
innobase_additional_mem_pool_size, innobase_file_io_threads,
......@@ -160,6 +130,12 @@ static char* innobase_data_home_dir = NULL;
static char* innobase_data_file_path = NULL;
static char* innobase_log_group_home_dir = NULL;
static char* innobase_file_format_name = NULL;
/* Note: 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. */
static char* innobase_file_format_check = NULL;
/* The following has a misleading name: starting from 4.0.5, this also
affects Windows: */
static char* innobase_unix_file_flush_method = NULL;
......@@ -218,18 +194,38 @@ static handler *innobase_create_handler(handlerton *hton,
Validate the file format name and return its corresponding id. */
static
uint
file_format_name_lookup(
/*====================*/
/* out: valid file format id*/
const char* format_name); /* in: pointer to file format name */
innobase_file_format_name_lookup(
/*=============================*/
/* out: valid file format id */
const char* format_name); /* in: pointer to file format
name */
/****************************************************************
Validate the file format check config parameters, as a side affect it
sets the srv_check_file_format_at_startup variable. */
static
bool
innobase_file_format_check_on_off(
/*==============================*/
/* out: true if one of
"on" or "off" */
const char* format_check); /* in: parameter value */
/****************************************************************
Validate the file format check config parameters, as a side affect it
sets the srv_check_file_format_at_startup variable. */
static
bool
innobase_file_format_check_validate(
/*================================*/
/* out: true if valid
config value */
const char* format_check); /* in: parameter value */
/*****************************************************************
Check if it is a valid file format. This function is registered as
a callback with MySQL. */
static
int
innodb_file_format_check(
/*=====================*/
innodb_file_format_name_validate(
/*=============================*/
/* out: 0 for valid file
format */
THD* thd, /* in: thread handle */
......@@ -238,24 +234,55 @@ innodb_file_format_check(
void* save, /* out: immediate result
for update function */
struct st_mysql_value* value); /* in: incoming string */
/********************************************************************
Update the global variable using the "saved" value. This functions is
registered as a callback with MySQL. */
Update the system variable innodb_file_format using the "saved"
value. This function is registered as a callback with MySQL. */
static
bool
innodb_file_format_update(
/*======================*/
/* out: should never
fail since it is
already validated */
THD* thd, /* in: thread handle */
struct st_mysql_sys_var* var, /* in: pointer to
system variable */
void* var_ptr, /* out: where the
formal string goes */
void* save); /* in: immediate result
from check function */
innodb_file_format_name_update(
/*===========================*/
/* out: should never
fail since it is
already validated */
THD* thd, /* in: thread handle */
struct st_mysql_sys_var* var, /* in: pointer to
system variable */
void* var_ptr,/* out: where the
formal string goes */
void* save); /* in: immediate result
from check function */
/*****************************************************************
Check if it is a valid file format. This function is registered as
a callback with MySQL. */
static
int
innodb_file_format_check_validate(
/*==============================*/
/* out: 0 for valid file
format */
THD* thd, /* in: thread handle */
struct st_mysql_sys_var* var, /* in: pointer to system
variable */
void* save, /* out: immediate result
for update function */
struct st_mysql_value* value); /* in: incoming string */
/********************************************************************
Update the system variable innodb_file_format_check using the "saved"
value. This function is registered as a callback with MySQL. */
static
bool
innodb_file_format_check_update(
/*============================*/
/* out: should never
fail since it is
already validated */
THD* thd, /* in: thread handle */
struct st_mysql_sys_var* var, /* in: pointer to
system variable */
void* var_ptr,/* out: where the
formal string goes */
void* save); /* in: immediate result
from check function */
/********************************************************************
Return alter table flags supported in an InnoDB database. */
......@@ -1812,7 +1839,8 @@ innobase_init(
/* Validate the file format by animal name */
if (innobase_file_format_name != NULL) {
format_id = file_format_name_lookup(innobase_file_format_name);
format_id = innobase_file_format_name_lookup(
innobase_file_format_name);
if (format_id > DICT_TF_FORMAT_MAX) {
......@@ -1829,8 +1857,42 @@ innobase_init(
}
srv_file_format = format_id;
innobase_file_format_name =
(char*) file_format_name_map[srv_file_format];
/* Given the type of innobase_file_format_name we have little
choice but to cast away the constness from the returned name.
innobase_file_format_name is used in the MySQL set variable
interface and so can't be const. */
innobase_file_format_name =
(char*) trx_sys_file_format_id_to_name(format_id);
/* Process innobase_file_format_check variable */
ut_a(innobase_file_format_check != NULL);
/* As a side affect it will set srv_check_file_format_at_startup
on valid input. First we check for "on"/"off". */
if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
/* Did the user specify a format name that we support ?
As a side affect it will update the variable
srv_check_file_format_at_startup*/
if (!innobase_file_format_check_validate(
innobase_file_format_check)) {
sql_print_error("InnoDB: invalid "
"innodb_file_format_check value: "
"should be either 'on' or 'off' or "
"any value up to %s or it's "
"equivalent numeric id",
trx_sys_file_format_id_to_name(
DICT_TF_FORMAT_MAX));
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
goto error;
}
}
/* --------------------------------------------------*/
......@@ -1921,6 +1983,9 @@ innobase_init(
}
#endif /* MYSQL_DYNAMIC_PLUGIN */
/* Get the current high water mark format. */
innobase_file_format_check = (char*) trx_sys_file_format_max_get();
DBUG_RETURN(FALSE);
error:
DBUG_RETURN(TRUE);
......@@ -2793,12 +2858,20 @@ retry:
}
}
stats.block_size = 16 * 1024; /* Index block size in InnoDB: used by MySQL
in query optimization */
/* Index block size in InnoDB: used by MySQL in query optimization */
stats.block_size = 16 * 1024;
/* Init table lock structure */
thr_lock_data_init(&share->lock,&lock,(void*) 0);
if (prebuilt->table) {
/* We update the highest file format in the system table
space, if this table has higher file format setting. */
trx_sys_file_format_max_update(
prebuilt->table->flags, &innobase_file_format_check);
}
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
DBUG_RETURN(0);
......@@ -5827,6 +5900,11 @@ ha_innobase::create(
DBUG_ASSERT(innobase_table != 0);
/* We update the highest file format in the system table
space, if this table has a higher file format setting. */
trx_sys_file_format_max_update(flags, &innobase_file_format_check);
/* Note: We can't call update_thd() as prebuilt will not be
setup at this stage and so we use thd. */
......@@ -8749,13 +8827,13 @@ ha_innobase::check_if_incompatible_data(
Validate the file format name and return its corresponding id. */
static
uint
file_format_name_lookup(
/*====================*/
innobase_file_format_name_lookup(
/*=============================*/
/* out: valid file format id*/
const char* format_name) /* in: pointer to file format name */
{
uint format_id;
char* endp;
uint format_id;
ut_a(format_name != NULL);
......@@ -8776,7 +8854,7 @@ file_format_name_lookup(
format_id++) {
const char* name;
name = file_format_name_map[format_id];
name = trx_sys_file_format_id_to_name(format_id);
if (!innobase_strcasecmp(format_name, name)) {
......@@ -8788,13 +8866,66 @@ file_format_name_lookup(
return(DICT_TF_FORMAT_MAX + 1);
}
/****************************************************************
Validate the file format check value, is it one of "on" or "off",
as a side affect it sets the srv_check_file_format_at_startup variable. */
static
bool
innobase_file_format_check_on_off(
/*==============================*/
/* out: true if config value one
of "on" or "off" */
const char* format_check) /* in: parameter value */
{
bool ret = true;
if (!innobase_strcasecmp(format_check, "off")) {
/* Set the value to disable checking. */
srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
} else if (!innobase_strcasecmp(format_check, "on")) {
/* Set the value to the lowest supported format. */
srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
} else {
ret = FALSE;
}
return(ret);
}
/****************************************************************
Validate the file format check config parameters, as a side affect it
sets the srv_check_file_format_at_startup variable. */
static
bool
innobase_file_format_check_validate(
/*================================*/
/* out: true if valid config value */
const char* format_check) /* in: parameter value */
{
uint format_id;
bool ret = true;
format_id = innobase_file_format_name_lookup(format_check);
if (format_id < DICT_TF_FORMAT_MAX + 1) {
srv_check_file_format_at_startup = format_id;
} else {
ret = false;
}
return(ret);
}
/*****************************************************************
Check if it is a valid file format. This function is registered as
a callback with MySQL. */
static
int
innodb_file_format_check(
/*=====================*/
innodb_file_format_name_validate(
/*=============================*/
/* out: 0 for valid file
format */
THD* thd, /* in: thread handle */
......@@ -8804,8 +8935,8 @@ innodb_file_format_check(
for update function */
struct st_mysql_value* value) /* in: incoming string */
{
char buff[STRING_BUFFER_USUAL_SIZE];
const char* file_format_input;
char buff[STRING_BUFFER_USUAL_SIZE];
int len = sizeof(buff);
ut_a(save != NULL);
......@@ -8814,10 +8945,10 @@ innodb_file_format_check(
file_format_input = value->val_str(value, buff, &len);
if (file_format_input != NULL) {
uint format_id;
format_id = file_format_name_lookup(file_format_input);
format_id = innobase_file_format_name_lookup(
file_format_input);
if (format_id <= DICT_TF_FORMAT_MAX) {
......@@ -8830,12 +8961,12 @@ innodb_file_format_check(
}
/********************************************************************
Update the global variable using the "saved" value. This functions is
registered as a callback with MySQL. */
Update the system variable innodb_file_format using the "saved"
value. This function is registered as a callback with MySQL. */
static
bool
innodb_file_format_update(
/*======================*/
innodb_file_format_name_update(
/*===========================*/
/* out: should never
fail since it is
already validated */
......@@ -8853,7 +8984,108 @@ innodb_file_format_update(
srv_file_format = *(uint*) save;
(*(char**) var_ptr) = (char*) file_format_name_map[srv_file_format];
/* Given the type of var_ptr we have little choice but to cast
away the constness from the returned name. */
(*(char**) var_ptr) =
(char*) trx_sys_file_format_id_to_name(srv_file_format);
return(true);
}
/*****************************************************************
Check if valid argument to innodb_file_format_check. This
function is registered as a callback with MySQL. */
static
int
innodb_file_format_check_validate(
/*==============================*/
/* out: 0 for valid file
format */
THD* thd, /* in: thread handle */
struct st_mysql_sys_var* var, /* in: pointer to system
variable */
void* save, /* out: immediate result
for update function */
struct st_mysql_value* value) /* in: incoming string */
{
const char* file_format_input;
char buff[STRING_BUFFER_USUAL_SIZE];
int len = sizeof(buff);
ut_a(save != NULL);
ut_a(value != NULL);
file_format_input = value->val_str(value, buff, &len);
if (file_format_input != NULL) {
/* Check if user set on/off, we want to print a suitable
message if they did so. */
if (innobase_file_format_check_on_off(file_format_input)) {
sql_print_warning(
"InnoDB: invalid innodb_file_format_check"
"value; on/off can only be set at startup or "
"in the configuration file");
} else if (innobase_file_format_check_validate(
file_format_input)) {
uint format_id;
format_id = innobase_file_format_name_lookup(
file_format_input);
ut_a(format_id <= DICT_TF_FORMAT_MAX);
*(uint*) save = format_id;
return(0);
} else {
sql_print_warning(
"InnoDB: invalid innodb_file_format_check "
"value; can be any format up to %s "
"or it's equivalent numeric id",
trx_sys_file_format_id_to_name(
DICT_TF_FORMAT_MAX));
}
}
return(1);
}
/********************************************************************
Update the system variable innodb_file_format_check using the "saved"
value. This function is registered as a callback with MySQL. */
static
bool
innodb_file_format_check_update(
/*============================*/
/* out: should never
fail since it is
already validated */
THD* thd, /* in: thread handle */
struct st_mysql_sys_var* var, /* in: pointer to
system variable */
void* var_ptr, /* out: where the
formal string goes */
void* save) /* in: immediate result
from check function */
{
uint format_id;
ut_a(save != NULL);
ut_a(var_ptr != NULL);
format_id = *(uint*) save;
/* Update the max format id in the system tablespace. */
if (trx_sys_file_format_max_set(format_id, (char**) var_ptr)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" [Info] InnoDB: the file format in the system "
"tablespace is now set to %s.\n", *(char**) var_ptr);
}
return(true);
}
......@@ -8912,8 +9144,15 @@ static MYSQL_SYSVAR_BOOL(file_per_table, srv_file_per_table,
static MYSQL_SYSVAR_STR(file_format, innobase_file_format_name,
PLUGIN_VAR_RQCMDARG,
"File format to use for new tables in .ibd files.",
(mysql_var_check_func) &innodb_file_format_check,
(mysql_var_update_func) &innodb_file_format_update, "Antelope");
(mysql_var_check_func) &innodb_file_format_name_validate,
(mysql_var_update_func) &innodb_file_format_name_update, "Antelope");
static MYSQL_SYSVAR_STR(file_format_check, innobase_file_format_check,
PLUGIN_VAR_OPCMDARG,
"The highest file format in the tablespace.",
(mysql_var_check_func) &innodb_file_format_check_validate,
(mysql_var_update_func) &innodb_file_format_check_update,
"on");
static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
PLUGIN_VAR_OPCMDARG,
......@@ -9097,6 +9336,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(file_io_threads),
MYSQL_SYSVAR(file_per_table),
MYSQL_SYSVAR(file_format),
MYSQL_SYSVAR(file_format_check),
MYSQL_SYSVAR(flush_log_at_trx_commit),
MYSQL_SYSVAR(flush_method),
MYSQL_SYSVAR(force_recovery),
......
......@@ -61,7 +61,9 @@ extern char* srv_arch_dir;
dictionary tables are in the system tablespace 0 */
extern my_bool srv_file_per_table;
/* 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
on duplicate key checking and foreign key checking */
extern ibool srv_locks_unsafe_for_binlog;
......
......@@ -389,6 +389,8 @@ or row lock! */
trx_i_s_cache_t::rw_lock */
#define SYNC_TRX_I_S_LAST_READ 1900 /* Used for
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
this in X-mode, implicit or backround
operations purge, rollback, foreign
......
......@@ -298,7 +298,59 @@ UNIV_INTERN
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 */
#define TRX_SYS_SYSTEM_RSEG_ID 0
......@@ -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
/* 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 */
struct trx_doublewrite_struct{
mutex_t mutex; /* mutex protecting the first_free field and
......
......@@ -358,3 +358,36 @@ drop table t8, t9;
set global innodb_file_per_table=0;
set global innodb_file_format=Antelope;
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;
eval set global innodb_file_per_table=$per_table;
eval set global innodb_file_format=$format;
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;
dictionary tables are in the system tablespace 0 */
UNIV_INTERN my_bool srv_file_per_table;
/* 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
# error "DICT_TF_FORMAT_51 must be 0!"
#endif
......
......@@ -1408,6 +1408,8 @@ innobase_start_or_create_for_mysql(void)
mutex_exit(&(log_sys->mutex));
}
trx_sys_file_format_init();
if (create_new_db) {
mtr_start(&mtr);
fsp_header_init(0, sum_of_new_sizes, &mtr);
......@@ -1444,6 +1446,16 @@ innobase_start_or_create_for_mysql(void)
recv_recovery_from_archive_finish();
#endif /* UNIV_LOG_ARCHIVE */
} 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
been shut down normally: this is the normal startup path */
......@@ -1873,6 +1885,8 @@ innobase_shutdown_for_mysql(void)
srv_misc_tmpfile = 0;
}
trx_sys_file_format_close();
mutex_free(&srv_monitor_file_mutex);
mutex_free(&srv_dict_tmpfile_mutex);
mutex_free(&srv_misc_tmpfile_mutex);
......
......@@ -1055,6 +1055,7 @@ sync_thread_add_level(
case SYNC_THR_LOCAL:
case SYNC_ANY_LATCH:
case SYNC_TRX_SYS_HEADER:
case SYNC_FILE_FORMAT_TAG:
case SYNC_DOUBLEWRITE:
case SYNC_BUF_POOL:
case SYNC_SEARCH_SYS:
......
......@@ -22,6 +22,17 @@ Created 3/26/1996 Heikki Tuuri
#include "log0log.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 */
UNIV_INTERN trx_sys_t* trx_sys = NULL;
UNIV_INTERN trx_doublewrite_t* trx_doublewrite = NULL;
......@@ -53,6 +64,44 @@ InnoDB. */
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;
/* 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. */
......@@ -1008,3 +1057,246 @@ trx_sys_create(void)
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