diff --git a/README b/README index 8b6ccdfe5cf..92eae28a64f 100644 --- a/README +++ b/README @@ -1,50 +1,47 @@ -This is a release of MySQL, a dual-license SQL database server. -MySQL is brought to you by the MySQL team at Sun Microsystems, Inc. +This is a release of MariaDB, a branch of MySQL. + +MariaDB is a drop-in replacement of MySQL, with more features, less +bugs and better performance. + +MariaDB is brought to you by many of the original developers of MySQL, +that now work for Monty Program Ab, and by many people in the +community. + +MySQL, which is the base of MariaDB, is brought to you by Sun. License information can be found in these files: - For GPL (free) distributions, see the COPYING file and the EXCEPTIONS-CLIENT file. -- For commercial distributions, see the LICENSE.mysql file. -GPLv2 Disclaimer -For the avoidance of doubt, except that if any license choice -other than GPL or LGPL is available it will apply instead, Sun -elects to use only the General Public License version 2 (GPLv2) -at this time for any software where a choice of GPL license versions -is made available with the language indicating that GPLv2 or any -later version may be used, or where a choice of which version of -the GPL is applied is otherwise unspecified. +A description of the MariaDB project can be found at: +http://askmonty.org/wiki/index.php/MariaDB -For further information about MySQL or additional documentation, see: -- The latest information about MySQL: http://www.mysql.com -- The current MySQL documentation: http://dev.mysql.com/doc +The differences between MariaDB and MySQL can be found at: +http://askmonty.org/wiki/index.php/MariaDB_versus_MySQL + +Documentation about MySQL can be found at: +http://dev.mysql.com/doc + +For further information about MySQL documentation, see: +- The current MySQL documentation: Some manual sections of special interest: -- If you are migrating from an older version of MySQL, please read the - "Upgrading from..." section first! -- To see what MySQL can do, take a look at the features section. -- For installation instructions, see the Installing and Upgrading -chapter. -- For the new features/bugfix history, see the Change History appendix. -- For the currently known bugs/misfeatures (known errors) see the -Problems - and Common Errors appendix. - For a list of developers and other contributors, see the Credits appendix. A local copy of the MySQL Reference Manual can be found in the Docs directory in GNU Info format. You can also browse the manual online or -download it in any of several formats at the URL given earlier in this -file. +download it in any of several formats from +http://dev.mysql.com/doc ************************************************************ IMPORTANT: -Bug or error reports should be sent to http://bugs.mysql.com. - - +Bug or error reports regarding MariaDB should be sent to +https://bugs.launchpad.net/maria +Bugs in the MySQL code can also be sent to http://bugs.mysql.com *************************************************************************** %%The following software may be included in this product: diff --git a/mysql-test/patches/events_stress.diff b/mysql-test/patches/events_stress.diff new file mode 100644 index 00000000000..afbd3b51c1d --- /dev/null +++ b/mysql-test/patches/events_stress.diff @@ -0,0 +1,33 @@ +--- mysql-test/t/events_stress.test.orig 2009-07-05 10:29:14.000000000 +0000 ++++ mysql-test/t/events_stress.test 2009-07-05 10:30:49.000000000 +0000 +@@ -61,6 +61,7 @@ + } + --enable_query_log + SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2'; ++SET @old_event_scheduler=@@event_scheduler; + SET GLOBAL event_scheduler=on; + --sleep 2.5 + DROP DATABASE events_conn1_test2; +@@ -137,5 +138,5 @@ + DROP DATABASE events_test; + + # Cleanup +-SET GLOBAL event_scheduler=off; ++SET GLOBAL event_scheduler=@old_event_scheduler; + --source include/check_events_off.inc +--- mysql-test/r/events_stress.result.orig 2009-07-05 10:54:30.000000000 +0000 ++++ mysql-test/r/events_stress.result 2009-07-05 10:54:48.000000000 +0000 +@@ -32,6 +32,7 @@ + SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2'; + COUNT(*) + 50 ++SET @old_event_scheduler=@@event_scheduler; + SET GLOBAL event_scheduler=on; + DROP DATABASE events_conn1_test2; + SET GLOBAL event_scheduler=off; +@@ -63,4 +64,4 @@ + DROP TABLE fill_it2; + DROP TABLE fill_it3; + DROP DATABASE events_test; +-SET GLOBAL event_scheduler=off; ++SET GLOBAL event_scheduler=@old_event_scheduler; diff --git a/mysql-test/patches/information_schema.diff b/mysql-test/patches/information_schema.diff new file mode 100644 index 00000000000..4d67ed3f82d --- /dev/null +++ b/mysql-test/patches/information_schema.diff @@ -0,0 +1,129 @@ +--- mysql-test/r/information_schema.result.orig 2009-06-25 21:33:28.000000000 +0000 ++++ mysql-test/r/information_schema.result 2009-06-25 21:33:49.000000000 +0000 +@@ -71,6 +71,20 @@ + TRIGGERS + USER_PRIVILEGES + VIEWS ++INNODB_BUFFER_POOL_PAGES_INDEX ++INNODB_RSEG ++INNODB_LOCKS ++INNODB_BUFFER_POOL_PAGES ++XTRADB_ENHANCEMENTS ++INNODB_TRX ++INNODB_INDEX_STATS ++INNODB_LOCK_WAITS ++INNODB_CMP_RESET ++INNODB_CMP ++INNODB_CMPMEM_RESET ++INNODB_BUFFER_POOL_PAGES_BLOB ++INNODB_CMPMEM ++INNODB_TABLE_STATS + columns_priv + db + event +@@ -799,6 +813,8 @@ + TABLES UPDATE_TIME datetime + TABLES CHECK_TIME datetime + TRIGGERS CREATED datetime ++INNODB_TRX trx_started datetime ++INNODB_TRX trx_wait_started datetime + event execute_at datetime + event last_executed datetime + event starts datetime +@@ -847,12 +863,15 @@ + TABLE_CONSTRAINTS TABLE_NAME select + TABLE_PRIVILEGES TABLE_NAME select + VIEWS TABLE_NAME select ++INNODB_BUFFER_POOL_PAGES_INDEX table_name select ++INNODB_INDEX_STATS table_name select ++INNODB_TABLE_STATS table_name select + delete from mysql.user where user='mysqltest_4'; + delete from mysql.db where user='mysqltest_4'; + flush privileges; + SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; + table_schema count(*) +-information_schema 28 ++information_schema 42 + mysql 22 + create table t1 (i int, j int); + create trigger trg1 before insert on t1 for each row +@@ -1267,6 +1286,20 @@ + TRIGGERS TRIGGER_SCHEMA + USER_PRIVILEGES GRANTEE + VIEWS TABLE_SCHEMA ++INNODB_BUFFER_POOL_PAGES_INDEX schema_name ++INNODB_RSEG rseg_id ++INNODB_LOCKS lock_id ++INNODB_BUFFER_POOL_PAGES page_type ++XTRADB_ENHANCEMENTS name ++INNODB_TRX trx_id ++INNODB_INDEX_STATS table_name ++INNODB_LOCK_WAITS requesting_trx_id ++INNODB_CMP_RESET page_size ++INNODB_CMP page_size ++INNODB_CMPMEM_RESET page_size ++INNODB_BUFFER_POOL_PAGES_BLOB space_id ++INNODB_CMPMEM page_size ++INNODB_TABLE_STATS table_name + SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN +@@ -1310,14 +1343,28 @@ + TRIGGERS TRIGGER_SCHEMA + USER_PRIVILEGES GRANTEE + VIEWS TABLE_SCHEMA ++INNODB_BUFFER_POOL_PAGES_INDEX schema_name ++INNODB_RSEG rseg_id ++INNODB_LOCKS lock_id ++INNODB_BUFFER_POOL_PAGES page_type ++XTRADB_ENHANCEMENTS name ++INNODB_TRX trx_id ++INNODB_INDEX_STATS table_name ++INNODB_LOCK_WAITS requesting_trx_id ++INNODB_CMP_RESET page_size ++INNODB_CMP page_size ++INNODB_CMPMEM_RESET page_size ++INNODB_BUFFER_POOL_PAGES_BLOB space_id ++INNODB_CMPMEM page_size ++INNODB_TABLE_STATS table_name + SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'); + MAX(table_name) +-VIEWS ++XTRADB_ENHANCEMENTS + SELECT table_name from information_schema.tables + WHERE table_name=(SELECT MAX(table_name) + FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test')); + table_name +-VIEWS ++XTRADB_ENHANCEMENTS + DROP TABLE IF EXISTS bug23037; + DROP FUNCTION IF EXISTS get_value; + SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='bug23037'; +@@ -1386,6 +1433,19 @@ + FILES information_schema.FILES 1 + GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 + GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 ++INNODB_BUFFER_POOL_PAGES information_schema.INNODB_BUFFER_POOL_PAGES 1 ++INNODB_BUFFER_POOL_PAGES_BLOB information_schema.INNODB_BUFFER_POOL_PAGES_BLOB 1 ++INNODB_BUFFER_POOL_PAGES_INDEX information_schema.INNODB_BUFFER_POOL_PAGES_INDEX 1 ++INNODB_CMP information_schema.INNODB_CMP 1 ++INNODB_CMPMEM information_schema.INNODB_CMPMEM 1 ++INNODB_CMPMEM_RESET information_schema.INNODB_CMPMEM_RESET 1 ++INNODB_CMP_RESET information_schema.INNODB_CMP_RESET 1 ++INNODB_INDEX_STATS information_schema.INNODB_INDEX_STATS 1 ++INNODB_LOCKS information_schema.INNODB_LOCKS 1 ++INNODB_LOCK_WAITS information_schema.INNODB_LOCK_WAITS 1 ++INNODB_RSEG information_schema.INNODB_RSEG 1 ++INNODB_TABLE_STATS information_schema.INNODB_TABLE_STATS 1 ++INNODB_TRX information_schema.INNODB_TRX 1 + KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 + PARTITIONS information_schema.PARTITIONS 1 + PLUGINS information_schema.PLUGINS 1 +@@ -1404,6 +1464,7 @@ + TRIGGERS information_schema.TRIGGERS 1 + USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 + VIEWS information_schema.VIEWS 1 ++XTRADB_ENHANCEMENTS information_schema.XTRADB_ENHANCEMENTS 1 + create table t1(f1 int); + create view v1 as select f1+1 as a from t1; + create table t2 (f1 int, f2 int); diff --git a/mysql-test/patches/information_schema_db.diff b/mysql-test/patches/information_schema_db.diff new file mode 100644 index 00000000000..de7f52e8275 --- /dev/null +++ b/mysql-test/patches/information_schema_db.diff @@ -0,0 +1,23 @@ +--- mysql-test/r/information_schema_db.result.orig 2009-06-25 21:41:38.000000000 +0000 ++++ mysql-test/r/information_schema_db.result 2009-06-25 21:42:01.000000000 +0000 +@@ -33,6 +33,20 @@ + TRIGGERS + USER_PRIVILEGES + VIEWS ++INNODB_BUFFER_POOL_PAGES_INDEX ++INNODB_RSEG ++INNODB_LOCKS ++INNODB_BUFFER_POOL_PAGES ++XTRADB_ENHANCEMENTS ++INNODB_TRX ++INNODB_INDEX_STATS ++INNODB_LOCK_WAITS ++INNODB_CMP_RESET ++INNODB_CMP ++INNODB_CMPMEM_RESET ++INNODB_BUFFER_POOL_PAGES_BLOB ++INNODB_CMPMEM ++INNODB_TABLE_STATS + show tables from INFORMATION_SCHEMA like 'T%'; + Tables_in_information_schema (T%) + TABLES diff --git a/mysql-test/patches/mysqlshow.diff b/mysql-test/patches/mysqlshow.diff new file mode 100644 index 00000000000..7c02b9d8bf7 --- /dev/null +++ b/mysql-test/patches/mysqlshow.diff @@ -0,0 +1,44 @@ +--- mysql-test/r/mysqlshow.result.orig 2009-06-25 21:56:22.000000000 +0000 ++++ mysql-test/r/mysqlshow.result 2009-06-25 21:56:28.000000000 +0000 +@@ -107,6 +107,20 @@ + | TRIGGERS | + | USER_PRIVILEGES | + | VIEWS | ++| INNODB_BUFFER_POOL_PAGES_INDEX | ++| INNODB_RSEG | ++| INNODB_LOCKS | ++| INNODB_BUFFER_POOL_PAGES | ++| XTRADB_ENHANCEMENTS | ++| INNODB_TRX | ++| INNODB_INDEX_STATS | ++| INNODB_LOCK_WAITS | ++| INNODB_CMP_RESET | ++| INNODB_CMP | ++| INNODB_CMPMEM_RESET | ++| INNODB_BUFFER_POOL_PAGES_BLOB | ++| INNODB_CMPMEM | ++| INNODB_TABLE_STATS | + +---------------------------------------+ + Database: INFORMATION_SCHEMA + +---------------------------------------+ +@@ -140,6 +154,20 @@ + | TRIGGERS | + | USER_PRIVILEGES | + | VIEWS | ++| INNODB_BUFFER_POOL_PAGES_INDEX | ++| INNODB_RSEG | ++| INNODB_LOCKS | ++| INNODB_BUFFER_POOL_PAGES | ++| XTRADB_ENHANCEMENTS | ++| INNODB_TRX | ++| INNODB_INDEX_STATS | ++| INNODB_LOCK_WAITS | ++| INNODB_CMP_RESET | ++| INNODB_CMP | ++| INNODB_CMPMEM_RESET | ++| INNODB_BUFFER_POOL_PAGES_BLOB | ++| INNODB_CMPMEM | ++| INNODB_TABLE_STATS | + +---------------------------------------+ + Wildcard: inf_rmation_schema + +--------------------+ diff --git a/storage/xtradb/buf/buf0flu.c b/storage/xtradb/buf/buf0flu.c index 9acf4f50bf1..7da5fca26dc 100644 --- a/storage/xtradb/buf/buf0flu.c +++ b/storage/xtradb/buf/buf0flu.c @@ -108,6 +108,20 @@ buf_flush_insert_sorted_into_flush_list( prev_b = NULL; b = UT_LIST_GET_FIRST(buf_pool->flush_list); + if (srv_fast_recovery) { + /* speed hack */ + if (b == NULL || b->oldest_modification < block->page.oldest_modification) { + UT_LIST_ADD_FIRST(flush_list, buf_pool->flush_list, &block->page); + } else { + b = UT_LIST_GET_LAST(buf_pool->flush_list); + if (b->oldest_modification < block->page.oldest_modification) { + /* align oldest_modification not to sort */ + block->page.oldest_modification = b->oldest_modification; + } + UT_LIST_ADD_LAST(flush_list, buf_pool->flush_list, &block->page); + } + } else { + /* normal */ while (b && b->oldest_modification > block->page.oldest_modification) { ut_ad(b->in_flush_list); prev_b = b; @@ -120,6 +134,7 @@ buf_flush_insert_sorted_into_flush_list( UT_LIST_INSERT_AFTER(flush_list, buf_pool->flush_list, prev_b, &block->page); } + } #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG ut_a(buf_flush_validate_low()); @@ -886,8 +901,9 @@ buf_flush_try_neighbors( /* out: number of pages flushed */ ulint space, /* in: space id */ ulint offset, /* in: page offset */ - enum buf_flush flush_type) /* in: BUF_FLUSH_LRU or + enum buf_flush flush_type, /* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */ + ulint flush_neighbors) { buf_page_t* bpage; ulint low, high; @@ -896,7 +912,7 @@ buf_flush_try_neighbors( ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); - if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) { + if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN || !flush_neighbors) { /* If there is little space, it is better not to flush any block except from the end of the LRU list */ @@ -1101,30 +1117,9 @@ retry_lock_1: old_page_count = page_count; - if (srv_flush_neighbor_pages) { /* Try to flush also all the neighbors */ page_count += buf_flush_try_neighbors( - space, offset, flush_type); - } else { - /* Try to flush the page only */ - //buf_pool_mutex_enter(); - rw_lock_s_lock(&page_hash_latch); - - mutex_t* block_mutex = buf_page_get_mutex(bpage); -retry_lock_2: - mutex_enter(block_mutex); - if (block_mutex != buf_page_get_mutex(bpage)) { - mutex_exit(block_mutex); - block_mutex = buf_page_get_mutex(bpage); - goto retry_lock_2; - } - - buf_page_t* bpage_tmp = buf_page_hash_get(space, offset); - if (bpage_tmp) { - buf_flush_page(bpage_tmp, flush_type); - page_count++; - } - } + space, offset, flush_type, srv_flush_neighbor_pages); /* fprintf(stderr, "Flush type %lu, page no %lu, neighb %lu\n", flush_type, offset, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 4e6549de3e0..241408779bb 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -155,6 +155,7 @@ static long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_additional_mem_pool_size, innobase_file_io_threads, innobase_force_recovery, innobase_open_files, innobase_autoinc_lock_mode; +static unsigned long innobase_commit_concurrency = 0; static unsigned long innobase_read_io_threads, innobase_write_io_threads; static my_bool innobase_thread_concurrency_timer_based; @@ -189,6 +190,7 @@ static char* innobase_log_arch_dir = NULL; static my_bool innobase_use_doublewrite = TRUE; static my_bool innobase_use_checksums = TRUE; static my_bool innobase_extra_undoslots = FALSE; +static my_bool innobase_fast_recovery = FALSE; static my_bool innobase_locks_unsafe_for_binlog = FALSE; static my_bool innobase_overwrite_relay_log_info = FALSE; static my_bool innobase_rollback_on_timeout = FALSE; @@ -272,6 +274,53 @@ innobase_alter_table_flags( static const char innobase_hton_name[]= "InnoDB"; +/** @brief Initialize the default value of innodb_commit_concurrency. + +Once InnoDB is running, the innodb_commit_concurrency must not change +from zero to nonzero. (Bug #42101) + +The initial default value is 0, and without this extra initialization, +SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter +to 0, even if it was initially set to nonzero at the command line +or configuration file. */ +static +void +innobase_commit_concurrency_init_default(void); +/*==========================================*/ + +/***************************************************************** +Check for a valid value of innobase_commit_concurrency. */ +static +int +innobase_commit_concurrency_validate( +/*=================================*/ + /* out: 0 for valid + innodb_commit_concurrency */ + THD* thd, /* in: thread handle */ + struct st_mysql_sys_var* var, /* in: pointer to system + variable */ + void* save, /* out: immediate result + for update function */ + struct st_mysql_value* value) /* in: incoming string */ +{ + long long intbuf; + ulong commit_concurrency; + + DBUG_ENTER("innobase_commit_concurrency_validate"); + + if (value->val_int(value, &intbuf)) { + /* The value is NULL. That is invalid. */ + DBUG_RETURN(1); + } + + *reinterpret_cast(save) = commit_concurrency + = static_cast(intbuf); + + /* Allow the value to be updated, as long as it remains zero + or nonzero. */ + DBUG_RETURN(!(!commit_concurrency == !innobase_commit_concurrency)); +} + static MYSQL_THDVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG, "Enable InnoDB support for the XA two-phase commit", /* check_func */ NULL, /* update_func */ NULL, @@ -2219,6 +2268,8 @@ mem_free_and_error: srv_force_recovery = (ulint) innobase_force_recovery; + srv_fast_recovery = (ibool) innobase_fast_recovery; + srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite; srv_use_checksums = (ibool) innobase_use_checksums; @@ -2253,6 +2304,8 @@ mem_free_and_error: ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; + innobase_commit_concurrency_init_default(); + /* Since we in this module access directly the fields of a trx struct, and due to different headers and flags it might happen that mutex_t has a different size in this module and in InnoDB @@ -2576,11 +2629,11 @@ innobase_commit( Note, the position is current because of prepare_commit_mutex */ retry: - if (srv_commit_concurrency > 0) { + if (innobase_commit_concurrency > 0) { pthread_mutex_lock(&commit_cond_m); commit_threads++; - if (commit_threads > srv_commit_concurrency) { + if (commit_threads > innobase_commit_concurrency) { commit_threads--; pthread_cond_wait(&commit_cond, &commit_cond_m); @@ -2597,7 +2650,7 @@ retry: innobase_commit_low(trx); - if (srv_commit_concurrency > 0) { + if (innobase_commit_concurrency > 0) { pthread_mutex_lock(&commit_cond_m); commit_threads--; pthread_cond_signal(&commit_cond); @@ -9297,6 +9350,97 @@ innobase_set_cursor_view( } +/*********************************************************************** +Check whether any of the given columns is being renamed in the table. */ +static +bool +column_is_being_renamed( +/*====================*/ + /* out: true if any of col_names is + being renamed in table */ + TABLE* table, /* in: MySQL table */ + uint n_cols, /* in: number of columns */ + const char** col_names) /* in: names of the columns */ +{ + uint j; + uint k; + Field* field; + const char* col_name; + + for (j = 0; j < n_cols; j++) { + col_name = col_names[j]; + for (k = 0; k < table->s->fields; k++) { + field = table->field[k]; + if ((field->flags & FIELD_IS_RENAMED) + && innobase_strcasecmp(field->field_name, + col_name) == 0) { + return(true); + } + } + } + + return(false); +} + +/*********************************************************************** +Check whether a column in table "table" is being renamed and if this column +is part of a foreign key, either part of another table, referencing this +table or part of this table, referencing another table. */ +static +bool +foreign_key_column_is_being_renamed( +/*================================*/ + /* out: true if a column that + participates in a foreign key definition + is being renamed */ + row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */ + TABLE* table) /* in: MySQL table */ +{ + dict_foreign_t* foreign; + + /* check whether there are foreign keys at all */ + if (UT_LIST_GET_LEN(prebuilt->table->foreign_list) == 0 + && UT_LIST_GET_LEN(prebuilt->table->referenced_list) == 0) { + /* no foreign keys involved with prebuilt->table */ + + return(false); + } + + row_mysql_lock_data_dictionary(prebuilt->trx); + + /* Check whether any column in the foreign key constraints which refer + to this table is being renamed. */ + for (foreign = UT_LIST_GET_FIRST(prebuilt->table->referenced_list); + foreign != NULL; + foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + + if (column_is_being_renamed(table, foreign->n_fields, + foreign->referenced_col_names)) { + + row_mysql_unlock_data_dictionary(prebuilt->trx); + return(true); + } + } + + /* Check whether any column in the foreign key constraints in the + table is being renamed. */ + for (foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list); + foreign != NULL; + foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + + if (column_is_being_renamed(table, foreign->n_fields, + foreign->foreign_col_names)) { + + row_mysql_unlock_data_dictionary(prebuilt->trx); + return(true); + } + } + + row_mysql_unlock_data_dictionary(prebuilt->trx); + + return(false); +} + UNIV_INTERN bool ha_innobase::check_if_incompatible_data( @@ -9322,6 +9466,13 @@ ha_innobase::check_if_incompatible_data( DBUG_RETURN(COMPATIBLE_DATA_NO); } + /* Check if a column participating in a foreign key is being renamed. + There is no mechanism for updating InnoDB foreign key definitions. */ + if (foreign_key_column_is_being_renamed(prebuilt, table)) { + + return(COMPATIBLE_DATA_NO); + } + /* Check that row format didn't change */ row_type = get_row_type(); info_row_type = info->row_type; @@ -9727,6 +9878,11 @@ static MYSQL_SYSVAR_BOOL(extra_undoslots, innobase_extra_undoslots, "don't use the datafile for normal mysqld or ibbackup! ####", NULL, NULL, FALSE); +static MYSQL_SYSVAR_BOOL(fast_recovery, innobase_fast_recovery, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Enable to use speed hack of recovery avoiding flush list sorting.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_BOOL(overwrite_relay_log_info, innobase_overwrite_relay_log_info, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, "During InnoDB crash recovery on slave overwrite relay-log.info " @@ -9891,10 +10047,10 @@ static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size, "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", NULL, NULL, 8*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L); -static MYSQL_SYSVAR_ULONG(commit_concurrency, srv_commit_concurrency, +static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, PLUGIN_VAR_RQCMDARG, "Helps in performance tuning in heavily concurrent environments.", - NULL, NULL, 0, 0, 1000, 0); + innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0); static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, @@ -10120,6 +10276,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(data_home_dir), MYSQL_SYSVAR(doublewrite), MYSQL_SYSVAR(extra_undoslots), + MYSQL_SYSVAR(fast_recovery), MYSQL_SYSVAR(fast_shutdown), MYSQL_SYSVAR(file_io_threads), MYSQL_SYSVAR(file_per_table), @@ -10373,6 +10530,24 @@ i_s_innodb_index_stats, i_s_innodb_patches mysql_declare_plugin_end; +/** @brief Initialize the default value of innodb_commit_concurrency. + +Once InnoDB is running, the innodb_commit_concurrency must not change +from zero to nonzero. (Bug #42101) + +The initial default value is 0, and without this extra initialization, +SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter +to 0, even if it was initially set to nonzero at the command line +or configuration file. */ +static +void +innobase_commit_concurrency_init_default(void) +/*==========================================*/ +{ + MYSQL_SYSVAR_NAME(commit_concurrency).def_val + = innobase_commit_concurrency; +} + #ifdef UNIV_COMPILE_TEST_FUNCS typedef struct innobase_convert_name_test_struct { diff --git a/storage/xtradb/include/row0mysql.h b/storage/xtradb/include/row0mysql.h index c1e11124a5d..8e42c316209 100644 --- a/storage/xtradb/include/row0mysql.h +++ b/storage/xtradb/include/row0mysql.h @@ -695,6 +695,21 @@ struct row_prebuilt_struct { This eliminates lock waits in some cases; note that this breaks serializability. */ + ulint new_rec_locks; /* normally 0; if + srv_locks_unsafe_for_binlog is + TRUE or session is using READ + COMMITTED isolation level, in a + cursor search, if we set a new + record lock on an index, this is + incremented; this is used in + releasing the locks under the + cursors if we are performing an + UPDATE and we determine after + retrieving the row that it does + not need to be locked; thus, + these can be used to implement a + 'mini-rollback' that releases + the latest record locks */ ulint mysql_prefix_len;/* byte offset of the end of the last requested column */ ulint mysql_row_len; /* length in bytes of a row in the diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index c16c8e33057..84fe71595d7 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -97,6 +97,8 @@ extern ulint* srv_data_file_is_raw_partition; extern ibool srv_extra_undoslots; +extern ibool srv_fast_recovery; + extern ibool srv_auto_extend_last_data_file; extern ulint srv_last_file_size_max; extern ulong srv_auto_extend_increment; @@ -149,7 +151,6 @@ extern ulint srv_max_dirty_pages_pct; extern ulint srv_force_recovery; extern ulong srv_thread_concurrency; -extern ulong srv_commit_concurrency; extern ulint srv_max_n_threads; diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index e7f7539f9ee..1bec1ff73be 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -43,34 +43,6 @@ extern sess_t* trx_dummy_sess; the kernel mutex */ extern ulint trx_n_mysql_transactions; -/***************************************************************** -Resets the new record lock info in a transaction struct. */ -UNIV_INLINE -void -trx_reset_new_rec_lock_info( -/*========================*/ - trx_t* trx); /* in: transaction struct */ -/***************************************************************** -Registers that we have set a new record lock on an index. We only have space -to store 2 indexes! If this is called to store more than 2 indexes after -trx_reset_new_rec_lock_info(), then this function does nothing. */ -UNIV_INLINE -void -trx_register_new_rec_lock( -/*======================*/ - trx_t* trx, /* in: transaction struct */ - dict_index_t* index); /* in: trx sets a new record lock on this - index */ -/***************************************************************** -Checks if trx has set a new record lock on an index. */ -UNIV_INLINE -ibool -trx_new_rec_locks_contain( -/*======================*/ - /* out: TRUE if trx has set a new record lock - on index */ - trx_t* trx, /* in: transaction struct */ - dict_index_t* index); /* in: index */ /************************************************************************ Releases the search latch if trx has reserved it. */ UNIV_INTERN @@ -624,20 +596,6 @@ struct trx_struct{ to srv_conc_innodb_enter, if the value here is > 0, we decrement this by 1 */ /*------------------------------*/ - dict_index_t* new_rec_locks[2];/* these are normally NULL; if - srv_locks_unsafe_for_binlog is TRUE - or session is using READ COMMITTED - isolation level, - in a cursor search, if we set a new - record lock on an index, this is set - to point to the index; this is - used in releasing the locks under the - cursors if we are performing an UPDATE - and we determine after retrieving - the row that it does not need to be - locked; thus, these can be used to - implement a 'mini-rollback' that - releases the latest record locks */ UT_LIST_NODE_T(trx_t) trx_list; /* list of transactions */ UT_LIST_NODE_T(trx_t) diff --git a/storage/xtradb/include/trx0trx.ic b/storage/xtradb/include/trx0trx.ic index 6da89f002fe..51212539c09 100644 --- a/storage/xtradb/include/trx0trx.ic +++ b/storage/xtradb/include/trx0trx.ic @@ -55,64 +55,6 @@ trx_start_if_not_started_low( } } -/***************************************************************** -Resets the new record lock info in a transaction struct. */ -UNIV_INLINE -void -trx_reset_new_rec_lock_info( -/*========================*/ - trx_t* trx) /* in: transaction struct */ -{ - trx->new_rec_locks[0] = NULL; - trx->new_rec_locks[1] = NULL; -} - -/***************************************************************** -Registers that we have set a new record lock on an index. We only have space -to store 2 indexes! If this is called to store more than 2 indexes after -trx_reset_new_rec_lock_info(), then this function does nothing. */ -UNIV_INLINE -void -trx_register_new_rec_lock( -/*======================*/ - trx_t* trx, /* in: transaction struct */ - dict_index_t* index) /* in: trx sets a new record lock on this - index */ -{ - if (trx->new_rec_locks[0] == NULL) { - trx->new_rec_locks[0] = index; - - return; - } - - if (trx->new_rec_locks[0] == index) { - - return; - } - - if (trx->new_rec_locks[1] != NULL) { - - return; - } - - trx->new_rec_locks[1] = index; -} - -/***************************************************************** -Checks if trx has set a new record lock on an index. */ -UNIV_INLINE -ibool -trx_new_rec_locks_contain( -/*======================*/ - /* out: TRUE if trx has set a new record lock - on index */ - trx_t* trx, /* in: transaction struct */ - dict_index_t* index) /* in: index */ -{ - return(trx->new_rec_locks[0] == index - || trx->new_rec_locks[1] == index); -} - /******************************************************************** Retrieves the error_info field from a trx. */ UNIV_INLINE diff --git a/storage/xtradb/lock/lock0lock.c b/storage/xtradb/lock/lock0lock.c index 3730c66313d..9e90e099428 100644 --- a/storage/xtradb/lock/lock0lock.c +++ b/storage/xtradb/lock/lock0lock.c @@ -1976,12 +1976,6 @@ lock_rec_lock_fast( if (lock == NULL) { if (!impl) { lock_rec_create(mode, block, heap_no, index, trx); - - if (srv_locks_unsafe_for_binlog - || trx->isolation_level - == TRX_ISO_READ_COMMITTED) { - trx_register_new_rec_lock(trx, index); - } } return(TRUE); @@ -2005,11 +1999,6 @@ lock_rec_lock_fast( if (!lock_rec_get_nth_bit(lock, heap_no)) { lock_rec_set_nth_bit(lock, heap_no); - if (srv_locks_unsafe_for_binlog - || trx->isolation_level - == TRX_ISO_READ_COMMITTED) { - trx_register_new_rec_lock(trx, index); - } } } @@ -2069,22 +2058,12 @@ lock_rec_lock_slow( err = lock_rec_enqueue_waiting(mode, block, heap_no, index, thr); - - if (srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) { - trx_register_new_rec_lock(trx, index); - } } else { if (!impl) { /* Set the requested lock on the record */ lock_rec_add_to_queue(LOCK_REC | mode, block, heap_no, index, trx); - if (srv_locks_unsafe_for_binlog - || trx->isolation_level - == TRX_ISO_READ_COMMITTED) { - trx_register_new_rec_lock(trx, index); - } } err = DB_SUCCESS; diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c index 7acc330113b..3a9e1de0125 100644 --- a/storage/xtradb/row/row0mysql.c +++ b/storage/xtradb/row/row0mysql.c @@ -1452,12 +1452,9 @@ row_unlock_for_mysql( and clust_pcur, and we do not need to reposition the cursors. */ { - dict_index_t* index; btr_pcur_t* pcur = prebuilt->pcur; btr_pcur_t* clust_pcur = prebuilt->clust_pcur; trx_t* trx = prebuilt->trx; - rec_t* rec; - mtr_t mtr; ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); @@ -1477,9 +1474,12 @@ row_unlock_for_mysql( trx->op_info = "unlock_row"; - index = btr_pcur_get_btr_cur(pcur)->index; + if (prebuilt->new_rec_locks >= 1) { - if (index != NULL && trx_new_rec_locks_contain(trx, index)) { + rec_t* rec; + dict_index_t* index; + dulint rec_trx_id; + mtr_t mtr; mtr_start(&mtr); @@ -1490,45 +1490,71 @@ row_unlock_for_mysql( } rec = btr_pcur_get_rec(pcur); + index = btr_pcur_get_btr_cur(pcur)->index; - lock_rec_unlock(trx, btr_pcur_get_block(pcur), - rec, prebuilt->select_lock_type); + if (prebuilt->new_rec_locks >= 2) { + /* Restore the cursor position and find the record + in the clustered index. */ - mtr_commit(&mtr); + if (!has_latches_on_recs) { + btr_pcur_restore_position(BTR_SEARCH_LEAF, + clust_pcur, &mtr); + } - /* If the search was done through the clustered index, then - we have not used clust_pcur at all, and we must NOT try to - reset locks on clust_pcur. The values in clust_pcur may be - garbage! */ - - if (dict_index_is_clust(index)) { - - goto func_exit; - } - } - - index = btr_pcur_get_btr_cur(clust_pcur)->index; - - if (index != NULL && trx_new_rec_locks_contain(trx, index)) { - - mtr_start(&mtr); - - /* Restore the cursor position and find the record */ - - if (!has_latches_on_recs) { - btr_pcur_restore_position(BTR_SEARCH_LEAF, clust_pcur, - &mtr); + rec = btr_pcur_get_rec(clust_pcur); + index = btr_pcur_get_btr_cur(clust_pcur)->index; } - rec = btr_pcur_get_rec(clust_pcur); + if (UNIV_UNLIKELY(!(dict_index_is_clust(index)))) { + /* This is not a clustered index record. We + do not know how to unlock the record. */ + goto no_unlock; + } - lock_rec_unlock(trx, btr_pcur_get_block(clust_pcur), - rec, prebuilt->select_lock_type); + /* If the record has been modified by this + transaction, do not unlock it. */ + if (index->trx_id_offset) { + rec_trx_id = trx_read_trx_id(rec + + index->trx_id_offset); + } else { + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + + *offsets_ = (sizeof offsets_) / sizeof *offsets_; + offsets = rec_get_offsets(rec, index, offsets, + ULINT_UNDEFINED, &heap); + + rec_trx_id = row_get_rec_trx_id(rec, index, offsets); + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + } + + if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) { + /* We did not update the record: unlock it */ + + rec = btr_pcur_get_rec(pcur); + index = btr_pcur_get_btr_cur(pcur)->index; + + lock_rec_unlock(trx, btr_pcur_get_block(pcur), + rec, prebuilt->select_lock_type); + + if (prebuilt->new_rec_locks >= 2) { + rec = btr_pcur_get_rec(clust_pcur); + index = btr_pcur_get_btr_cur(clust_pcur)->index; + + lock_rec_unlock(trx, btr_pcur_get_block(clust_pcur), + rec, prebuilt->select_lock_type); + } + } + +no_unlock: mtr_commit(&mtr); } -func_exit: trx->op_info = ""; return(DB_SUCCESS); diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c index ebd7bf4a2ce..fb1523d3370 100644 --- a/storage/xtradb/row/row0sel.c +++ b/storage/xtradb/row/row0sel.c @@ -3002,8 +3002,9 @@ row_sel_get_clust_rec_for_mysql( func_exit: *out_rec = clust_rec; - if (prebuilt->select_lock_type == LOCK_X) { - /* We may use the cursor in update: store its position */ + if (prebuilt->select_lock_type != LOCK_NONE) { + /* We may use the cursor in update or in unlock_row(): + store its position */ btr_pcur_store_position(prebuilt->clust_pcur, mtr); } @@ -3405,13 +3406,7 @@ row_search_for_mysql( is set or session is using a READ COMMITED isolation level. Then we are able to remove the record locks set here on an individual row. */ - - if ((srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) - && prebuilt->select_lock_type != LOCK_NONE) { - - trx_reset_new_rec_lock_info(trx); - } + prebuilt->new_rec_locks = 0; /*-------------------------------------------------------------*/ /* PHASE 1: Try to pop the row from the prefetch cache */ @@ -4056,6 +4051,12 @@ no_gap_lock: switch (err) { const rec_t* old_vers; case DB_SUCCESS: + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { + /* Note that a record of + prebuilt->index was locked. */ + prebuilt->new_rec_locks = 1; + } break; case DB_LOCK_WAIT: if (UNIV_LIKELY(prebuilt->row_read_type @@ -4086,7 +4087,7 @@ no_gap_lock: if (UNIV_LIKELY(trx->wait_lock != NULL)) { lock_cancel_waiting_and_release( trx->wait_lock); - trx_reset_new_rec_lock_info(trx); + prebuilt->new_rec_locks = 0; } else { mutex_exit(&kernel_mutex); @@ -4098,6 +4099,9 @@ no_gap_lock: ULINT_UNDEFINED, &heap); err = DB_SUCCESS; + /* Note that a record of + prebuilt->index was locked. */ + prebuilt->new_rec_locks = 1; break; } mutex_exit(&kernel_mutex); @@ -4246,6 +4250,15 @@ requires_clust_rec: goto next_rec; } + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { + /* Note that both the secondary index record + and the clustered index record were locked. */ + ut_ad(prebuilt->new_rec_locks == 1); + prebuilt->new_rec_locks = 2; + } + if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) { /* The record is delete marked: we can skip it */ @@ -4375,13 +4388,7 @@ next_rec: prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; } did_semi_consistent_read = FALSE; - - if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) - && prebuilt->select_lock_type != LOCK_NONE) { - - trx_reset_new_rec_lock_info(trx); - } + prebuilt->new_rec_locks = 0; /*-------------------------------------------------------------*/ /* PHASE 5: Move the cursor to the next index record */ @@ -4487,7 +4494,7 @@ lock_wait_or_error: rec_loop we will again try to set a lock, and new_rec_lock_info in trx will be right at the end. */ - trx_reset_new_rec_lock_info(trx); + prebuilt->new_rec_locks = 0; } mode = pcur->search_mode; diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index 5afa5435b00..587f8319ad0 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -133,6 +133,8 @@ UNIV_INTERN ulint* srv_data_file_sizes = NULL; UNIV_INTERN ibool srv_extra_undoslots = FALSE; +UNIV_INTERN ibool srv_fast_recovery = FALSE; + /* if TRUE, then we auto-extend the last data file */ UNIV_INTERN ibool srv_auto_extend_last_data_file = FALSE; /* if != 0, this tells the max size auto-extending may increase the @@ -287,7 +289,6 @@ concurrency check. */ UNIV_INTERN ibool srv_thread_concurrency_timer_based = FALSE; UNIV_INTERN ulong srv_thread_concurrency = 0; -UNIV_INTERN ulong srv_commit_concurrency = 0; /* this mutex protects srv_conc data structures */ UNIV_INTERN os_fast_mutex_t srv_conc_mutex; diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c index 5fb234e3aa7..0f81bba0427 100644 --- a/storage/xtradb/trx/trx0trx.c +++ b/storage/xtradb/trx/trx0trx.c @@ -187,8 +187,6 @@ trx_create( trx->autoinc_locks = ib_vector_create( mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4); - trx_reset_new_rec_lock_info(trx); - return(trx); }