diff options
author | unknown <heikki@hundin.mysql.fi> | 2002-11-06 00:41:27 +0200 |
---|---|---|
committer | unknown <heikki@hundin.mysql.fi> | 2002-11-06 00:41:27 +0200 |
commit | 444d8207d9a277231733dc6cd58bf21b626bba31 (patch) | |
tree | fed8334ab45443418d527c3837593e1121ed1975 /innobase | |
parent | 23f4865b163293006bbedbc2b69bc55ba1081baa (diff) | |
download | mariadb-git-444d8207d9a277231733dc6cd58bf21b626bba31.tar.gz |
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
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/dict/dict0crea.c | 18 | ||||
-rw-r--r-- | innobase/dict/dict0dict.c | 219 | ||||
-rw-r--r-- | innobase/include/log0recv.h | 1 | ||||
-rw-r--r-- | innobase/include/row0mysql.h | 39 | ||||
-rw-r--r-- | innobase/include/srv0srv.h | 3 | ||||
-rw-r--r-- | innobase/include/trx0trx.h | 63 | ||||
-rw-r--r-- | innobase/log/log0recv.c | 20 | ||||
-rw-r--r-- | innobase/os/os0sync.c | 10 | ||||
-rw-r--r-- | innobase/os/os0thread.c | 13 | ||||
-rw-r--r-- | innobase/row/row0ins.c | 13 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 98 | ||||
-rw-r--r-- | innobase/row/row0purge.c | 30 | ||||
-rw-r--r-- | innobase/row/row0undo.c | 20 | ||||
-rw-r--r-- | innobase/row/row0upd.c | 28 | ||||
-rw-r--r-- | innobase/srv/srv0srv.c | 17 | ||||
-rw-r--r-- | innobase/srv/srv0start.c | 16 | ||||
-rw-r--r-- | innobase/trx/trx0roll.c | 8 | ||||
-rw-r--r-- | innobase/trx/trx0trx.c | 4 |
18 files changed, 444 insertions, 176 deletions
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 60beeacf435..b0f84e5663a 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -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); } diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 2ee2c9d18a9..18f27602cf0 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -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 */ @@ -183,6 +186,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. */ void @@ -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'; @@ -2051,6 +2118,44 @@ dict_scan_table_name( } /************************************************************************* +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. */ static @@ -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; + 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. */ - goto try_find_index; + 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 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; + } } } diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h index baa2ba50c7d..7418e4abf1b 100644 --- a/innobase/include/log0recv.h +++ b/innobase/include/log0recv.h @@ -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! */ diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 8152c534f48..c72c905edf5 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -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. */ diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 4d2768cf109..ad6f71f7a3a 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -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; diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 874b126e47c..1468ef449e7 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -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 diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 1223f9b6041..0fcf32ad99e 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -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); } diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 14677ede20f..bac1f23a1af 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -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); @@ -441,8 +445,12 @@ os_fast_mutex_init( 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 } /************************************************************** diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 48aea4b8abb..30404c4e66b 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -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); diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 4e8b487a0f1..d0a5cfec604 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -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) { diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 6fde57eb75a..b109b785a45 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -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); diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c index 3d9ae6aad8b..b64003f22d4 100644 --- a/innobase/row/row0purge.c +++ b/innobase/row/row0purge.c @@ -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); - node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr)); + mutex_enter(&(dict_sys->mutex)); - mutex_exit(&(dict_sys->mutex)); + node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr)); + 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 */ diff --git a/innobase/row/row0undo.c b/innobase/row/row0undo.c index 6f1cfc4db9f..01b0b1ab41e 100644 --- a/innobase/row/row0undo.c +++ b/innobase/row/row0undo.c @@ -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 */ diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 0be4f901d16..1231c94da63 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -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); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 11e45df4ce3..51d7878fd29 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -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) { + + 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 */ 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 */ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index cad946b1e54..d006b4ec915 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -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); } diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index 4c2ee5dc9be..1f0e0c58ac7 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -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", diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 7566fe1839e..9f711890f60 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -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); } |