diff --git a/buf/buf0flu.c b/buf/buf0flu.c index 9acf4f50bf1..7da5fca26dc 100644 --- a/buf/buf0flu.c +++ b/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/buf/buf0rea.c b/buf/buf0rea.c index c5a7def8733..086ea035a7b 100644 --- a/buf/buf0rea.c +++ b/buf/buf0rea.c @@ -134,6 +134,46 @@ buf_read_page_low( bpage = buf_page_init_for_read(err, mode, space, zip_size, unzip, tablespace_version, offset); if (bpage == NULL) { + /* bugfix: http://bugs.mysql.com/bug.php?id=43948 */ + if (recv_recovery_is_on() && *err == DB_TABLESPACE_DELETED) { + /* hashed log recs must be treated here */ + recv_addr_t* recv_addr; + + mutex_enter(&(recv_sys->mutex)); + + if (recv_sys->apply_log_recs == FALSE) { + mutex_exit(&(recv_sys->mutex)); + goto not_to_recover; + } + + /* recv_get_fil_addr_struct() */ + recv_addr = HASH_GET_FIRST(recv_sys->addr_hash, + hash_calc_hash(ut_fold_ulint_pair(space, offset), + recv_sys->addr_hash)); + while (recv_addr) { + if ((recv_addr->space == space) + && (recv_addr->page_no == offset)) { + break; + } + recv_addr = HASH_GET_NEXT(addr_hash, recv_addr); + } + + if ((recv_addr == NULL) + || (recv_addr->state == RECV_BEING_PROCESSED) + || (recv_addr->state == RECV_PROCESSED)) { + mutex_exit(&(recv_sys->mutex)); + goto not_to_recover; + } + + fprintf(stderr, " (cannot find space: %lu)", space); + recv_addr->state = RECV_PROCESSED; + + ut_a(recv_sys->n_addrs); + recv_sys->n_addrs--; + + mutex_exit(&(recv_sys->mutex)); + } +not_to_recover: return(0); } @@ -784,11 +824,11 @@ buf_read_recv_pages( while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) { os_aio_simulated_wake_handler_threads(); - os_thread_sleep(500000); + os_thread_sleep(10000); count++; - if (count > 100) { + if (count > 5000) { fprintf(stderr, "InnoDB: Error: InnoDB has waited for" " 50 seconds for pending\n" diff --git a/dict/dict0dict.c b/dict/dict0dict.c index 61c20d4bbb9..68fa5fccf64 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -3049,7 +3049,7 @@ scan_more: } else if (quote) { /* Within quotes: do not look for starting quotes or comments. */ - } else if (*sptr == '"' || *sptr == '`') { + } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') { /* Starting quote: remember the quote character. */ quote = *sptr; } else if (*sptr == '#' diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index 8f925c4bcb4..24d29862fd8 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -194,6 +194,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; @@ -2220,9 +2221,12 @@ mem_free_and_error: srv_n_write_io_threads = (ulint) innobase_write_io_threads; srv_read_ahead &= 3; + srv_adaptive_checkpoint %= 3; 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; @@ -9318,7 +9322,8 @@ ha_innobase::check_if_incompatible_data( /* Check that row format didn't change */ if ((info->used_fields & HA_CREATE_USED_ROW_FORMAT) && - get_row_type() != info->row_type) { + get_row_type() != ((info->row_type == ROW_TYPE_DEFAULT) + ? ROW_TYPE_COMPACT : info->row_type)) { return(COMPATIBLE_DATA_NO); } @@ -9709,6 +9714,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 " @@ -10030,10 +10040,36 @@ static MYSQL_SYSVAR_ENUM(read_ahead, srv_read_ahead, "Control read ahead activity. (none, random, linear, [both])", NULL, innodb_read_ahead_update, 3, &read_ahead_typelib); -static MYSQL_SYSVAR_ULONG(adaptive_checkpoint, srv_adaptive_checkpoint, +static +void +innodb_adaptive_checkpoint_update( + THD* thd, + struct st_mysql_sys_var* var, + void* var_ptr, + const void* save) +{ + *(long *)var_ptr= (*(long *)save) % 3; +} +const char *adaptive_checkpoint_names[]= +{ + "none", /* 0 */ + "reflex", /* 1 */ + "estimate", /* 2 */ + /* For compatibility of the older patch */ + "0", /* 3 ("none" + 3) */ + "1", /* 4 ("reflex" + 3) */ + "2", /* 5 ("estimate" + 3) */ + NullS +}; +TYPELIB adaptive_checkpoint_typelib= +{ + array_elements(adaptive_checkpoint_names) - 1, "adaptive_checkpoint_typelib", + adaptive_checkpoint_names, NULL +}; +static MYSQL_SYSVAR_ENUM(adaptive_checkpoint, srv_adaptive_checkpoint, PLUGIN_VAR_RQCMDARG, - "Enable/Disable flushing along modified age. 0:disable 1:enable", - NULL, NULL, 0, 0, 1, 0); + "Enable/Disable flushing along modified age. ([none], reflex, estimate)", + NULL, innodb_adaptive_checkpoint_update, 0, &adaptive_checkpoint_typelib); static MYSQL_SYSVAR_ULONG(enable_unsafe_group_commit, srv_enable_unsafe_group_commit, PLUGIN_VAR_RQCMDARG, @@ -10076,6 +10112,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), diff --git a/handler/innodb_patch_info.h b/handler/innodb_patch_info.h index 5bc79c9960d..770e74f39d1 100644 --- a/handler/innodb_patch_info.h +++ b/handler/innodb_patch_info.h @@ -37,5 +37,6 @@ struct innodb_enhancement { {"innodb_dict_size_limit","Limit dictionary cache size","Variable innodb_dict_size_limit in bytes","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_split_buf_pool_mutex","More fix of buffer_pool mutex","Spliting buf_pool_mutex and optimizing based on innodb_opt_lru_count","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_stats","Additional features about InnoDB statistics/optimizer","","http://www.percona.com/docs/wiki/percona-xtradb"}, +{"innodb_recovery_patches","Bugfixes and adjustments about recovery process","","http://www.percona.com/docs/wiki/percona-xtradb"}, {NULL, NULL, NULL, NULL} }; diff --git a/include/row0mysql.h b/include/row0mysql.h index c1e11124a5d..8e42c316209 100644 --- a/include/row0mysql.h +++ b/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/include/srv0srv.h b/include/srv0srv.h index c16c8e33057..c7ba91f4a39 100644 --- a/include/srv0srv.h +++ b/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; diff --git a/include/trx0trx.h b/include/trx0trx.h index e7f7539f9ee..1bec1ff73be 100644 --- a/include/trx0trx.h +++ b/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/include/trx0trx.ic b/include/trx0trx.ic index 6da89f002fe..51212539c09 100644 --- a/include/trx0trx.ic +++ b/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/include/univ.i b/include/univ.i index 27e82a5e07b..2a7efd6d762 100644 --- a/include/univ.i +++ b/include/univ.i @@ -35,7 +35,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 #define INNODB_VERSION_BUGFIX 3 -#define PERCONA_INNODB_VERSION 5a +#define PERCONA_INNODB_VERSION 6a /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; diff --git a/lock/lock0lock.c b/lock/lock0lock.c index 3730c66313d..9e90e099428 100644 --- a/lock/lock0lock.c +++ b/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/log/log0recv.c b/log/log0recv.c index b72dde4efcf..f0f5ae8d6cc 100644 --- a/log/log0recv.c +++ b/log/log0recv.c @@ -110,7 +110,7 @@ the log and store the scanned log records in the buffer pool: we will use these free frames to read in pages when we start applying the log records to the database. */ -UNIV_INTERN ulint recv_n_pool_free_frames = 256; +UNIV_INTERN ulint recv_n_pool_free_frames = 1024; /* The maximum lsn we see for a page during the recovery process. If this is bigger than the lsn we are able to scan up to, that is an indication that @@ -1225,6 +1225,8 @@ recv_recover_page( buf_block_get_page_no(block)); if ((recv_addr == NULL) + /* bugfix: http://bugs.mysql.com/bug.php?id=44140 */ + || (recv_addr->state == RECV_BEING_READ && !just_read_in) || (recv_addr->state == RECV_BEING_PROCESSED) || (recv_addr->state == RECV_PROCESSED)) { diff --git a/mysql-test/innodb-analyze.test b/mysql-test/innodb-analyze.test index d5d6d698170..de5a486a355 100644 --- a/mysql-test/innodb-analyze.test +++ b/mysql-test/innodb-analyze.test @@ -11,6 +11,7 @@ -- disable_result_log -- enable_warnings +SET @old_innodb_stats_sample_pages=@@innodb_stats_sample_pages; SET GLOBAL innodb_stats_sample_pages=0; # check that the value has been adjusted to 1 @@ -61,3 +62,4 @@ SET GLOBAL innodb_stats_sample_pages=16; ANALYZE TABLE innodb_analyze; DROP TABLE innodb_analyze; +SET GLOBAL innodb_stats_sample_pages=@old_innodb_stats_sample_pages; diff --git a/mysql-test/innodb_xtradb_bug317074.result b/mysql-test/innodb_xtradb_bug317074.result index aa80e4d7aa4..52c758a5eed 100644 --- a/mysql-test/innodb_xtradb_bug317074.result +++ b/mysql-test/innodb_xtradb_bug317074.result @@ -1,2 +1,5 @@ +SET @old_innodb_file_format=@@innodb_file_format; +SET @old_innodb_file_per_table=@@innodb_file_per_table; +SET @old_innodb_file_format_check=@@innodb_file_format_check; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=ON; diff --git a/mysql-test/innodb_xtradb_bug317074.test b/mysql-test/innodb_xtradb_bug317074.test index d5abb7a1670..a15d64d6bb5 100644 --- a/mysql-test/innodb_xtradb_bug317074.test +++ b/mysql-test/innodb_xtradb_bug317074.test @@ -1,5 +1,8 @@ -- source include/have_innodb.inc +SET @old_innodb_file_format=@@innodb_file_format; +SET @old_innodb_file_per_table=@@innodb_file_per_table; +SET @old_innodb_file_format_check=@@innodb_file_format_check; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=ON; @@ -36,3 +39,6 @@ DROP PROCEDURE insert_many; ALTER TABLE test1 ENGINE=MyISAM; DROP TABLE test1; +SET GLOBAL innodb_file_format=@old_innodb_file_format; +SET GLOBAL innodb_file_per_table=@old_innodb_file_per_table; +SET GLOBAL innodb_file_format_check=@old_innodb_file_format_check; diff --git a/mysql-test/patches/events_stress.diff b/mysql-test/patches/events_stress.diff index f1c36d44a1e..afbd3b51c1d 100644 --- a/mysql-test/patches/events_stress.diff +++ b/mysql-test/patches/events_stress.diff @@ -1,5 +1,5 @@ ---- mysql-test/t/events_stress.test.orig 2009-04-16 19:39:47.000000000 +0000 -+++ mysql-test/t/events_stress.test 2009-04-16 19:41:16.000000000 +0000 +--- 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 @@ -8,13 +8,15 @@ SET GLOBAL event_scheduler=on; --sleep 2.5 DROP DATABASE events_conn1_test2; -@@ -135,3 +136,4 @@ - # - +@@ -137,5 +138,5 @@ DROP DATABASE events_test; + + # Cleanup +-SET GLOBAL event_scheduler=off; +SET GLOBAL event_scheduler=@old_event_scheduler; ---- mysql-test/r/events_stress.result.orig 2009-04-16 19:41:48.000000000 +0000 -+++ mysql-test/r/events_stress.result 2009-04-16 19:42:07.000000000 +0000 + --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(*) @@ -23,8 +25,9 @@ SET GLOBAL event_scheduler=on; DROP DATABASE events_conn1_test2; SET GLOBAL event_scheduler=off; -@@ -63,3 +64,4 @@ +@@ -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 index c09633f82b7..4d67ed3f82d 100644 --- a/mysql-test/patches/information_schema.diff +++ b/mysql-test/patches/information_schema.diff @@ -1,6 +1,6 @@ ---- mysql-test/r/information_schema.result.orig 2009-04-16 19:59:13.000000000 +0000 -+++ mysql-test/r/information_schema.result 2009-04-16 20:00:16.000000000 +0000 -@@ -71,6 +71,18 @@ +--- 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 @@ -10,16 +10,18 @@ +INNODB_BUFFER_POOL_PAGES +XTRADB_ENHANCEMENTS +INNODB_TRX -+INNODB_BUFFER_POOL_PAGES_BLOB ++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 +811,8 @@ +@@ -799,6 +813,8 @@ TABLES UPDATE_TIME datetime TABLES CHECK_TIME datetime TRIGGERS CREATED datetime @@ -28,22 +30,24 @@ event execute_at datetime event last_executed datetime event starts datetime -@@ -847,12 +861,13 @@ +@@ -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 40 ++information_schema 42 mysql 22 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row -@@ -1267,6 +1282,18 @@ +@@ -1267,6 +1286,20 @@ TRIGGERS TRIGGER_SCHEMA USER_PRIVILEGES GRANTEE VIEWS TABLE_SCHEMA @@ -53,16 +57,18 @@ +INNODB_BUFFER_POOL_PAGES page_type +XTRADB_ENHANCEMENTS name +INNODB_TRX trx_id -+INNODB_BUFFER_POOL_PAGES_BLOB space_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 +1337,26 @@ +@@ -1310,14 +1343,28 @@ TRIGGERS TRIGGER_SCHEMA USER_PRIVILEGES GRANTEE VIEWS TABLE_SCHEMA @@ -72,12 +78,14 @@ +INNODB_BUFFER_POOL_PAGES page_type +XTRADB_ENHANCEMENTS name +INNODB_TRX trx_id -+INNODB_BUFFER_POOL_PAGES_BLOB space_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 @@ -91,7 +99,7 @@ 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 +1425,17 @@ +@@ -1386,6 +1433,19 @@ FILES information_schema.FILES 1 GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 @@ -102,14 +110,16 @@ +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 +1454,7 @@ +@@ -1404,6 +1464,7 @@ TRIGGERS information_schema.TRIGGERS 1 USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 VIEWS information_schema.VIEWS 1 diff --git a/mysql-test/patches/information_schema_db.diff b/mysql-test/patches/information_schema_db.diff index a645fcf4a08..de7f52e8275 100644 --- a/mysql-test/patches/information_schema_db.diff +++ b/mysql-test/patches/information_schema_db.diff @@ -1,6 +1,6 @@ ---- mysql-test/r/information_schema_db.result.orig 2009-04-16 20:05:49.000000000 +0000 -+++ mysql-test/r/information_schema_db.result 2009-04-16 20:06:07.000000000 +0000 -@@ -33,6 +33,18 @@ +--- 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 @@ -10,12 +10,14 @@ +INNODB_BUFFER_POOL_PAGES +XTRADB_ENHANCEMENTS +INNODB_TRX -+INNODB_BUFFER_POOL_PAGES_BLOB ++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 index 7af21075624..7c02b9d8bf7 100644 --- a/mysql-test/patches/mysqlshow.diff +++ b/mysql-test/patches/mysqlshow.diff @@ -1,6 +1,6 @@ ---- mysql-test/r/mysqlshow.result.orig 2009-04-16 20:13:30.000000000 +0000 -+++ mysql-test/r/mysqlshow.result 2009-04-16 20:13:45.000000000 +0000 -@@ -107,6 +107,18 @@ +--- 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 | @@ -10,16 +10,18 @@ +| INNODB_BUFFER_POOL_PAGES | +| XTRADB_ENHANCEMENTS | +| INNODB_TRX | -+| INNODB_BUFFER_POOL_PAGES_BLOB | ++| 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 +152,18 @@ +@@ -140,6 +154,20 @@ | TRIGGERS | | USER_PRIVILEGES | | VIEWS | @@ -29,12 +31,14 @@ +| INNODB_BUFFER_POOL_PAGES | +| XTRADB_ENHANCEMENTS | +| INNODB_TRX | -+| INNODB_BUFFER_POOL_PAGES_BLOB | ++| 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/row/row0mysql.c b/row/row0mysql.c index 7acc330113b..3a9e1de0125 100644 --- a/row/row0mysql.c +++ b/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/row/row0sel.c b/row/row0sel.c index ebd7bf4a2ce..fb1523d3370 100644 --- a/row/row0sel.c +++ b/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/srv/srv0srv.c b/srv/srv0srv.c index 09b4dee88aa..0897de61e16 100644 --- a/srv/srv0srv.c +++ b/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 @@ -364,7 +366,7 @@ UNIV_INTERN ulint srv_flush_neighbor_pages = 1; /* 0:disable 1:enable */ UNIV_INTERN ulint srv_enable_unsafe_group_commit = 0; /* 0:disable 1:enable */ UNIV_INTERN ulint srv_read_ahead = 3; /* 1: random 2: linear 3: Both */ -UNIV_INTERN ulint srv_adaptive_checkpoint = 0; /* 0:disable 1:enable */ +UNIV_INTERN ulint srv_adaptive_checkpoint = 0; /* 0: none 1: reflex 2: estimate */ UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */ @@ -2509,6 +2511,9 @@ srv_master_thread( mutex_exit(&kernel_mutex); + mutex_enter(&(log_sys->mutex)); + lsn_old = log_sys->lsn; + mutex_exit(&(log_sys->mutex)); loop: /*****************************************************************/ /* ---- When there is database activity by users, we cycle in this @@ -2538,14 +2543,24 @@ loop: for (i = 0; i < 10; i++) { n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; - mutex_enter(&(log_sys->mutex)); - lsn_old = log_sys->lsn; - mutex_exit(&(log_sys->mutex)); srv_main_thread_op_info = "sleeping"; if (!skip_sleep) { os_thread_sleep(1000000); + + /* + mutex_enter(&(log_sys->mutex)); + oldest_lsn = buf_pool_get_oldest_modification(); + ib_uint64_t lsn = log_sys->lsn; + mutex_exit(&(log_sys->mutex)); + + if(oldest_lsn) + fprintf(stderr, + "InnoDB flush: age pct: %lu, lsn progress: %lu\n", + (lsn - oldest_lsn) * 100 / log_sys->max_checkpoint_age, + lsn - lsn_old); + */ } skip_sleep = FALSE; @@ -2610,13 +2625,16 @@ loop: iteration of this loop. */ skip_sleep = TRUE; - } else if (srv_adaptive_checkpoint) { + mutex_enter(&(log_sys->mutex)); + lsn_old = log_sys->lsn; + mutex_exit(&(log_sys->mutex)); + } else if (srv_adaptive_checkpoint == 1) { /* Try to keep modified age not to exceed max_checkpoint_age * 7/8 line */ mutex_enter(&(log_sys->mutex)); - + lsn_old = log_sys->lsn; oldest_lsn = buf_pool_get_oldest_modification(); if (oldest_lsn == 0) { @@ -2628,6 +2646,49 @@ loop: /* LOG_POOL_PREFLUSH_RATIO_ASYNC is exceeded. */ /* We should not flush from here. */ mutex_exit(&(log_sys->mutex)); + } else if ((log_sys->lsn - oldest_lsn) + > (log_sys->max_checkpoint_age) - ((log_sys->max_checkpoint_age) / 4)) { + + /* 2nd defence line (max_checkpoint_age * 3/4) */ + + mutex_exit(&(log_sys->mutex)); + + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100), + IB_ULONGLONG_MAX); + skip_sleep = TRUE; + } else if ((log_sys->lsn - oldest_lsn) + > (log_sys->max_checkpoint_age)/2 ) { + + /* 1st defence line (max_checkpoint_age * 1/2) */ + + mutex_exit(&(log_sys->mutex)); + + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(10), + IB_ULONGLONG_MAX); + skip_sleep = TRUE; + } else { + mutex_exit(&(log_sys->mutex)); + } + } + } else if (srv_adaptive_checkpoint == 2) { + + /* Try to keep modified age not to exceed + max_checkpoint_age * 7/8 line */ + + mutex_enter(&(log_sys->mutex)); + + oldest_lsn = buf_pool_get_oldest_modification(); + if (oldest_lsn == 0) { + lsn_old = log_sys->lsn; + mutex_exit(&(log_sys->mutex)); + + } else { + if ((log_sys->lsn - oldest_lsn) + > (log_sys->max_checkpoint_age) - ((log_sys->max_checkpoint_age) / 8)) { + /* LOG_POOL_PREFLUSH_RATIO_ASYNC is exceeded. */ + /* We should not flush from here. */ + lsn_old = log_sys->lsn; + mutex_exit(&(log_sys->mutex)); } else if ((log_sys->lsn - oldest_lsn) > (log_sys->max_checkpoint_age)/2 ) { @@ -2663,11 +2724,23 @@ loop: mutex_exit(&flush_list_mutex); - if(bpl) + if (!srv_use_doublewrite_buf) { + /* flush is faster than when doublewrite */ + bpl = (bpl * 3) / 4; + } + + if (bpl) { +retry_flush_batch: n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, bpl, oldest_lsn + (lsn - lsn_old)); + if (n_pages_flushed == ULINT_UNDEFINED) { + os_thread_sleep(5000); + goto retry_flush_batch; + } + } + lsn_old = lsn; /* fprintf(stderr, "InnoDB flush: age pct: %lu, lsn progress: %lu, blocks to flush:%llu\n", @@ -2675,10 +2748,15 @@ loop: lsn - lsn_old, bpl); */ } else { + lsn_old = log_sys->lsn; mutex_exit(&(log_sys->mutex)); } } + } else { + mutex_enter(&(log_sys->mutex)); + lsn_old = log_sys->lsn; + mutex_exit(&(log_sys->mutex)); } if (srv_activity_count == old_activity_count) { diff --git a/trx/trx0trx.c b/trx/trx0trx.c index 5fb234e3aa7..0f81bba0427 100644 --- a/trx/trx0trx.c +++ b/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); }