Commit 444d8207 authored by unknown's avatar unknown

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