Many files:
Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock sql/ha_innodb.cc: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/dict/dict0crea.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/dict/dict0dict.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/include/log0recv.h: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/include/row0mysql.h: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/include/srv0srv.h: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/include/trx0trx.h: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/log/log0recv.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/os/os0sync.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/os/os0thread.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/row/row0ins.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/row/row0mysql.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/row/row0purge.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/row/row0undo.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/row/row0upd.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/srv/srv0srv.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/srv/srv0start.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/trx/trx0roll.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock innobase/trx/trx0trx.c: Merge InnoDB-4.0.5b: minor improvements to foreign keys, more logical data dictionary lock
This commit is contained in:
parent
23f4865b16
commit
444d8207d9
@ -1041,7 +1041,7 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
que_t* graph;
|
||||
ulint error;
|
||||
trx_t* trx;
|
||||
char* str;
|
||||
char* str;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
@ -1060,20 +1060,24 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
trx->op_info = (char *) "creating foreign key sys tables";
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
if (table1) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: dropping incompletely created SYS_FOREIGN table\n");
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx, TRUE);
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx);
|
||||
}
|
||||
|
||||
if (table2) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n");
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS",trx,TRUE);
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS", trx);
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
@ -1122,8 +1126,8 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
fprintf(stderr,
|
||||
"InnoDB: dropping incompletely created SYS_FOREIGN tables\n");
|
||||
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx, TRUE);
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS",trx,TRUE);
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx);
|
||||
row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS", trx);
|
||||
|
||||
error = DB_MUST_GET_MORE_FILE_SPACE;
|
||||
}
|
||||
@ -1132,6 +1136,8 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
|
||||
trx->op_info = (char *) "";
|
||||
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
@ -1139,8 +1145,6 @@ dict_create_or_check_foreign_constraint_tables(void)
|
||||
"InnoDB: Foreign key constraint system tables created\n");
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
|
@ -30,13 +30,16 @@ Created 1/8/1996 Heikki Tuuri
|
||||
dict_sys_t* dict_sys = NULL; /* the dictionary system */
|
||||
|
||||
rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
|
||||
this in X-mode, implicit or backround
|
||||
this in X-mode; implicit or backround
|
||||
operations purge, rollback, foreign
|
||||
key checks reserve this in S-mode; we
|
||||
cannot trust that MySQL protects
|
||||
implicit or background operations
|
||||
from dropping a table: this is our
|
||||
mechanism */
|
||||
a table drop since MySQL does not
|
||||
know of them; therefore we need this;
|
||||
NOTE: a transaction which reserves
|
||||
this must keep book on the mode in
|
||||
trx->dict_operation_lock_mode */
|
||||
|
||||
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
|
||||
creating a table or index object */
|
||||
@ -182,6 +185,58 @@ dict_foreign_free(
|
||||
/*==============*/
|
||||
dict_foreign_t* foreign); /* in, own: foreign key struct */
|
||||
|
||||
/************************************************************************
|
||||
Checks if the database name in two table names is the same. */
|
||||
static
|
||||
ibool
|
||||
dict_tables_have_same_db(
|
||||
/*=====================*/
|
||||
/* out: TRUE if same db name */
|
||||
char* name1, /* in: table name in the form dbname '/' tablename */
|
||||
char* name2) /* in: table name in the form dbname '/' tablename */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
if (name1[i] == '/' && name2[i] == '/') {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
if (name1[i] != name2[i]) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
ut_a(0);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Return the end of table name where we have removed dbname and '/'. */
|
||||
static
|
||||
char*
|
||||
dict_remove_db_name(
|
||||
/*================*/
|
||||
/* out: table name */
|
||||
char* name) /* in: table name in the form dbname '/' tablename */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < 100000 ; i++) {
|
||||
if (name[i] == '/') {
|
||||
|
||||
return(name + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
ut_a(0);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Reserves the dictionary system mutex for MySQL. */
|
||||
|
||||
@ -1926,7 +1981,8 @@ dict_scan_col(
|
||||
|
||||
old_ptr = ptr;
|
||||
|
||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' && *ptr != '`') {
|
||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' && *ptr != '`'
|
||||
&& *ptr != '\0') {
|
||||
|
||||
ptr++;
|
||||
}
|
||||
@ -2000,7 +2056,7 @@ dict_scan_table_name(
|
||||
|
||||
old_ptr = ptr;
|
||||
|
||||
while (!isspace(*ptr) && *ptr != '(' && *ptr != '`') {
|
||||
while (!isspace(*ptr) && *ptr != '(' && *ptr != '`' && *ptr != '\0') {
|
||||
if (*ptr == '.') {
|
||||
dot_ptr = ptr;
|
||||
}
|
||||
@ -2023,17 +2079,28 @@ dict_scan_table_name(
|
||||
}
|
||||
#ifdef __WIN__
|
||||
ut_cpy_in_lower_case(second_table_name + i, old_ptr,
|
||||
ptr - old_ptr);
|
||||
ptr - old_ptr);
|
||||
#else
|
||||
ut_memcpy(second_table_name + i, old_ptr, ptr - old_ptr);
|
||||
if (srv_lower_case_table_names) {
|
||||
ut_cpy_in_lower_case(second_table_name + i, old_ptr,
|
||||
ptr - old_ptr);
|
||||
} else {
|
||||
ut_memcpy(second_table_name + i, old_ptr,
|
||||
ptr - old_ptr);
|
||||
}
|
||||
#endif
|
||||
second_table_name[i + (ptr - old_ptr)] = '\0';
|
||||
} else {
|
||||
#ifdef __WIN__
|
||||
ut_cpy_in_lower_case(second_table_name, old_ptr,
|
||||
ptr - old_ptr);
|
||||
ptr - old_ptr);
|
||||
#else
|
||||
ut_memcpy(second_table_name, old_ptr, ptr - old_ptr);
|
||||
if (srv_lower_case_table_names) {
|
||||
ut_cpy_in_lower_case(second_table_name, old_ptr,
|
||||
ptr - old_ptr);
|
||||
} else {
|
||||
ut_memcpy(second_table_name, old_ptr, ptr - old_ptr);
|
||||
}
|
||||
#endif
|
||||
second_table_name[dot_ptr - old_ptr] = '/';
|
||||
second_table_name[ptr - old_ptr] = '\0';
|
||||
@ -2050,6 +2117,44 @@ dict_scan_table_name(
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Skips one 'word', like an id. For the lexical definition of 'word', see the
|
||||
code below. */
|
||||
static
|
||||
char*
|
||||
dict_skip_word(
|
||||
/*===========*/
|
||||
/* out: scanned to */
|
||||
char* ptr, /* in: scanned to */
|
||||
ibool* success)/* out: TRUE if success, FALSE if just spaces left in
|
||||
string */
|
||||
{
|
||||
*success = FALSE;
|
||||
|
||||
while (isspace(*ptr)) {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (*ptr == '\0') {
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
if (*ptr == '`') {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != '`'
|
||||
&& *ptr != '\0') {
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
*success = TRUE;
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Returns the number of opening brackets '(' subtracted by the number
|
||||
of closing brackets ')' between string and ptr. */
|
||||
@ -2119,7 +2224,6 @@ dict_create_foreign_constraints(
|
||||
if (table == NULL) {
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
loop:
|
||||
ptr = dict_scan_to(ptr, (char *) "FOREIGN");
|
||||
|
||||
@ -2148,7 +2252,19 @@ loop:
|
||||
ptr = dict_accept(ptr, (char *) "(", &success);
|
||||
|
||||
if (!success) {
|
||||
goto loop;
|
||||
/* MySQL allows also an index id before the '('; we
|
||||
skip it */
|
||||
ptr = dict_skip_word(ptr, &success);
|
||||
|
||||
if (!success) {
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, (char *) "(", &success);
|
||||
|
||||
if (!success) {
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
@ -2223,6 +2339,7 @@ col_loop1:
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2236,6 +2353,7 @@ col_loop2:
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2263,14 +2381,20 @@ col_loop2:
|
||||
ptr = dict_accept(ptr, "DELETE", &success);
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "RESTRICT", &success);
|
||||
|
||||
if (success) {
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "CASCADE", &success);
|
||||
|
||||
if (success) {
|
||||
|
||||
foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE;
|
||||
|
||||
goto try_find_index;
|
||||
@ -2279,32 +2403,47 @@ col_loop2:
|
||||
ptr = dict_accept(ptr, "SET", &success);
|
||||
|
||||
if (!success) {
|
||||
|
||||
goto try_find_index;
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "NULL", &success);
|
||||
|
||||
if (success) {
|
||||
for (j = 0; j < foreign->n_fields; j++) {
|
||||
if ((dict_index_get_nth_type(
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
for (j = 0; j < foreign->n_fields; j++) {
|
||||
if ((dict_index_get_nth_type(
|
||||
foreign->foreign_index, j)->prtype)
|
||||
& DATA_NOT_NULL) {
|
||||
|
||||
/* It is not sensible to define SET NULL
|
||||
if the column is not allowed to be NULL! */
|
||||
/* It is not sensible to define SET NULL
|
||||
if the column is not allowed to be NULL! */
|
||||
|
||||
dict_foreign_free(foreign);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
|
||||
|
||||
goto try_find_index;
|
||||
}
|
||||
|
||||
foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
|
||||
|
||||
try_find_index:
|
||||
/* We check that there are no superfluous words like 'ON UPDATE ...'
|
||||
which we do not support yet. */
|
||||
|
||||
ptr = dict_accept(ptr, (char *) "ON", &success);
|
||||
|
||||
if (success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
/* Try to find an index which contains the columns as the first fields
|
||||
and in the right order, and the types are the same as in
|
||||
foreign->foreign_index */
|
||||
@ -2351,6 +2490,7 @@ try_find_index:
|
||||
referenced_table->referenced_list,
|
||||
foreign);
|
||||
}
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
@ -2849,6 +2989,14 @@ dict_update_statistics_low(
|
||||
ulint size;
|
||||
ulint sum_of_index_sizes = 0;
|
||||
|
||||
/* If we have set a high innodb_force_recovery level, do not calculate
|
||||
statistics, as a badly corrupted index can cause a crash in it. */
|
||||
|
||||
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find out the sizes of the indexes and how many different values
|
||||
for the key they approximately have */
|
||||
|
||||
@ -3152,16 +3300,25 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
}
|
||||
}
|
||||
|
||||
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
|
||||
if (dict_tables_have_same_db(table->name,
|
||||
foreign->referenced_table_name)) {
|
||||
/* Do not print the database name of the referenced
|
||||
table */
|
||||
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
|
||||
dict_remove_db_name(
|
||||
foreign->referenced_table_name));
|
||||
} else {
|
||||
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
|
||||
foreign->referenced_table_name);
|
||||
/* Change the '/' in the table name to '.' */
|
||||
/* Change the '/' in the table name to '.' */
|
||||
|
||||
for (i = ut_strlen(buf); i > 0; i--) {
|
||||
if (buf[i] == '/') {
|
||||
for (i = ut_strlen(buf); i > 0; i--) {
|
||||
if (buf[i] == '/') {
|
||||
|
||||
buf[i] = '.';
|
||||
buf[i] = '.';
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,6 +334,7 @@ extern ibool recv_no_ibuf_operations;
|
||||
extern ibool recv_needed_recovery;
|
||||
|
||||
extern ibool recv_is_making_a_backup;
|
||||
extern ulint recv_max_parsed_page_no;
|
||||
|
||||
/* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many
|
||||
times! */
|
||||
|
@ -230,18 +230,35 @@ row_update_cascade_for_mysql(
|
||||
or set null operation */
|
||||
dict_table_t* table); /* in: table where we do the operation */
|
||||
/*************************************************************************
|
||||
Locks the data dictionary exclusively for performing a table create
|
||||
operation. */
|
||||
Locks the data dictionary exclusively for performing a table create or other
|
||||
data dictionary modification operation. */
|
||||
|
||||
void
|
||||
row_mysql_lock_data_dictionary(void);
|
||||
/*================================*/
|
||||
row_mysql_lock_data_dictionary(
|
||||
/*===========================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Unlocks the data dictionary exclusively lock. */
|
||||
Unlocks the data dictionary exclusive lock. */
|
||||
|
||||
void
|
||||
row_mysql_unlock_data_dictionary(void);
|
||||
/*==================================*/
|
||||
row_mysql_unlock_data_dictionary(
|
||||
/*=============================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Locks the data dictionary in shared mode from modifications, for performing
|
||||
foreign key check, rollback, or other operation invisible to MySQL. */
|
||||
|
||||
void
|
||||
row_mysql_freeze_data_dictionary(
|
||||
/*=============================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Unlocks the data dictionary shared lock. */
|
||||
|
||||
void
|
||||
row_mysql_unfreeze_data_dictionary(
|
||||
/*===============================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Does a table creation operation for MySQL. If the name of the created
|
||||
table ends to characters INNODB_MONITOR, then this also starts
|
||||
@ -310,11 +327,9 @@ output by the master thread. */
|
||||
int
|
||||
row_drop_table_for_mysql(
|
||||
/*=====================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
char* name, /* in: table name */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool has_dict_mutex);/* in: TRUE if the caller already owns the
|
||||
dictionary system mutex */
|
||||
/* out: error code or DB_SUCCESS */
|
||||
char* name, /* in: table name */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/*************************************************************************
|
||||
Drops a database for MySQL. */
|
||||
|
||||
|
@ -28,6 +28,9 @@ extern os_event_t srv_lock_timeout_thread_event;
|
||||
at a time */
|
||||
#define SRV_AUTO_EXTEND_INCREMENT (8 * ((1024 * 1024) / UNIV_PAGE_SIZE))
|
||||
|
||||
/* This is set to TRUE if the MySQL user has set it in MySQL */
|
||||
extern ibool srv_lower_case_table_names;
|
||||
|
||||
/* Server parameters which are read from the initfile */
|
||||
|
||||
extern char* srv_data_home;
|
||||
|
@ -386,9 +386,10 @@ struct trx_struct{
|
||||
/* how many tables the current SQL
|
||||
statement uses, except those
|
||||
in consistent read */
|
||||
ibool has_dict_operation_lock;
|
||||
/* TRUE if the trx currently holds
|
||||
an s-lock on dict_operation_lock */
|
||||
ibool dict_operation_lock_mode;
|
||||
/* 0, RW_S_LATCH, or RW_X_LATCH:
|
||||
the latch mode trx currently holds
|
||||
on dict_operation_lock */
|
||||
ibool has_search_latch;
|
||||
/* TRUE if this trx has latched the
|
||||
search system latch in S-mode */
|
||||
@ -427,34 +428,6 @@ struct trx_struct{
|
||||
mysql_trx_list; /* list of transactions created for
|
||||
MySQL */
|
||||
/*------------------------------*/
|
||||
mutex_t undo_mutex; /* mutex protecting the fields in this
|
||||
section (down to undo_no_arr), EXCEPT
|
||||
last_sql_stat_start, which can be
|
||||
accessed only when we know that there
|
||||
cannot be any activity in the undo
|
||||
logs! */
|
||||
dulint undo_no; /* next undo log record number to
|
||||
assign */
|
||||
trx_savept_t last_sql_stat_start;
|
||||
/* undo_no when the last sql statement
|
||||
was started: in case of an error, trx
|
||||
is rolled back down to this undo
|
||||
number; see note at undo_mutex! */
|
||||
trx_rseg_t* rseg; /* rollback segment assigned to the
|
||||
transaction, or NULL if not assigned
|
||||
yet */
|
||||
trx_undo_t* insert_undo; /* pointer to the insert undo log, or
|
||||
NULL if no inserts performed yet */
|
||||
trx_undo_t* update_undo; /* pointer to the update undo log, or
|
||||
NULL if no update performed yet */
|
||||
dulint roll_limit; /* least undo number to undo during
|
||||
a rollback */
|
||||
ulint pages_undone; /* number of undo log pages undone
|
||||
since the last undo log truncation */
|
||||
trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
|
||||
records which are currently processed
|
||||
by a rollback operation */
|
||||
/*------------------------------*/
|
||||
ulint error_state; /* 0 if no error, otherwise error
|
||||
number */
|
||||
void* error_info; /* if the error number indicates a
|
||||
@ -508,6 +481,34 @@ struct trx_struct{
|
||||
/*------------------------------*/
|
||||
mem_heap_t* read_view_heap; /* memory heap for the read view */
|
||||
read_view_t* read_view; /* consistent read view or NULL */
|
||||
/*------------------------------*/
|
||||
mutex_t undo_mutex; /* mutex protecting the fields in this
|
||||
section (down to undo_no_arr), EXCEPT
|
||||
last_sql_stat_start, which can be
|
||||
accessed only when we know that there
|
||||
cannot be any activity in the undo
|
||||
logs! */
|
||||
dulint undo_no; /* next undo log record number to
|
||||
assign */
|
||||
trx_savept_t last_sql_stat_start;
|
||||
/* undo_no when the last sql statement
|
||||
was started: in case of an error, trx
|
||||
is rolled back down to this undo
|
||||
number; see note at undo_mutex! */
|
||||
trx_rseg_t* rseg; /* rollback segment assigned to the
|
||||
transaction, or NULL if not assigned
|
||||
yet */
|
||||
trx_undo_t* insert_undo; /* pointer to the insert undo log, or
|
||||
NULL if no inserts performed yet */
|
||||
trx_undo_t* update_undo; /* pointer to the update undo log, or
|
||||
NULL if no update performed yet */
|
||||
dulint roll_limit; /* least undo number to undo during
|
||||
a rollback */
|
||||
ulint pages_undone; /* number of undo log pages undone
|
||||
since the last undo log truncation */
|
||||
trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
|
||||
records which are currently processed
|
||||
by a rollback operation */
|
||||
};
|
||||
|
||||
#define TRX_MAX_N_THREADS 32 /* maximum number of concurrent
|
||||
|
@ -69,6 +69,8 @@ ulint recv_previous_parsed_rec_type = 999999;
|
||||
ulint recv_previous_parsed_rec_offset = 0;
|
||||
ulint recv_previous_parsed_rec_is_multi = 0;
|
||||
|
||||
ulint recv_max_parsed_page_no = 0;
|
||||
|
||||
/************************************************************
|
||||
Creates the recovery system. */
|
||||
|
||||
@ -141,7 +143,13 @@ recv_sys_empty_hash(void)
|
||||
/*=====================*/
|
||||
{
|
||||
ut_ad(mutex_own(&(recv_sys->mutex)));
|
||||
ut_a(recv_sys->n_addrs == 0);
|
||||
if (recv_sys->n_addrs != 0) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: %lu pages with log records were left unprocessed!\n"
|
||||
"InnoDB: Maximum page number with log records on it %lu\n",
|
||||
recv_sys->n_addrs, recv_max_parsed_page_no);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
hash_table_free(recv_sys->addr_hash);
|
||||
mem_heap_empty(recv_sys->heap);
|
||||
@ -1361,6 +1369,12 @@ recv_apply_log_recs_for_backup(
|
||||
n_pages_total += file_sizes[i];
|
||||
}
|
||||
|
||||
if (recv_max_parsed_page_no >= n_pages_total) {
|
||||
printf(
|
||||
"InnoDB: Error: tablespace size %lu pages, but a log record on page %lu!\n",
|
||||
n_pages_total, recv_max_parsed_page_no);
|
||||
}
|
||||
|
||||
printf(
|
||||
"InnoDB: Starting an apply batch of log records to the database...\n"
|
||||
"InnoDB: Progress in percents: ");
|
||||
@ -1701,6 +1715,10 @@ recv_parse_log_rec(
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (*page_no > recv_max_parsed_page_no) {
|
||||
recv_max_parsed_page_no = *page_no;
|
||||
}
|
||||
|
||||
return(new_ptr - ptr);
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,12 @@ os_event_create(
|
||||
event = ut_malloc(sizeof(struct os_event_struct));
|
||||
|
||||
os_fast_mutex_init(&(event->os_mutex));
|
||||
pthread_cond_init(&(event->cond_var), NULL);
|
||||
|
||||
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
|
||||
pthread_cond_init(&(event->cond_var), pthread_condattr_default);
|
||||
#else
|
||||
pthread_cond_init(&(event->cond_var), NULL);
|
||||
#endif
|
||||
event->is_set = FALSE;
|
||||
|
||||
return(event);
|
||||
@ -440,9 +444,13 @@ os_fast_mutex_init(
|
||||
ut_a(fast_mutex);
|
||||
|
||||
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
|
||||
#else
|
||||
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
|
||||
pthread_mutex_init(fast_mutex, pthread_mutexattr_default);
|
||||
#else
|
||||
pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
@ -126,8 +126,10 @@ os_thread_create(
|
||||
os_thread_t pthread;
|
||||
pthread_attr_t attr;
|
||||
|
||||
#if !(defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10))
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UNIV_AIX
|
||||
/* We must make sure a thread stack is at least 32 kB, otherwise
|
||||
InnoDB might crash; we do not know if the default stack size on
|
||||
@ -142,16 +144,21 @@ os_thread_create(
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
ret = pthread_create(&pthread, &attr, start_f, arg);
|
||||
|
||||
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
|
||||
ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
|
||||
#else
|
||||
ret = pthread_create(&pthread, &attr, start_f, arg);
|
||||
#endif
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: pthread_create returned %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if !(defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10))
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
#endif
|
||||
if (srv_set_thread_priorities) {
|
||||
|
||||
my_pthread_setprio(pthread, srv_query_thread_priority);
|
||||
|
@ -643,7 +643,7 @@ row_ins_check_foreign_constraint(
|
||||
|
||||
run_again:
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
|
||||
|
||||
|
||||
err = DB_SUCCESS;
|
||||
|
||||
if (thr_get_trx(thr)->check_foreigns == FALSE) {
|
||||
@ -880,21 +880,16 @@ row_ins_check_foreign_constraints(
|
||||
trx);
|
||||
}
|
||||
|
||||
if (!trx->has_dict_operation_lock) {
|
||||
if (0 == trx->dict_operation_lock_mode) {
|
||||
got_s_lock = TRUE;
|
||||
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
|
||||
trx->has_dict_operation_lock = TRUE;
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
||||
table, index, entry, thr);
|
||||
if (got_s_lock) {
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
|
||||
trx->has_dict_operation_lock = FALSE;
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
@ -1134,32 +1134,73 @@ row_mysql_recover_tmp_table(
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Locks the data dictionary exclusively for performing a table create
|
||||
operation. */
|
||||
Locks the data dictionary in shared mode from modifications, for performing
|
||||
foreign key check, rollback, or other operation invisible to MySQL. */
|
||||
|
||||
void
|
||||
row_mysql_lock_data_dictionary(void)
|
||||
/*================================*/
|
||||
row_mysql_freeze_data_dictionary(
|
||||
/*=============================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
ut_a(trx->dict_operation_lock_mode == 0);
|
||||
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
|
||||
trx->dict_operation_lock_mode = RW_S_LATCH;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Unlocks the data dictionary shared lock. */
|
||||
|
||||
void
|
||||
row_mysql_unfreeze_data_dictionary(
|
||||
/*===============================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
|
||||
trx->dict_operation_lock_mode = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Locks the data dictionary exclusively for performing a table create or other
|
||||
data dictionary modification operation. */
|
||||
|
||||
void
|
||||
row_mysql_lock_data_dictionary(
|
||||
/*===========================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
ut_a(trx->dict_operation_lock_mode == 0);
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks or lock waits can occur then in these operations */
|
||||
|
||||
rw_lock_x_lock(&dict_operation_lock);
|
||||
trx->dict_operation_lock_mode = RW_X_LATCH;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Unlocks the data dictionary exclusively lock. */
|
||||
Unlocks the data dictionary exclusive lock. */
|
||||
|
||||
void
|
||||
row_mysql_unlock_data_dictionary(void)
|
||||
/*==================================*/
|
||||
row_mysql_unlock_data_dictionary(
|
||||
/*=============================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&dict_operation_lock);
|
||||
|
||||
trx->dict_operation_lock_mode = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@ -1183,6 +1224,7 @@ row_create_table_for_mysql(
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
if (srv_created_new_raw) {
|
||||
@ -1331,7 +1373,7 @@ row_create_table_for_mysql(
|
||||
fprintf(stderr,
|
||||
"InnoDB: Warning: cannot create table %s because tablespace full\n",
|
||||
table->name);
|
||||
row_drop_table_for_mysql(table->name, trx, TRUE);
|
||||
row_drop_table_for_mysql(table->name, trx);
|
||||
} else {
|
||||
ut_a(err == DB_DUPLICATE_KEY);
|
||||
|
||||
@ -1425,7 +1467,7 @@ row_create_index_for_mysql(
|
||||
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
row_drop_table_for_mysql(index->table_name, trx, TRUE);
|
||||
row_drop_table_for_mysql(index->table_name, trx);
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
}
|
||||
@ -1499,7 +1541,7 @@ row_table_add_foreign_constraints(
|
||||
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
row_drop_table_for_mysql(name, trx, TRUE);
|
||||
row_drop_table_for_mysql(name, trx);
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
}
|
||||
@ -1530,7 +1572,7 @@ row_drop_table_for_mysql_in_background(
|
||||
name); */
|
||||
/* Drop the table in InnoDB */
|
||||
|
||||
error = row_drop_table_for_mysql(name, trx, FALSE);
|
||||
error = row_drop_table_for_mysql(name, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
fprintf(stderr,
|
||||
@ -1689,9 +1731,7 @@ row_drop_table_for_mysql(
|
||||
/*=====================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
char* name, /* in: table name */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool has_dict_mutex) /* in: TRUE if the caller already owns the
|
||||
dictionary system mutex */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
dict_table_t* table;
|
||||
que_thr_t* thr;
|
||||
@ -1703,6 +1743,7 @@ row_drop_table_for_mysql(
|
||||
ulint namelen;
|
||||
ulint keywordlen;
|
||||
ulint rounds = 0;
|
||||
ibool locked_dictionary = FALSE;
|
||||
char buf[10000];
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
@ -1846,12 +1887,13 @@ row_drop_table_for_mysql(
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
if (!has_dict_mutex) {
|
||||
if (trx->dict_operation_lock_mode != RW_X_LATCH) {
|
||||
/* Prevent foreign key checks etc. while we are dropping the
|
||||
table */
|
||||
rw_lock_x_lock(&dict_operation_lock);
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
locked_dictionary = TRUE;
|
||||
}
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
@ -1948,9 +1990,8 @@ row_drop_table_for_mysql(
|
||||
}
|
||||
funct_exit:
|
||||
|
||||
if (!has_dict_mutex) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&dict_operation_lock);
|
||||
if (locked_dictionary) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
que_graph_free(graph);
|
||||
@ -1986,8 +2027,7 @@ row_drop_database_for_mysql(
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
loop:
|
||||
rw_lock_x_lock(&dict_operation_lock);
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
while ((table_name = dict_get_first_table_name_in_db(name))) {
|
||||
ut_a(memcmp(table_name, name, strlen(name)) == 0);
|
||||
@ -2000,8 +2040,7 @@ loop:
|
||||
the table */
|
||||
|
||||
if (table->n_mysql_handles_opened > 0) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&dict_operation_lock);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
@ -2016,7 +2055,7 @@ loop:
|
||||
goto loop;
|
||||
}
|
||||
|
||||
err = row_drop_table_for_mysql(table_name, trx, TRUE);
|
||||
err = row_drop_table_for_mysql(table_name, trx);
|
||||
|
||||
mem_free(table_name);
|
||||
|
||||
@ -2028,8 +2067,7 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&dict_operation_lock);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
@ -2166,8 +2204,7 @@ row_rename_table_for_mysql(
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
rw_lock_x_lock(&dict_operation_lock);
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
table = dict_table_get_low(old_name);
|
||||
|
||||
@ -2249,8 +2286,7 @@ row_rename_table_for_mysql(
|
||||
}
|
||||
}
|
||||
funct_exit:
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
rw_lock_x_unlock(&dict_operation_lock);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
|
@ -24,6 +24,7 @@ Created 3/14/1997 Heikki Tuuri
|
||||
#include "row0row.h"
|
||||
#include "row0upd.h"
|
||||
#include "row0vers.h"
|
||||
#include "row0mysql.h"
|
||||
#include "log0log.h"
|
||||
|
||||
/************************************************************************
|
||||
@ -454,8 +455,8 @@ ibool
|
||||
row_purge_parse_undo_rec(
|
||||
/*=====================*/
|
||||
/* out: TRUE if purge operation required:
|
||||
NOTE that then the CALLER must s-unlock
|
||||
dict_operation_lock! */
|
||||
NOTE that then the CALLER must unfreeze
|
||||
data dictionary! */
|
||||
purge_node_t* node, /* in: row undo node */
|
||||
ibool* updated_extern,
|
||||
/* out: TRUE if an externally stored field
|
||||
@ -464,6 +465,7 @@ row_purge_parse_undo_rec(
|
||||
{
|
||||
dict_index_t* clust_index;
|
||||
byte* ptr;
|
||||
trx_t* trx;
|
||||
dulint undo_no;
|
||||
dulint table_id;
|
||||
dulint trx_id;
|
||||
@ -473,6 +475,8 @@ row_purge_parse_undo_rec(
|
||||
ulint cmpl_info;
|
||||
|
||||
ut_ad(node && thr);
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
|
||||
updated_extern, &undo_no, &table_id);
|
||||
@ -498,17 +502,18 @@ row_purge_parse_undo_rec(
|
||||
/* Prevent DROP TABLE etc. from running when we are doing the purge
|
||||
for this row */
|
||||
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr));
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
if (node->table == NULL) {
|
||||
/* The table has been dropped: no need to do purge */
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
@ -518,7 +523,7 @@ row_purge_parse_undo_rec(
|
||||
if (clust_index == NULL) {
|
||||
/* The table was corrupt in the data dictionary */
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
@ -556,9 +561,12 @@ row_purge(
|
||||
dulint roll_ptr;
|
||||
ibool purge_needed;
|
||||
ibool updated_extern;
|
||||
trx_t* trx;
|
||||
|
||||
ut_ad(node && thr);
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
|
||||
&(node->reservation),
|
||||
node->heap);
|
||||
@ -577,8 +585,8 @@ row_purge(
|
||||
} else {
|
||||
purge_needed = row_purge_parse_undo_rec(node, &updated_extern,
|
||||
thr);
|
||||
/* If purge_needed == TRUE, we must also remember to unlock
|
||||
dict_operation_lock! */
|
||||
/* If purge_needed == TRUE, we must also remember to unfreeze
|
||||
data dictionary! */
|
||||
}
|
||||
|
||||
if (purge_needed) {
|
||||
@ -600,7 +608,7 @@ row_purge(
|
||||
btr_pcur_close(&(node->pcur));
|
||||
}
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
/* Do some cleanup */
|
||||
|
@ -24,6 +24,7 @@ Created 1/8/1997 Heikki Tuuri
|
||||
#include "row0row.h"
|
||||
#include "row0uins.h"
|
||||
#include "row0umod.h"
|
||||
#include "row0mysql.h"
|
||||
#include "srv0srv.h"
|
||||
|
||||
/* How to undo row operations?
|
||||
@ -204,6 +205,7 @@ row_undo(
|
||||
ulint err;
|
||||
trx_t* trx;
|
||||
dulint roll_ptr;
|
||||
ibool froze_data_dict = FALSE;
|
||||
|
||||
ut_ad(node && thr);
|
||||
|
||||
@ -256,13 +258,13 @@ row_undo(
|
||||
/* Prevent DROP TABLE etc. while we are rolling back this row.
|
||||
If we are doing a TABLE CREATE or some other dictionary operation,
|
||||
then we already have dict_operation_lock locked in x-mode. Do not
|
||||
try to lock again in s-mode, because that would cause a hang.
|
||||
|
||||
TODO: keep track when trx exactly has the latch locked!!!
|
||||
TODO: trx->dict_operation tells it only in some cases!!! */
|
||||
|
||||
if (!trx->dict_operation) {
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
try to lock again in s-mode, because that would cause a hang. */
|
||||
|
||||
if (trx->dict_operation_lock_mode == 0) {
|
||||
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
|
||||
froze_data_dict = TRUE;
|
||||
}
|
||||
|
||||
if (node->state == UNDO_NODE_INSERT) {
|
||||
@ -275,9 +277,9 @@ row_undo(
|
||||
err = row_undo_mod(node, thr);
|
||||
}
|
||||
|
||||
if (!trx->dict_operation) {
|
||||
if (froze_data_dict) {
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
/* Do some cleanup */
|
||||
|
@ -89,14 +89,16 @@ row_upd_index_is_referenced(
|
||||
{
|
||||
dict_table_t* table = index->table;
|
||||
dict_foreign_t* foreign;
|
||||
ibool froze_data_dict = FALSE;
|
||||
|
||||
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (!trx->has_dict_operation_lock) {
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
if (trx->dict_operation_lock_mode == 0) {
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
froze_data_dict = TRUE;
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
@ -104,8 +106,8 @@ row_upd_index_is_referenced(
|
||||
while (foreign) {
|
||||
if (foreign->referenced_index == index) {
|
||||
|
||||
if (!trx->has_dict_operation_lock) {
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
if (froze_data_dict) {
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
@ -114,8 +116,8 @@ row_upd_index_is_referenced(
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
if (!trx->has_dict_operation_lock) {
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
if (froze_data_dict) {
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
@ -162,12 +164,10 @@ row_upd_check_references_constraints(
|
||||
|
||||
mtr_start(mtr);
|
||||
|
||||
if (!trx->has_dict_operation_lock) {
|
||||
if (trx->dict_operation_lock_mode == 0) {
|
||||
got_s_lock = TRUE;
|
||||
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
|
||||
trx->has_dict_operation_lock = TRUE;
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
@ -211,10 +211,7 @@ row_upd_check_references_constraints(
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
if (got_s_lock) {
|
||||
rw_lock_s_unlock(
|
||||
&dict_operation_lock);
|
||||
trx->has_dict_operation_lock
|
||||
= FALSE;
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
@ -227,8 +224,7 @@ row_upd_check_references_constraints(
|
||||
}
|
||||
|
||||
if (got_s_lock) {
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
trx->has_dict_operation_lock = FALSE;
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
@ -51,6 +51,10 @@ Created 10/8/1995 Heikki Tuuri
|
||||
#include "srv0start.h"
|
||||
#include "row0mysql.h"
|
||||
|
||||
/* This is set to TRUE if the MySQL user has set it in MySQL; currently
|
||||
affects only FOREIGN KEY definition parsing */
|
||||
ibool srv_lower_case_table_names = FALSE;
|
||||
|
||||
/* Buffer which can be used in printing fatal error messages */
|
||||
char srv_fatal_errbuf[5000];
|
||||
|
||||
@ -2064,6 +2068,7 @@ srv_suspend_mysql_thread(
|
||||
os_event_t event;
|
||||
double wait_time;
|
||||
trx_t* trx;
|
||||
ibool had_dict_lock = FALSE;
|
||||
|
||||
ut_ad(!mutex_own(&kernel_mutex));
|
||||
|
||||
@ -2107,18 +2112,22 @@ srv_suspend_mysql_thread(
|
||||
srv_conc_force_exit_innodb(thr_get_trx(thr));
|
||||
|
||||
/* Release possible foreign key check latch */
|
||||
if (trx->has_dict_operation_lock) {
|
||||
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
|
||||
|
||||
rw_lock_s_unlock(&dict_operation_lock);
|
||||
had_dict_lock = TRUE;
|
||||
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
ut_a(trx->dict_operation_lock_mode == 0);
|
||||
|
||||
/* Wait for the release */
|
||||
|
||||
os_event_wait(event);
|
||||
|
||||
if (trx->has_dict_operation_lock) {
|
||||
if (had_dict_lock) {
|
||||
|
||||
rw_lock_s_lock(&dict_operation_lock);
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
/* Return back inside InnoDB */
|
||||
|
@ -1380,7 +1380,7 @@ innobase_start_or_create_for_mysql(void)
|
||||
if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: pthread_mutex_trylock returns an unexpected value on\n"
|
||||
"InnoDB: success! Cannot continue.\n");
|
||||
"InnoDB: success! Cannot continue.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -1390,11 +1390,17 @@ innobase_start_or_create_for_mysql(void)
|
||||
|
||||
os_fast_mutex_unlock(&srv_os_test_mutex);
|
||||
|
||||
if (srv_print_verbose_log)
|
||||
{
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr, " InnoDB: Started\n");
|
||||
if (srv_print_verbose_log) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr, " InnoDB: Started\n");
|
||||
}
|
||||
|
||||
if (srv_force_recovery > 0) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: !!! innodb_force_recovery is set to %lu !!!\n",
|
||||
srv_force_recovery);
|
||||
}
|
||||
|
||||
return((int) DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ loop:
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
if (trx->dict_operation) {
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
que_run_threads(thr);
|
||||
@ -290,14 +290,14 @@ loop:
|
||||
fprintf(stderr,
|
||||
"InnoDB: Table found: dropping table %s in recovery\n", table->name);
|
||||
|
||||
err = row_drop_table_for_mysql(table->name, trx,
|
||||
TRUE);
|
||||
err = row_drop_table_for_mysql(table->name, trx);
|
||||
|
||||
ut_a(err == (int) DB_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (trx->dict_operation) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
fprintf(stderr, "InnoDB: Rolling back of trx id %lu %lu completed\n",
|
||||
|
@ -134,7 +134,7 @@ trx_create(
|
||||
trx->lock_heap = mem_heap_create_in_buffer(256);
|
||||
UT_LIST_INIT(trx->trx_locks);
|
||||
|
||||
trx->has_dict_operation_lock = FALSE;
|
||||
trx->dict_operation_lock_mode = 0;
|
||||
trx->has_search_latch = FALSE;
|
||||
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
||||
|
||||
@ -261,6 +261,8 @@ trx_free(
|
||||
ut_a(!trx->has_search_latch);
|
||||
ut_a(!trx->auto_inc_lock);
|
||||
|
||||
ut_a(trx->dict_operation_lock_mode == 0);
|
||||
|
||||
if (trx->lock_heap) {
|
||||
mem_heap_free(trx->lock_heap);
|
||||
}
|
||||
|
@ -1153,15 +1153,15 @@ ha_innobase::open(
|
||||
ib_table = dict_table_get_and_increment_handle_count(
|
||||
norm_name, NULL);
|
||||
if (NULL == ib_table) {
|
||||
|
||||
sql_print_error("InnoDB error:\n\
|
||||
Cannot find table %s from the internal data dictionary\n\
|
||||
of InnoDB though the .frm file for the table exists. Maybe you\n\
|
||||
have deleted and recreated InnoDB data files but have forgotten\n\
|
||||
to delete the corresponding .frm files of InnoDB tables, or you\n\
|
||||
have moved .frm files to another database?\n\
|
||||
Look from section 15.1 of http://www.innodb.com/ibman.html\n\
|
||||
how you can resolve the problem.\n",
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr, " InnoDB error:\n"
|
||||
"Cannot find table %s from the internal data dictionary\n"
|
||||
"of InnoDB though the .frm file for the table exists. Maybe you\n"
|
||||
"have deleted and recreated InnoDB data files but have forgotten\n"
|
||||
"to delete the corresponding .frm files of InnoDB tables, or you\n"
|
||||
"have moved .frm files to another database?\n"
|
||||
"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
|
||||
"how you can resolve the problem.\n",
|
||||
norm_name);
|
||||
|
||||
free_share(share);
|
||||
@ -2961,16 +2961,21 @@ ha_innobase::create(
|
||||
trx->check_unique_secondary = FALSE;
|
||||
}
|
||||
|
||||
if (lower_case_table_names) {
|
||||
srv_lower_case_table_names = TRUE;
|
||||
} else {
|
||||
srv_lower_case_table_names = FALSE;
|
||||
}
|
||||
|
||||
fn_format(name2, name, "", "",2); // Remove the .frm extension
|
||||
|
||||
normalize_table_name(norm_name, name2);
|
||||
|
||||
/* Latch the InnoDB data dictionary exclusive so that no deadlocks
|
||||
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
|
||||
or lock waits can happen in it during a table create operation.
|
||||
(Drop table etc. do this latching in row0mysql.c.) */
|
||||
Drop table etc. do this latching in row0mysql.c. */
|
||||
|
||||
row_mysql_lock_data_dictionary();
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
/* Create the table definition in InnoDB */
|
||||
|
||||
@ -2979,7 +2984,7 @@ ha_innobase::create(
|
||||
if (error) {
|
||||
innobase_commit_low(trx);
|
||||
|
||||
row_mysql_unlock_data_dictionary();
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
@ -3009,7 +3014,7 @@ ha_innobase::create(
|
||||
if (error) {
|
||||
innobase_commit_low(trx);
|
||||
|
||||
row_mysql_unlock_data_dictionary();
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
@ -3024,7 +3029,7 @@ ha_innobase::create(
|
||||
(uint) primary_key_no))) {
|
||||
innobase_commit_low(trx);
|
||||
|
||||
row_mysql_unlock_data_dictionary();
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
@ -3040,7 +3045,7 @@ ha_innobase::create(
|
||||
|
||||
innobase_commit_low(trx);
|
||||
|
||||
row_mysql_unlock_data_dictionary();
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
@ -3057,7 +3062,7 @@ ha_innobase::create(
|
||||
if (error) {
|
||||
innobase_commit_low(trx);
|
||||
|
||||
row_mysql_unlock_data_dictionary();
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
@ -3066,7 +3071,7 @@ ha_innobase::create(
|
||||
|
||||
innobase_commit_low(trx);
|
||||
|
||||
row_mysql_unlock_data_dictionary();
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
/* Flush the log to reduce probability that the .frm files and
|
||||
the InnoDB data dictionary get out-of-sync if the user runs
|
||||
@ -3108,6 +3113,12 @@ ha_innobase::delete_table(
|
||||
|
||||
DBUG_ENTER("ha_innobase::delete_table");
|
||||
|
||||
if (lower_case_table_names) {
|
||||
srv_lower_case_table_names = TRUE;
|
||||
} else {
|
||||
srv_lower_case_table_names = FALSE;
|
||||
}
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
name_len = strlen(name);
|
||||
@ -3121,7 +3132,7 @@ ha_innobase::delete_table(
|
||||
|
||||
/* Drop the table in InnoDB */
|
||||
|
||||
error = row_drop_table_for_mysql(norm_name, trx, FALSE);
|
||||
error = row_drop_table_for_mysql(norm_name, trx);
|
||||
|
||||
/* Flush the log to reduce probability that the .frm files and
|
||||
the InnoDB data dictionary get out-of-sync if the user runs
|
||||
@ -3218,6 +3229,12 @@ ha_innobase::rename_table(
|
||||
|
||||
DBUG_ENTER("ha_innobase::rename_table");
|
||||
|
||||
if (lower_case_table_names) {
|
||||
srv_lower_case_table_names = TRUE;
|
||||
} else {
|
||||
srv_lower_case_table_names = FALSE;
|
||||
}
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
name_len1 = strlen(from);
|
||||
@ -3406,6 +3423,15 @@ ha_innobase::info(
|
||||
|
||||
DBUG_ENTER("info");
|
||||
|
||||
/* If we are forcing recovery at a high level, we will suppress
|
||||
statistics calculation on tables, because that may crash the
|
||||
server if an index is badly corrupted. */
|
||||
|
||||
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Warning: since it is not sure that MySQL calls external_lock
|
||||
before calling this function, the trx field in prebuilt can be
|
||||
obsolete! */
|
||||
|
Loading…
x
Reference in New Issue
Block a user