diff options
-rw-r--r-- | innobase/btr/btr0sea.c | 44 | ||||
-rw-r--r-- | innobase/dict/dict0dict.c | 3 | ||||
-rw-r--r-- | innobase/dict/dict0load.c | 20 | ||||
-rw-r--r-- | innobase/fil/fil0fil.c | 83 | ||||
-rw-r--r-- | innobase/include/univ.i | 6 | ||||
-rw-r--r-- | innobase/os/os0sync.c | 30 | ||||
-rw-r--r-- | innobase/srv/srv0start.c | 14 | ||||
-rw-r--r-- | mysql-test/r/innodb.result | 71 | ||||
-rw-r--r-- | mysql-test/t/innodb.test | 102 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 59 | ||||
-rw-r--r-- | sql/ha_innodb.h | 13 |
11 files changed, 376 insertions, 69 deletions
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index 81f23cfa99c..32e22aa51bc 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -191,7 +191,7 @@ static void btr_search_info_update_hash( /*========================*/ - btr_search_t* info, /* in: search info */ + btr_search_t* info, /* in/out: search info */ btr_cur_t* cursor) /* in: cursor which was just positioned */ { dict_index_t* index; @@ -452,7 +452,7 @@ Updates the search info. */ void btr_search_info_update_slow( /*========================*/ - btr_search_t* info, /* in: search info */ + btr_search_t* info, /* in/out: search info */ btr_cur_t* cursor) /* in: cursor which was just positioned */ { buf_block_t* block; @@ -912,12 +912,12 @@ btr_search_drop_page_hash_index( ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)); ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - +retry: rw_lock_s_lock(&btr_search_latch); block = buf_block_align(page); - if (!block->is_hashed) { + if (UNIV_LIKELY(!block->is_hashed)) { rw_lock_s_unlock(&btr_search_latch); @@ -958,6 +958,8 @@ btr_search_drop_page_hash_index( tree_id = btr_page_get_index_id(page); + ut_a(0 == ut_dulint_cmp(tree_id, index->id)); + prev_fold = 0; heap = NULL; @@ -992,6 +994,26 @@ next_rec: rw_lock_x_lock(&btr_search_latch); + if (UNIV_UNLIKELY(!block->is_hashed)) { + /* Someone else has meanwhile dropped the hash index */ + + goto cleanup; + } + + ut_a(block->index == index); + + if (UNIV_UNLIKELY(block->curr_n_fields != n_fields) + || UNIV_UNLIKELY(block->curr_n_bytes != n_bytes)) { + + /* Someone else has meanwhile built a new hash index on the + page, with different parameters */ + + rw_lock_x_unlock(&btr_search_latch); + + mem_free(folds); + goto retry; + } + for (i = 0; i < n_cached; i++) { ha_remove_all_nodes_to_page(table, folds[i], page); @@ -999,8 +1021,20 @@ next_rec: block->is_hashed = FALSE; block->index = NULL; +cleanup: + if (UNIV_UNLIKELY(block->n_pointers)) { + /* Corruption */ + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Corruption of adaptive hash index. After dropping\n" +"InnoDB: the hash index to a page of %s, still %lu hash nodes remain.\n", + index->name, (ulong) block->n_pointers); + rw_lock_x_unlock(&btr_search_latch); - rw_lock_x_unlock(&btr_search_latch); + btr_search_validate(); + } else { + rw_lock_x_unlock(&btr_search_latch); + } mem_free(folds); } diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 8050eebddd8..58c4e3ed6a3 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2803,7 +2803,8 @@ dict_table_get_highest_foreign_id( if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len && 0 == ut_memcmp(foreign->id, table->name, len) && 0 == ut_memcmp(foreign->id + len, - dict_ibfk, (sizeof dict_ibfk) - 1)) { + dict_ibfk, (sizeof dict_ibfk) - 1) + && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') { /* It is of the >= 4.0.18 format */ id = strtoul(foreign->id + len + ((sizeof dict_ibfk) - 1), diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 3281f9926f9..6415cc56b61 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -385,13 +385,23 @@ dict_load_columns( field = rec_get_nth_field_old(rec, 6, &len); prtype = mach_read_from_4(field); - if (dtype_is_non_binary_string_type(mtype, prtype) - && dtype_get_charset_coll(prtype) == 0) { - /* This is a non-binary string type, and the table - was created with < 4.1.2. Use the default charset. */ + if (dtype_get_charset_coll(prtype) == 0 + && dtype_is_string_type(mtype)) { + /* The table was created with < 4.1.2. */ - prtype = dtype_form_prtype(prtype, + if (dtype_is_binary_string_type(mtype, prtype)) { + /* Use the binary collation for + string columns of binary type. */ + + prtype = dtype_form_prtype(prtype, + DATA_MYSQL_BINARY_CHARSET_COLL); + } else { + /* Use the default charset for + other than binary columns. */ + + prtype = dtype_form_prtype(prtype, data_mysql_default_charset_coll); + } } field = rec_get_nth_field_old(rec, 7, &len); diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 20f522c1a60..69c076d78f3 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -181,6 +181,11 @@ struct fil_space_struct { hash_node_t name_hash;/* hash chain the name_hash table */ rw_lock_t latch; /* latch protecting the file space storage allocation */ + UT_LIST_NODE_T(fil_space_t) unflushed_spaces; + /* list of spaces with at least one unflushed + file we have written to */ + ibool is_in_unflushed_spaces; /* TRUE if this space is + currently in the list above */ UT_LIST_NODE_T(fil_space_t) space_list; /* list of all spaces */ ibuf_data_t* ibuf_data; @@ -213,6 +218,12 @@ struct fil_system_struct { not put to this list: they are opened after the startup, and kept open until shutdown */ + UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces; + /* base node for the list of those + tablespaces whose files contain + unflushed writes; those spaces have + at least one file node where + modification_counter > flush_counter */ ulint n_open; /* number of files currently open */ ulint max_n_open; /* n_open is not allowed to exceed this */ @@ -389,6 +400,36 @@ fil_space_get_ibuf_data( return(space->ibuf_data); } +/************************************************************************** +Checks if all the file nodes in a space are flushed. The caller must hold +the fil_system mutex. */ +static +ibool +fil_space_is_flushed( +/*=================*/ + /* out: TRUE if all are flushed */ + fil_space_t* space) /* in: space */ +{ + fil_node_t* node; + +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(fil_system->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + node = UT_LIST_GET_FIRST(space->chain); + + while (node) { + if (node->modification_counter > node->flush_counter) { + + return(FALSE); + } + + node = UT_LIST_GET_NEXT(chain, node); + } + + return(TRUE); +} + /*********************************************************************** Appends a new file to the chain of files of a space. File must be closed. */ @@ -841,6 +882,16 @@ fil_node_free( node->modification_counter = node->flush_counter; + if (space->is_in_unflushed_spaces + && fil_space_is_flushed(space)) { + + space->is_in_unflushed_spaces = FALSE; + + UT_LIST_REMOVE(unflushed_spaces, + system->unflushed_spaces, + space); + } + fil_node_close_file(node, system); } @@ -1004,6 +1055,8 @@ try_again: HASH_INSERT(fil_space_t, name_hash, system->name_hash, ut_fold_string(name), space); + space->is_in_unflushed_spaces = FALSE; + UT_LIST_ADD_LAST(space_list, system->space_list, space); mutex_exit(&(system->mutex)); @@ -1099,6 +1152,13 @@ fil_space_free( HASH_DELETE(fil_space_t, name_hash, system->name_hash, ut_fold_string(space->name), space); + if (space->is_in_unflushed_spaces) { + space->is_in_unflushed_spaces = FALSE; + + UT_LIST_REMOVE(unflushed_spaces, system->unflushed_spaces, + space); + } + UT_LIST_REMOVE(space_list, system->space_list, space); ut_a(space->magic_n == FIL_SPACE_MAGIC_N); @@ -1250,6 +1310,7 @@ fil_system_create( system->tablespace_version = 0; + UT_LIST_INIT(system->unflushed_spaces); UT_LIST_INIT(system->space_list); return(system); @@ -3742,6 +3803,14 @@ fil_node_complete_io( if (type == OS_FILE_WRITE) { system->modification_counter++; node->modification_counter = system->modification_counter; + + if (!node->space->is_in_unflushed_spaces) { + + node->space->is_in_unflushed_spaces = TRUE; + UT_LIST_ADD_FIRST(unflushed_spaces, + system->unflushed_spaces, + node->space); + } } if (node->n_pending == 0 && node->space->purpose == FIL_TABLESPACE @@ -4162,6 +4231,16 @@ retry: skip_flush: if (node->flush_counter < old_mod_counter) { node->flush_counter = old_mod_counter; + + if (space->is_in_unflushed_spaces + && fil_space_is_flushed(space)) { + + space->is_in_unflushed_spaces = FALSE; + + UT_LIST_REMOVE(unflushed_spaces, + system->unflushed_spaces, + space); + } } if (space->purpose == FIL_TABLESPACE) { @@ -4193,7 +4272,7 @@ fil_flush_file_spaces( mutex_enter(&(system->mutex)); - space = UT_LIST_GET_FIRST(system->space_list); + space = UT_LIST_GET_FIRST(system->unflushed_spaces); while (space) { if (space->purpose == purpose && !space->is_being_deleted) { @@ -4209,7 +4288,7 @@ fil_flush_file_spaces( space->n_pending_flushes--; } - space = UT_LIST_GET_NEXT(space_list, space); + space = UT_LIST_GET_NEXT(unflushed_spaces, space); } mutex_exit(&(system->mutex)); diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 15650f22ed8..dd4862b3808 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -126,14 +126,8 @@ by one. */ #ifdef __WIN__ #define UNIV_INLINE __inline #else -/* config.h contains the right def for 'inline' for the current compiler */ -#if (__GNUC__ == 2) -#define UNIV_INLINE extern inline -#else -/* extern inline doesn't work with gcc 3.0.2 */ #define UNIV_INLINE static inline #endif -#endif #else /* If we want to compile a noninlined version we use the following macro diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 487e8f40a39..8bafb73baf8 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -317,28 +317,28 @@ os_event_wait( os_fast_mutex_lock(&(event->os_mutex)); old_signal_count = event->signal_count; -loop: - if (event->is_set == TRUE - || event->signal_count != old_signal_count) { - os_fast_mutex_unlock(&(event->os_mutex)); + for (;;) { + if (event->is_set == TRUE + || event->signal_count != old_signal_count) { - if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_fast_mutex_unlock(&(event->os_mutex)); - os_thread_exit(NULL); - } - /* Ok, we may return */ + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { - return; - } + os_thread_exit(NULL); + } + /* Ok, we may return */ - pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); + return; + } - /* Solaris manual said that spurious wakeups may occur: we have to - check if the event really has been signaled after we came here to - wait */ + pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); - goto loop; + /* Solaris manual said that spurious wakeups may occur: we + have to check if the event really has been signaled after + we came here to wait */ + } #endif } diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 4f99f340e1c..b345a27af20 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -233,6 +233,13 @@ srv_parse_data_file_paths_and_sizes( } } + if (i == 0) { + /* If innodb_data_file_path was defined it must contain + at least one data file definition */ + + return(FALSE); + } + *data_file_names = (char**)ut_malloc(i * sizeof(void*)); *data_file_sizes = (ulint*)ut_malloc(i * sizeof(ulint)); *data_file_is_raw_partition = (ulint*)ut_malloc(i * sizeof(ulint)); @@ -379,6 +386,13 @@ srv_parse_log_group_home_dirs( } } + if (i != 1) { + /* If innodb_log_group_home_dir was defined it must + contain exactly one path definition under current MySQL */ + + return(FALSE); + } + *log_group_home_dirs = (char**) ut_malloc(i * sizeof(void*)); /* Then store the actual values to our array */ diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 0816d0de43c..163b9302b5c 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3180,3 +3180,74 @@ a hex(b) 7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2 update t1 set b = 'three' where a = 6; drop table t1; +CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; +CREATE TABLE t2(a INT) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; +ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) default NULL, + KEY `t2_ibfk_0` (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t2,t1; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +commit; +set autocommit = 0; +update t1 set b = 5 where a = 2; +create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +set autocommit = 0; +insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +commit; +commit; +drop trigger t1t; +drop table t1; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +insert into t2(a) values (1),(2),(3); +insert into t3(a) values (1),(2),(3); +insert into t4(a) values (1),(2),(3); +insert into t3(a) values (5),(7),(8); +insert into t4(a) values (5),(7),(8); +insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); +create trigger t1t before insert on t1 for each row begin +INSERT INTO t2 SET a = NEW.a; +end | +create trigger t2t before insert on t2 for each row begin +DELETE FROM t3 WHERE a = NEW.a; +end | +create trigger t3t before delete on t3 for each row begin +UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +end | +create trigger t4t before update on t4 for each row begin +UPDATE t5 SET b = b + 1 where a = NEW.a; +end | +commit; +set autocommit = 0; +update t1 set b = b + 5 where a = 1; +update t2 set b = b + 5 where a = 1; +update t3 set b = b + 5 where a = 1; +update t4 set b = b + 5 where a = 1; +insert into t5(a) values(20); +set autocommit = 0; +insert into t1(a) values(7); +insert into t2(a) values(8); +delete from t2 where a = 3; +update t4 set b = b + 1 where a = 3; +commit; +drop trigger t1t; +drop trigger t2t; +drop trigger t3t; +drop trigger t4t; +drop table t1, t2, t3, t4, t5; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 8d2f18e2362..a47e635cf74 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2047,3 +2047,105 @@ insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1 select a,hex(b) from t1 order by b; update t1 set b = 'three' where a = 6; drop table t1; + +# Ensure that <tablename>_ibfk_0 is not mistreated as a +# generated foreign key identifier. (Bug #16387) + +CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; +CREATE TABLE t2(a INT) ENGINE=InnoDB; +ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; +ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); +ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; +SHOW CREATE TABLE t2; +DROP TABLE t2,t1; + +# +# Test case for bug #16229: MySQL/InnoDB uses full explicit table locks in trigger processing +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +commit; +connection b; +set autocommit = 0; +update t1 set b = 5 where a = 2; +connection a; +delimiter |; +create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +delimiter ;| +set autocommit = 0; +connection a; +insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +connection b; +commit; +connection a; +commit; +drop trigger t1t; +drop table t1; +disconnect a; +disconnect b; +# +# Another trigger test +# +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +insert into t1(a) values (1),(2),(3); +insert into t2(a) values (1),(2),(3); +insert into t3(a) values (1),(2),(3); +insert into t4(a) values (1),(2),(3); +insert into t3(a) values (5),(7),(8); +insert into t4(a) values (5),(7),(8); +insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); + +delimiter |; +create trigger t1t before insert on t1 for each row begin + INSERT INTO t2 SET a = NEW.a; +end | + +create trigger t2t before insert on t2 for each row begin + DELETE FROM t3 WHERE a = NEW.a; +end | + +create trigger t3t before delete on t3 for each row begin + UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +end | + +create trigger t4t before update on t4 for each row begin + UPDATE t5 SET b = b + 1 where a = NEW.a; +end | +delimiter ;| +commit; +set autocommit = 0; +update t1 set b = b + 5 where a = 1; +update t2 set b = b + 5 where a = 1; +update t3 set b = b + 5 where a = 1; +update t4 set b = b + 5 where a = 1; +insert into t5(a) values(20); +connection b; +set autocommit = 0; +insert into t1(a) values(7); +insert into t2(a) values(8); +delete from t2 where a = 3; +update t4 set b = b + 1 where a = 3; +commit; +drop trigger t1t; +drop trigger t2t; +drop trigger t3t; +drop trigger t4t; +drop table t1, t2, t3, t4, t5; +disconnect a; +disconnect b; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index b33d2dfbd97..1b1326920ad 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -138,8 +138,6 @@ extern "C" { #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */ #define HA_INNOBASE_RANGE_COUNT 100 -uint innobase_init_flags = 0; -ulong innobase_cache_size = 0; ulong innobase_large_page_size = 0; /* The default values for the following, type long or longlong, start-up @@ -187,8 +185,6 @@ it every INNOBASE_WAKE_INTERVAL'th step. */ #define INNOBASE_WAKE_INTERVAL 32 ulong innobase_active_counter = 0; -char* innobase_home = NULL; - static HASH innobase_open_tables; #ifdef __NETWARE__ /* some special cleanup for NetWare */ @@ -814,7 +810,6 @@ ha_innobase::ha_innobase(TABLE *table_arg) HA_PRIMARY_KEY_IN_READ_INDEX | HA_CAN_GEOMETRY | HA_TABLE_SCAN_ON_INDEX), - last_dup_key((uint) -1), start_of_scan(0), num_write_row(0) {} @@ -983,6 +978,11 @@ innobase_query_caching_of_table_permitted( sql_print_error("The calling thread is holding the adaptive " "search, latch though calling " "innobase_query_caching_of_table_permitted."); + + mutex_enter_noninline(&kernel_mutex); + trx_print(stderr, trx, 1024); + mutex_exit_noninline(&kernel_mutex); + ut_error; } innobase_release_stat_resources(trx); @@ -6329,14 +6329,17 @@ ha_innobase::external_lock( TABLES if AUTOCOMMIT=1. It does not make much sense to acquire an InnoDB table lock if it is released immediately at the end of LOCK TABLES, and InnoDB's table locks in that case cause - VERY easily deadlocks. We do not set InnoDB table locks when - MySQL sets them at the start of a stored procedure call - (MySQL does have thd->in_lock_tables TRUE there). */ + VERY easily deadlocks. + + We do not set InnoDB table locks if user has not explicitly + requested a table lock. Note that thd->in_lock_tables + can be TRUE on some cases e.g. at the start of a stored + procedure call (SQLCOM_CALL). */ if (prebuilt->select_lock_type != LOCK_NONE) { if (thd->in_lock_tables && - thd->lex->sql_command != SQLCOM_CALL && + thd->lex->sql_command == SQLCOM_LOCK_TABLES && thd->variables.innodb_table_locks && (thd->options & OPTION_NOT_AUTOCOMMIT)) { @@ -6838,7 +6841,7 @@ ha_innobase::store_lock( } else if (lock_type != TL_IGNORE) { - /* We set possible LOCK_X value in external_lock, not yet + /* We set possible LOCK_X value in external_lock, not yet here even if this would be SELECT ... FOR UPDATE */ prebuilt->select_lock_type = LOCK_NONE; @@ -6847,7 +6850,7 @@ ha_innobase::store_lock( if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { - /* Starting from 5.0.7, we weaken also the table locks + /* Starting from 5.0.7, we weaken also the table locks set at the start of a MySQL stored procedure call, just like we weaken the locks set at the start of an SQL statement. MySQL does set thd->in_lock_tables TRUE there, but in reality @@ -6870,26 +6873,36 @@ ha_innobase::store_lock( lock_type = TL_READ_NO_INSERT; } - /* If we are not doing a LOCK TABLE or DISCARD/IMPORT - TABLESPACE or TRUNCATE TABLE, then allow multiple writers */ + /* If we are not doing a LOCK TABLE, DISCARD/IMPORT + TABLESPACE or TRUNCATE TABLE then allow multiple + writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ + < TL_WRITE_CONCURRENT_INSERT. - if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) + We especially allow multiple writers if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) + (MySQL does have thd->in_lock_tables TRUE there). */ + + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT + && lock_type <= TL_WRITE) && (!thd->in_lock_tables - || thd->lex->sql_command == SQLCOM_CALL) + || thd->lex->sql_command == SQLCOM_CALL) && !thd->tablespace_op && thd->lex->sql_command != SQLCOM_TRUNCATE - && thd->lex->sql_command != SQLCOM_OPTIMIZE - && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { + && thd->lex->sql_command != SQLCOM_OPTIMIZE + && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { - lock_type = TL_WRITE_ALLOW_WRITE; + lock_type = TL_WRITE_ALLOW_WRITE; } /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... MySQL would use the lock TL_READ_NO_INSERT on t2, and that would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts to t2. Convert the lock to a normal read lock to allow - concurrent inserts to t2. */ + concurrent inserts to t2. + + We especially allow concurrent inserts if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) + (MySQL does have thd->in_lock_tables TRUE there). */ if (lock_type == TL_READ_NO_INSERT && (!thd->in_lock_tables @@ -6898,10 +6911,10 @@ ha_innobase::store_lock( lock_type = TL_READ; } - lock.type = lock_type; - } + lock.type = lock_type; + } - *to++= &lock; + *to++= &lock; return(to); } diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index aa8506abe6d..fb93b2abb0e 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -52,7 +52,6 @@ class ha_innobase: public handler THR_LOCK_DATA lock; INNOBASE_SHARE *share; - gptr alloc_ptr; byte* upd_buff; /* buffer used in updates */ byte* key_val_buff; /* buffer used in converting search key values from MySQL format @@ -62,7 +61,6 @@ class ha_innobase: public handler two buffers */ ulong int_table_flags; uint primary_key; - uint last_dup_key; ulong start_of_scan; /* this is set to 1 when we are starting a table scan but have not yet fetched any row, else 0 */ @@ -70,7 +68,6 @@ class ha_innobase: public handler ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, or undefined */ uint num_write_row; /* number of write_row() calls */ - ulong max_supported_row_length(const byte *buf); uint store_key_val_for_row(uint keynr, char* buff, uint buff_len, const byte* record); @@ -199,11 +196,8 @@ class ha_innobase: public handler }; extern struct show_var_st innodb_status_variables[]; -extern uint innobase_init_flags, innobase_lock_type; -extern ulong innobase_cache_size, innobase_fast_shutdown; +extern ulong innobase_fast_shutdown; extern ulong innobase_large_page_size; -extern char *innobase_home, *innobase_tmpdir, *innobase_logdir; -extern long innobase_lock_scan_time; extern long innobase_mirrored_log_groups, innobase_log_files_in_group; extern longlong innobase_buffer_pool_size, innobase_log_file_size; extern long innobase_log_buffer_size; @@ -240,8 +234,6 @@ extern ulong srv_commit_concurrency; extern ulong srv_flush_log_at_trx_commit; } -extern TYPELIB innobase_lock_typelib; - bool innobase_init(void); bool innobase_end(void); bool innobase_flush_logs(void); @@ -311,9 +303,6 @@ int innobase_rollback_by_xid( XID *xid); /* in : X/Open XA Transaction Identification */ -int innobase_xa_end(THD *thd); - - int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, my_off_t end_offset); |