diff options
author | Sergei Golubchik <serg@mariadb.org> | 2014-12-02 22:25:16 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2014-12-02 22:25:16 +0100 |
commit | 853077ad7e81be1ade20b4beab1b95d5766d87b1 (patch) | |
tree | 4c158691947ba7beb4577f26b160f243eabf39ef /storage/innobase | |
parent | bf3b4a23f75de50e0f1ab4a562e5801dabc7305b (diff) | |
parent | 2b5db1d5bcd7b46b654d59a07fc119ef6a6b8651 (diff) | |
download | mariadb-git-853077ad7e81be1ade20b4beab1b95d5766d87b1.tar.gz |
Merge branch '10.0' into bb-10.1-merge
Conflicts:
.bzrignore
VERSION
cmake/plugin.cmake
debian/dist/Debian/control
debian/dist/Ubuntu/control
mysql-test/r/join_outer.result
mysql-test/r/join_outer_jcl6.result
mysql-test/r/null.result
mysql-test/r/old-mode.result
mysql-test/r/union.result
mysql-test/t/join_outer.test
mysql-test/t/null.test
mysql-test/t/old-mode.test
mysql-test/t/union.test
packaging/rpm-oel/mysql.spec.in
scripts/mysql_config.sh
sql/ha_ndbcluster.cc
sql/ha_ndbcluster_binlog.cc
sql/ha_ndbcluster_cond.cc
sql/item_cmpfunc.h
sql/lock.cc
sql/sql_select.cc
sql/sql_show.cc
sql/sql_update.cc
sql/sql_yacc.yy
storage/innobase/buf/buf0flu.cc
storage/innobase/fil/fil0fil.cc
storage/innobase/include/srv0srv.h
storage/innobase/lock/lock0lock.cc
storage/tokudb/CMakeLists.txt
storage/xtradb/buf/buf0flu.cc
storage/xtradb/fil/fil0fil.cc
storage/xtradb/include/srv0srv.h
storage/xtradb/lock/lock0lock.cc
support-files/mysql.spec.sh
Diffstat (limited to 'storage/innobase')
61 files changed, 1420 insertions, 511 deletions
diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc index a060cbc7270..3859fb84b81 100644 --- a/storage/innobase/api/api0api.cc +++ b/storage/innobase/api/api0api.cc @@ -205,9 +205,9 @@ struct ib_tuple_t { }; /** The following counter is used to convey information to InnoDB -about server activity: in selects it is not sensible to call -srv_active_wake_master_thread after each fetch or search, we only do -it every INNOBASE_WAKE_INTERVAL'th step. */ +about server activity: in case of normal DML ops it is not +sensible to call srv_active_wake_master_thread after each +operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */ #define INNOBASE_WAKE_INTERVAL 32 @@ -427,7 +427,7 @@ ib_read_tuple( data = btr_rec_copy_externally_stored_field( copy, offsets, zip_size, i, &len, - tuple->heap); + tuple->heap, NULL); ut_a(len != UNIV_SQL_NULL); } @@ -707,8 +707,6 @@ ib_trx_rollback( /* It should always succeed */ ut_a(err == DB_SUCCESS); - ib_wake_master_thread(); - return(err); } @@ -1531,7 +1529,11 @@ ib_execute_insert_query_graph( dict_table_n_rows_inc(table); - srv_stats.n_rows_inserted.inc(); + if (table->is_system_db) { + srv_stats.n_system_rows_inserted.inc(); + } else { + srv_stats.n_rows_inserted.inc(); + } } trx->op_info = ""; @@ -1654,7 +1656,7 @@ ib_cursor_insert_row( src_tuple->index->table, q_proc->grph.ins, node->ins); } - srv_active_wake_master_thread(); + ib_wake_master_thread(); return(err); } @@ -1885,9 +1887,17 @@ ib_execute_update_query_graph( dict_table_n_rows_dec(table); - srv_stats.n_rows_deleted.inc(); + if (table->is_system_db) { + srv_stats.n_system_rows_deleted.inc(); + } else { + srv_stats.n_rows_deleted.inc(); + } } else { - srv_stats.n_rows_updated.inc(); + if (table->is_system_db) { + srv_stats.n_system_rows_updated.inc(); + } else { + srv_stats.n_rows_updated.inc(); + } } } else if (err == DB_RECORD_NOT_FOUND) { @@ -1940,7 +1950,7 @@ ib_cursor_update_row( err = ib_execute_update_query_graph(cursor, pcur); } - srv_active_wake_master_thread(); + ib_wake_master_thread(); return(err); } @@ -2082,7 +2092,7 @@ ib_cursor_delete_row( err = DB_RECORD_NOT_FOUND; } - srv_active_wake_master_thread(); + ib_wake_master_thread(); return(err); } diff --git a/storage/innobase/api/api0misc.cc b/storage/innobase/api/api0misc.cc index b2370105938..a980d32c33f 100644 --- a/storage/innobase/api/api0misc.cc +++ b/storage/innobase/api/api0misc.cc @@ -24,6 +24,7 @@ InnoDB Native API 3/20/2011 Jimmy Yang extracted from Embedded InnoDB *******************************************************/ +#include <my_config.h> #include <errno.h> #ifdef HAVE_UNISTD_H diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 4f9ccbe061a..ff27b470974 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -2826,6 +2826,134 @@ btr_page_tuple_smaller( return(cmp_dtuple_rec(tuple, first_rec, *offsets) < 0); } +/** Insert the tuple into the right sibling page, if the cursor is at the end +of a page. +@param[in] flags undo logging and locking flags +@param[in,out] cursor cursor at which to insert; when the function succeeds, + the cursor is positioned before the insert point. +@param[out] offsets offsets on inserted record +@param[in,out] heap memory heap for allocating offsets +@param[in] tuple tuple to insert +@param[in] n_ext number of externally stored columns +@param[in,out] mtr mini-transaction +@return inserted record (first record on the right sibling page); + the cursor will be positioned on the page infimum +@retval NULL if the operation was not performed */ +static +rec_t* +btr_insert_into_right_sibling( + ulint flags, + btr_cur_t* cursor, + ulint** offsets, + mem_heap_t* heap, + const dtuple_t* tuple, + ulint n_ext, + mtr_t* mtr) +{ + buf_block_t* block = btr_cur_get_block(cursor); + page_t* page = buf_block_get_frame(block); + ulint next_page_no = btr_page_get_next(page, mtr); + + ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad(heap); + + if (next_page_no == FIL_NULL || !page_rec_is_supremum( + page_rec_get_next(btr_cur_get_rec(cursor)))) { + + return(NULL); + } + + page_cur_t next_page_cursor; + buf_block_t* next_block; + page_t* next_page; + btr_cur_t next_father_cursor; + rec_t* rec = NULL; + ulint zip_size = buf_block_get_zip_size(block); + ulint max_size; + + next_block = btr_block_get( + buf_block_get_space(block), zip_size, + next_page_no, RW_X_LATCH, cursor->index, mtr); + next_page = buf_block_get_frame(next_block); + + bool is_leaf = page_is_leaf(next_page); + + btr_page_get_father( + cursor->index, next_block, mtr, &next_father_cursor); + + page_cur_search( + next_block, cursor->index, tuple, PAGE_CUR_LE, + &next_page_cursor); + + max_size = page_get_max_insert_size_after_reorganize(next_page, 1); + + /* Extends gap lock for the next page */ + lock_update_split_left(next_block, block); + + rec = page_cur_tuple_insert( + &next_page_cursor, tuple, cursor->index, offsets, &heap, + n_ext, mtr); + + if (rec == NULL) { + if (zip_size && is_leaf + && !dict_index_is_clust(cursor->index)) { + /* Reset the IBUF_BITMAP_FREE bits, because + page_cur_tuple_insert() will have attempted page + reorganize before failing. */ + ibuf_reset_free_bits(next_block); + } + return(NULL); + } + + ibool compressed; + dberr_t err; + ulint level = btr_page_get_level(next_page, mtr); + + /* adjust cursor position */ + *btr_cur_get_page_cur(cursor) = next_page_cursor; + + ut_ad(btr_cur_get_rec(cursor) == page_get_infimum_rec(next_page)); + ut_ad(page_rec_get_next(page_get_infimum_rec(next_page)) == rec); + + /* We have to change the parent node pointer */ + + compressed = btr_cur_pessimistic_delete( + &err, TRUE, &next_father_cursor, + BTR_CREATE_FLAG, RB_NONE, mtr); + + ut_a(err == DB_SUCCESS); + + if (!compressed) { + btr_cur_compress_if_useful(&next_father_cursor, FALSE, mtr); + } + + dtuple_t* node_ptr = dict_index_build_node_ptr( + cursor->index, rec, buf_block_get_page_no(next_block), + heap, level); + + btr_insert_on_non_leaf_level( + flags, cursor->index, level + 1, node_ptr, mtr); + + ut_ad(rec_offs_validate(rec, cursor->index, *offsets)); + + if (is_leaf && !dict_index_is_clust(cursor->index)) { + /* Update the free bits of the B-tree page in the + insert buffer bitmap. */ + + if (zip_size) { + ibuf_update_free_bits_zip(next_block, mtr); + } else { + ibuf_update_free_bits_if_full( + next_block, max_size, + rec_offs_size(*offsets) + PAGE_DIR_SLOT_SIZE); + } + } + + return(rec); +} + /*************************************************************//** Splits an index page to halves and inserts the tuple. It is assumed that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is @@ -2896,6 +3024,14 @@ func_start: ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); ut_ad(!page_is_empty(page)); + /* try to insert to the next page if possible before split */ + rec = btr_insert_into_right_sibling( + flags, cursor, offsets, *heap, tuple, n_ext, mtr); + + if (rec != NULL) { + return(rec); + } + page_no = buf_block_get_page_no(block); /* 1. Decide the split record; split_rec == NULL means that the diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 9b24244f35e..b030fd7da79 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1247,7 +1247,7 @@ btr_cur_optimistic_insert( rec_t* dummy; ibool leaf; ibool reorg; - ibool inherit; + ibool inherit = TRUE; ulint zip_size; ulint rec_size; dberr_t err; @@ -1525,7 +1525,7 @@ btr_cur_pessimistic_insert( ulint zip_size = dict_table_zip_size(index->table); big_rec_t* big_rec_vec = NULL; dberr_t err; - ibool dummy_inh; + ibool inherit = FALSE; ibool success; ulint n_reserved = 0; @@ -1547,7 +1547,7 @@ btr_cur_pessimistic_insert( /* Check locks and write to undo log, if specified */ err = btr_cur_ins_lock_and_undo(flags, cursor, entry, - thr, mtr, &dummy_inh); + thr, mtr, &inherit); if (err != DB_SUCCESS) { @@ -1607,10 +1607,31 @@ btr_cur_pessimistic_insert( ut_ad(page_rec_get_next(btr_cur_get_rec(cursor)) == *rec); + if (!(flags & BTR_NO_LOCKING_FLAG)) { + /* The cursor might be moved to the other page, + and the max trx id field should be updated after + the cursor was fixed. */ + if (!dict_index_is_clust(index)) { + page_update_max_trx_id( + btr_cur_get_block(cursor), + btr_cur_get_page_zip(cursor), + thr_get_trx(thr)->id, mtr); + } + if (!page_rec_is_infimum(btr_cur_get_rec(cursor)) + || btr_page_get_prev( + buf_block_get_frame( + btr_cur_get_block(cursor)), mtr) + == FIL_NULL) { + /* split and inserted need to call + lock_update_insert() always. */ + inherit = TRUE; + } + } + #ifdef BTR_CUR_ADAPT btr_search_update_hash_on_insert(cursor); #endif - if (!(flags & BTR_NO_LOCKING_FLAG)) { + if (inherit && !(flags & BTR_NO_LOCKING_FLAG)) { lock_update_insert(btr_cur_get_block(cursor), *rec); } @@ -3614,7 +3635,8 @@ btr_estimate_n_rows_in_range( const dtuple_t* tuple1, /*!< in: range start, may also be empty tuple */ ulint mode1, /*!< in: search mode for range start */ const dtuple_t* tuple2, /*!< in: range end, may also be empty tuple */ - ulint mode2) /*!< in: search mode for range end */ + ulint mode2, /*!< in: search mode for range end */ + trx_t* trx) /*!< in: trx */ { btr_path_t path1[BTR_PATH_ARRAY_N_SLOTS]; btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS]; @@ -3632,7 +3654,7 @@ btr_estimate_n_rows_in_range( table_n_rows = dict_table_get_n_rows(index->table); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); cursor.path_arr = path1; @@ -3650,7 +3672,7 @@ btr_estimate_n_rows_in_range( mtr_commit(&mtr); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); cursor.path_arr = path2; @@ -3826,7 +3848,7 @@ btr_estimate_number_of_different_key_vals( ib_uint64_t* n_diff; ib_uint64_t* n_not_null; ibool stats_null_not_equal; - ullint n_sample_pages; /* number of pages to sample */ + ullint n_sample_pages = 1; /* number of pages to sample */ ulint not_empty_flag = 0; ulint total_external_size = 0; ulint i; @@ -3873,18 +3895,63 @@ btr_estimate_number_of_different_key_vals( ut_error; } - /* It makes no sense to test more pages than are contained - in the index, thus we lower the number if it is too high */ - if (srv_stats_transient_sample_pages > index->stat_index_size) { - if (index->stat_index_size > 0) { - n_sample_pages = index->stat_index_size; + if (srv_stats_sample_traditional) { + /* It makes no sense to test more pages than are contained + in the index, thus we lower the number if it is too high */ + if (srv_stats_transient_sample_pages > index->stat_index_size) { + if (index->stat_index_size > 0) { + n_sample_pages = index->stat_index_size; + } } else { - n_sample_pages = 1; + n_sample_pages = srv_stats_transient_sample_pages; } } else { - n_sample_pages = srv_stats_transient_sample_pages; + /* New logaritmic number of pages that are estimated. + Number of pages estimated should be between 1 and + index->stat_index_size. + + If we have only 0 or 1 index pages then we can only take 1 + sample. We have already initialized n_sample_pages to 1. + + So taking index size as I and sample as S and log(I)*S as L + + requirement 1) we want the out limit of the expression to not exceed I; + requirement 2) we want the ideal pages to be at least S; + so the current expression is min(I, max( min(S,I), L) + + looking for simplifications: + + case 1: assume S < I + min(I, max( min(S,I), L) -> min(I , max( S, L)) + + but since L=LOG2(I)*S and log2(I) >=1 L>S always so max(S,L) = L. + + so we have: min(I , L) + + case 2: assume I < S + min(I, max( min(S,I), L) -> min(I, max( I, L)) + + case 2a: L > I + min(I, max( I, L)) -> min(I, L) -> I + + case 2b: when L < I + min(I, max( I, L)) -> min(I, I ) -> I + + so taking all case2 paths is I, our expression is: + n_pages = S < I? min(I,L) : I + */ + if (index->stat_index_size > 1) { + n_sample_pages = (srv_stats_transient_sample_pages < index->stat_index_size) ? + ut_min(index->stat_index_size, + log2(index->stat_index_size)*srv_stats_transient_sample_pages) + : index->stat_index_size; + + } } + /* Sanity check */ + ut_ad(n_sample_pages > 0 && n_sample_pages <= (index->stat_index_size <= 1 ? 1 : index->stat_index_size)); + /* We sample some pages in the index to get an estimate */ for (i = 0; i < n_sample_pages; i++) { @@ -5232,7 +5299,8 @@ btr_copy_blob_prefix( ulint len, /*!< in: length of buf, in bytes */ ulint space_id,/*!< in: space id of the BLOB pages */ ulint page_no,/*!< in: page number of the first BLOB page */ - ulint offset) /*!< in: offset on the first BLOB page */ + ulint offset, /*!< in: offset on the first BLOB page */ + trx_t* trx) /*!< in: transaction handle */ { ulint copied_len = 0; @@ -5244,7 +5312,7 @@ btr_copy_blob_prefix( ulint part_len; ulint copy_len; - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); block = buf_page_get(space_id, 0, page_no, RW_S_LATCH, &mtr); buf_block_dbg_add_level(block, SYNC_EXTERN_STORAGE); @@ -5447,7 +5515,8 @@ btr_copy_externally_stored_field_prefix_low( zero for uncompressed BLOBs */ ulint space_id,/*!< in: space id of the first BLOB page */ ulint page_no,/*!< in: page number of the first BLOB page */ - ulint offset) /*!< in: offset on the first BLOB page */ + ulint offset, /*!< in: offset on the first BLOB page */ + trx_t* trx) /*!< in: transaction handle */ { if (UNIV_UNLIKELY(len == 0)) { return(0); @@ -5458,7 +5527,7 @@ btr_copy_externally_stored_field_prefix_low( space_id, page_no, offset)); } else { return(btr_copy_blob_prefix(buf, len, space_id, - page_no, offset)); + page_no, offset, trx)); } } @@ -5479,7 +5548,8 @@ btr_copy_externally_stored_field_prefix( field containing also the reference to the external part; must be protected by a lock or a page latch */ - ulint local_len)/*!< in: length of data, in bytes */ + ulint local_len,/*!< in: length of data, in bytes */ + trx_t* trx) /*!< in: transaction handle */ { ulint space_id; ulint page_no; @@ -5518,7 +5588,7 @@ btr_copy_externally_stored_field_prefix( len - local_len, zip_size, space_id, page_no, - offset)); + offset, trx)); } /*******************************************************************//** @@ -5537,7 +5607,8 @@ btr_copy_externally_stored_field( ulint zip_size,/*!< in: nonzero=compressed BLOB page size, zero for uncompressed BLOBs */ ulint local_len,/*!< in: length of data */ - mem_heap_t* heap) /*!< in: mem heap */ + mem_heap_t* heap, /*!< in: mem heap */ + trx_t* trx) /*!< in: transaction handle */ { ulint space_id; ulint page_no; @@ -5568,7 +5639,8 @@ btr_copy_externally_stored_field( extern_len, zip_size, space_id, - page_no, offset); + page_no, offset, + trx); return(buf); } @@ -5587,7 +5659,8 @@ btr_rec_copy_externally_stored_field( zero for uncompressed BLOBs */ ulint no, /*!< in: field number */ ulint* len, /*!< out: length of the field */ - mem_heap_t* heap) /*!< in: mem heap */ + mem_heap_t* heap, /*!< in: mem heap */ + trx_t* trx) /*!< in: transaction handle */ { ulint local_len; const byte* data; @@ -5618,6 +5691,7 @@ btr_rec_copy_externally_stored_field( } return(btr_copy_externally_stored_field(len, data, - zip_size, local_len, heap)); + zip_size, local_len, heap, + trx)); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 82a2b6dbf6b..01d2e1bb8e2 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -486,7 +486,7 @@ btr_pcur_move_backward_from_page( mtr_commit(mtr); - mtr_start(mtr); + mtr_start_trx(mtr, mtr->trx); btr_pcur_restore_position(latch_mode2, cursor, mtr); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 710d9561d4c..33c9eb7a0f2 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -4301,6 +4301,7 @@ corrupt: " because of" " a corrupt database page.\n", stderr); + ut_error; } } @@ -5064,22 +5065,22 @@ Returns the ratio in percents of modified pages in the buffer pool / database pages in the buffer pool. @return modified page percentage ratio */ UNIV_INTERN -ulint +double buf_get_modified_ratio_pct(void) /*============================*/ { - ulint ratio; + double percentage = 0.0; ulint lru_len = 0; ulint free_len = 0; ulint flush_list_len = 0; buf_get_total_list_len(&lru_len, &free_len, &flush_list_len); - ratio = (100 * flush_list_len) / (1 + lru_len + free_len); + percentage = (100.0 * flush_list_len) / (1.0 + lru_len + free_len); /* 1 + is there to avoid division by zero */ - return(ratio); + return(percentage); } /*******************************************************************//** @@ -5292,6 +5293,8 @@ buf_print_io_instance( "Database pages %lu\n" "Old database pages %lu\n" "Modified db pages %lu\n" + "Percent of dirty pages(LRU & free pages): %.3f\n" + "Max dirty pages percent: %.3f\n" "Pending reads %lu\n" "Pending writes: LRU %lu, flush list %lu, single page %lu\n", pool_info->pool_size, @@ -5299,6 +5302,9 @@ buf_print_io_instance( pool_info->lru_len, pool_info->old_lru_len, pool_info->flush_list_len, + (((double) pool_info->flush_list_len) / + (pool_info->lru_len + pool_info->free_list_len + 1.0)) * 100.0, + srv_max_buf_pool_modified_pct, pool_info->n_pend_reads, pool_info->n_pending_flush_lru, pool_info->n_pending_flush_list, diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index d91f036b599..32c3c816a85 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2154,7 +2154,14 @@ page_cleaner_flush_pages_if_needed(void) ulint pct_total = 0; int age_factor = 0; - cur_lsn = log_get_lsn(); + cur_lsn = log_get_lsn_nowait(); + + /* log_get_lsn_nowait tries to get log_sys->mutex with + mutex_enter_nowait, if this does not succeed function + returns 0, do not use that value to update stats. */ + if (cur_lsn == 0) { + return(0); + } if (prev_lsn == 0) { /* First time around. */ diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 7f9f9781874..952f0fc3083 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -1211,7 +1211,7 @@ buf_LRU_check_size_of_non_data_objects( buf_lru_switched_on_innodb_mon = TRUE; srv_print_innodb_monitor = TRUE; - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); } } else if (buf_lru_switched_on_innodb_mon) { @@ -1348,7 +1348,7 @@ loop: mon_value_was = srv_print_innodb_monitor; started_monitor = TRUE; srv_print_innodb_monitor = TRUE; - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); } /* If we have scanned the whole LRU and still are unable to diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 8fdc64a6152..b13f68a08a7 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1708,6 +1708,10 @@ dict_table_rename_in_cache( foreign = *it; + if (foreign->referenced_table) { + foreign->referenced_table->referenced_set.erase(foreign); + } + if (ut_strlen(foreign->foreign_table_name) < ut_strlen(table->name)) { /* Allocate a longer name buffer; @@ -1859,6 +1863,10 @@ dict_table_rename_in_cache( table->foreign_set.erase(it); fk_set.insert(foreign); + + if (foreign->referenced_table) { + foreign->referenced_table->referenced_set.insert(foreign); + } } ut_a(table->foreign_set.empty()); @@ -3274,6 +3282,9 @@ dict_foreign_find( { ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(dict_foreign_set_validate(table->foreign_set)); + ut_ad(dict_foreign_set_validate(table->referenced_set)); + dict_foreign_set::iterator it = table->foreign_set.find(foreign); if (it != table->foreign_set.end()) { @@ -5630,6 +5641,11 @@ dict_find_table_by_space( ut_ad(space_id > 0); + if (dict_sys == NULL) { + /* This could happen when it's in redo processing. */ + return(NULL); + } + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); num_item = UT_LIST_GET_LEN(dict_sys->table_LRU); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index f18859393ee..16e64da6619 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2537,6 +2537,8 @@ func_exit: } } + ut_ad(err != DB_SUCCESS || dict_foreign_set_validate(*table)); + return(table); } diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 885627a61bc..58781fce1d4 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -35,6 +35,7 @@ Created 1/8/1996 Heikki Tuuri #include "mach0data.h" #include "dict0dict.h" #include "fts0priv.h" +#include "ut0crc32.h" #ifndef UNIV_HOTBACKUP # include "ha_prototypes.h" /* innobase_casedn_str(), innobase_get_lower_case_table_names */ @@ -44,6 +45,7 @@ Created 1/8/1996 Heikki Tuuri #ifdef UNIV_BLOB_DEBUG # include "ut0rbt.h" #endif /* UNIV_BLOB_DEBUG */ +#include <iostream> #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when creating a table or index object */ @@ -53,6 +55,18 @@ Created 1/8/1996 Heikki Tuuri UNIV_INTERN mysql_pfs_key_t autoinc_mutex_key; #endif /* UNIV_PFS_MUTEX */ +/** System databases */ +static const char* innobase_system_databases[] = { + "mysql/", + "information_schema/", + "performance_schema/", + NullS +}; + +/** An interger randomly initialized at startup used to make a temporary +table name as unique as possible. */ +static ib_uint32_t dict_temp_file_num; + /**********************************************************************//** Creates a table memory object. @return own: table object */ @@ -85,6 +99,7 @@ dict_mem_table_create( table->flags2 = (unsigned int) flags2; table->name = static_cast<char*>(ut_malloc(strlen(name) + 1)); memcpy(table->name, name, strlen(name) + 1); + table->is_system_db = dict_mem_table_is_system(table->name); table->space = (unsigned int) space; table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS); @@ -131,6 +146,36 @@ dict_mem_table_create( } /****************************************************************//** +Determines if a table belongs to a system database +@return */ +UNIV_INTERN +bool +dict_mem_table_is_system( +/*================*/ + char *name) /*!< in: table name */ +{ + ut_ad(name); + + /* table has the following format: database/table + and some system table are of the form SYS_* */ + if (strchr(name, '/')) { + int table_len = strlen(name); + const char *system_db; + int i = 0; + while ((system_db = innobase_system_databases[i++]) + && (system_db != NullS)) { + int len = strlen(system_db); + if (table_len > len && !strncmp(name, system_db, len)) { + return true; + } + } + return false; + } else { + return true; + } +} + +/****************************************************************//** Free a table memory object. */ UNIV_INTERN void @@ -614,26 +659,120 @@ dict_mem_index_free( mem_heap_free(index->heap); } -/*******************************************************************//** -Create a temporary tablename. -@return temporary tablename suitable for InnoDB use */ +/** Create a temporary tablename like "#sql-ibtid-inc where + tid = the Table ID + inc = a randomly initialized number that is incremented for each file +The table ID is a 64 bit integer, can use up to 20 digits, and is +initialized at bootstrap. The second number is 32 bits, can use up to 10 +digits, and is initialized at startup to a randomly distributed number. +It is hoped that the combination of these two numbers will provide a +reasonably unique temporary file name. +@param[in] heap A memory heap +@param[in] dbtab Table name in the form database/table name +@param[in] id Table id +@return A unique temporary tablename suitable for InnoDB use */ UNIV_INTERN char* dict_mem_create_temporary_tablename( -/*================================*/ - mem_heap_t* heap, /*!< in: memory heap */ - const char* dbtab, /*!< in: database/table name */ - table_id_t id) /*!< in: InnoDB table id */ + mem_heap_t* heap, + const char* dbtab, + table_id_t id) { - const char* dbend = strchr(dbtab, '/'); + size_t size; + char* name; + const char* dbend = strchr(dbtab, '/'); ut_ad(dbend); - size_t dblen = dbend - dbtab + 1; - size_t size = tmp_file_prefix_length + 4 + 9 + 9 + dblen; + size_t dblen = dbend - dbtab + 1; - char* name = static_cast<char*>(mem_heap_alloc(heap, size)); +#ifdef HAVE_ATOMIC_BUILTINS + /* Increment a randomly initialized number for each temp file. */ + os_atomic_increment_uint32(&dict_temp_file_num, 1); +#else /* HAVE_ATOMIC_BUILTINS */ + dict_temp_file_num++; +#endif /* HAVE_ATOMIC_BUILTINS */ + + size = tmp_file_prefix_length + 3 + 20 + 1 + 10 + dblen; + name = static_cast<char*>(mem_heap_alloc(heap, size)); memcpy(name, dbtab, dblen); ut_snprintf(name + dblen, size - dblen, - tmp_file_prefix "-ib" UINT64PF, id); + TEMP_FILE_PREFIX_INNODB UINT64PF "-" UINT32PF, + id, dict_temp_file_num); + return(name); } +/** Initialize dict memory variables */ + +void +dict_mem_init(void) +{ + /* Initialize a randomly distributed temporary file number */ + ib_uint32_t now = static_cast<ib_uint32_t>(ut_time()); + + const byte* buf = reinterpret_cast<const byte*>(&now); + ut_ad(ut_crc32 != NULL); + + dict_temp_file_num = ut_crc32(buf, sizeof(now)); + + DBUG_PRINT("dict_mem_init", + ("Starting Temporary file number is " UINT32PF, + dict_temp_file_num)); +} + +/** Validate the search order in the foreign key set. +@param[in] fk_set the foreign key set to be validated +@return true if search order is fine in the set, false otherwise. */ +bool +dict_foreign_set_validate( + const dict_foreign_set& fk_set) +{ + dict_foreign_not_exists not_exists(fk_set); + + dict_foreign_set::iterator it = std::find_if( + fk_set.begin(), fk_set.end(), not_exists); + + if (it == fk_set.end()) { + return(true); + } + + dict_foreign_t* foreign = *it; + std::cerr << "Foreign key lookup failed: " << *foreign; + std::cerr << fk_set; + ut_ad(0); + return(false); +} + +/** Validate the search order in the foreign key sets of the table +(foreign_set and referenced_set). +@param[in] table table whose foreign key sets are to be validated +@return true if foreign key sets are fine, false otherwise. */ +bool +dict_foreign_set_validate( + const dict_table_t& table) +{ + return(dict_foreign_set_validate(table.foreign_set) + && dict_foreign_set_validate(table.referenced_set)); +} + +std::ostream& +operator<< (std::ostream& out, const dict_foreign_t& foreign) +{ + out << "[dict_foreign_t: id='" << foreign.id << "'"; + + if (foreign.foreign_table_name != NULL) { + out << ",for: '" << foreign.foreign_table_name << "'"; + } + + out << "]"; + return(out); +} + +std::ostream& +operator<< (std::ostream& out, const dict_foreign_set& fk_set) +{ + out << "[dict_foreign_set:"; + std::for_each(fk_set.begin(), fk_set.end(), dict_foreign_print(out)); + out << "]" << std::endl; + return(out); +} + diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 445bf8cc232..bc12774d475 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -151,181 +151,9 @@ UNIV_INTERN mysql_pfs_key_t fil_system_mutex_key; UNIV_INTERN mysql_pfs_key_t fil_space_latch_key; #endif /* UNIV_PFS_RWLOCK */ -/** File node of a tablespace or the log data space */ -struct fil_node_t { - fil_space_t* space; /*!< backpointer to the space where this node - belongs */ - char* name; /*!< path to the file */ - ibool open; /*!< TRUE if file open */ - os_file_t handle; /*!< OS handle to the file, if file open */ - os_event_t sync_event;/*!< Condition event to group and - serialize calls to fsync */ - ibool is_raw_disk;/*!< TRUE if the 'file' is actually a raw - device or a raw disk partition */ - ulint size; /*!< size of the file in database pages, 0 if - not known yet; the possible last incomplete - megabyte may be ignored if space == 0 */ - ulint n_pending; - /*!< count of pending i/o's on this file; - closing of the file is not allowed if - this is > 0 */ - ulint n_pending_flushes; - /*!< count of pending flushes on this file; - closing of the file is not allowed if - this is > 0 */ - ibool being_extended; - /*!< TRUE if the node is currently - being extended. */ - ib_int64_t modification_counter;/*!< when we write to the file we - increment this by one */ - ib_int64_t flush_counter;/*!< up to what - modification_counter value we have - flushed the modifications to disk */ - ulint file_block_size;/*!< file system block size */ - UT_LIST_NODE_T(fil_node_t) chain; - /*!< link field for the file chain */ - UT_LIST_NODE_T(fil_node_t) LRU; - /*!< link field for the LRU list */ - ulint magic_n;/*!< FIL_NODE_MAGIC_N */ -}; - -/** Value of fil_node_t::magic_n */ -#define FIL_NODE_MAGIC_N 89389 - -/** Tablespace or log data space: let us call them by a common name space */ -struct fil_space_t { - char* name; /*!< space name = the path to the first file in - it */ - ulint id; /*!< space id */ - ib_int64_t tablespace_version; - /*!< in DISCARD/IMPORT this timestamp - is used to check if we should ignore - an insert buffer merge request for a - page because it actually was for the - previous incarnation of the space */ - ibool mark; /*!< this is set to TRUE at database startup if - the space corresponds to a table in the InnoDB - data dictionary; so we can print a warning of - orphaned tablespaces */ - ibool stop_ios;/*!< TRUE if we want to rename the - .ibd file of tablespace and want to - stop temporarily posting of new i/o - requests on the file */ - ibool stop_new_ops; - /*!< we set this TRUE when we start - deleting a single-table tablespace. - When this is set following new ops - are not allowed: - * read IO request - * ibuf merge - * file flush - Note that we can still possibly have - new write operations because we don't - check this flag when doing flush - batches. */ - ulint purpose;/*!< FIL_TABLESPACE, FIL_LOG, or - FIL_ARCH_LOG */ - UT_LIST_BASE_NODE_T(fil_node_t) chain; - /*!< base node for the file chain */ - ulint size; /*!< space size in pages; 0 if a single-table - tablespace whose size we do not know yet; - last incomplete megabytes in data files may be - ignored if space == 0 */ - ulint flags; /*!< tablespace flags; see - fsp_flags_is_valid(), - fsp_flags_get_zip_size() */ - ulint n_reserved_extents; - /*!< number of reserved free extents for - ongoing operations like B-tree page split */ - ulint n_pending_flushes; /*!< this is positive when flushing - the tablespace to disk; dropping of the - tablespace is forbidden if this is positive */ - ulint n_pending_ops;/*!< this is positive when we - have pending operations against this - tablespace. The pending operations can - be ibuf merges or lock validation code - trying to read a block. - Dropping of the tablespace is forbidden - if this is positive */ - hash_node_t hash; /*!< hash chain node */ - hash_node_t name_hash;/*!< hash chain the name_hash table */ -#ifndef UNIV_HOTBACKUP - rw_lock_t latch; /*!< latch protecting the file space storage - allocation */ -#endif /* !UNIV_HOTBACKUP */ - UT_LIST_NODE_T(fil_space_t) unflushed_spaces; - /*!< list of spaces with at least one unflushed - file we have written to */ - bool is_in_unflushed_spaces; - /*!< true if this space is currently in - unflushed_spaces */ - UT_LIST_NODE_T(fil_space_t) space_list; - /*!< list of all spaces */ - ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ -}; - -/** Value of fil_space_t::magic_n */ -#define FIL_SPACE_MAGIC_N 89472 - -/** The tablespace memory cache; also the totality of logs (the log -data space) is stored here; below we talk about tablespaces, but also -the ib_logfiles form a 'space' and it is handled here */ -struct fil_system_t { -#ifndef UNIV_HOTBACKUP - ib_mutex_t mutex; /*!< The mutex protecting the cache */ -#endif /* !UNIV_HOTBACKUP */ - hash_table_t* spaces; /*!< The hash table of spaces in the - system; they are hashed on the space - id */ - hash_table_t* name_hash; /*!< hash table based on the space - name */ - UT_LIST_BASE_NODE_T(fil_node_t) LRU; - /*!< base node for the LRU list of the - most recently used open files with no - pending i/o's; if we start an i/o on - the file, we first remove it from this - list, and return it to the start of - the list when the i/o ends; - log files and the system tablespace are - 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 */ - ib_int64_t modification_counter;/*!< when we write to a file we - increment this by one */ - ulint max_assigned_id;/*!< maximum space id in the existing - tables, or assigned during the time - mysqld has been up; at an InnoDB - startup we scan the data dictionary - and set here the maximum of the - space id's of the tables there */ - ib_int64_t tablespace_version; - /*!< a counter which is incremented for - every space object memory creation; - every space mem object gets a - 'timestamp' from this; in DISCARD/ - IMPORT this is used to check if we - should ignore an insert buffer merge - request */ - UT_LIST_BASE_NODE_T(fil_space_t) space_list; - /*!< list of all file spaces */ - ibool space_id_reuse_warned; - /* !< TRUE if fil_space_create() - has issued a warning about - potential space_id reuse */ -}; - /** The tablespace memory cache. This variable is NULL before the module is initialized. */ -static fil_system_t* fil_system = NULL; +fil_system_t* fil_system = NULL; /** Determine if (i) is a user tablespace id or not. */ # define fil_is_user_tablespace_id(i) ((i) > srv_undo_tablespaces_open) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 848d60f6e3f..ae61b77c6de 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -3393,7 +3393,8 @@ fts_fetch_doc_from_rec( dict_table_zip_size(table), clust_pos, &doc->text.f_len, static_cast<mem_heap_t*>( - doc->self_heap->arg)); + doc->self_heap->arg), + NULL); } else { doc->text.f_str = (byte*) rec_get_nth_field( clust_rec, offsets, clust_pos, @@ -7077,7 +7078,8 @@ fts_init_recover_doc( &doc.text.f_len, static_cast<byte*>(dfield_get_data(dfield)), zip_size, len, - static_cast<mem_heap_t*>(doc.self_heap->arg)); + static_cast<mem_heap_t*>(doc.self_heap->arg), + NULL); } else { doc.text.f_str = static_cast<byte*>( dfield_get_data(dfield)); diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index f26fd89ac76..8f4813e4b3f 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1918,7 +1918,8 @@ fts_query_fetch_document( if (dfield_is_ext(dfield)) { data = btr_copy_externally_stored_field( &cur_len, data, phrase->zip_size, - dfield_get_len(dfield), phrase->heap); + dfield_get_len(dfield), phrase->heap, + NULL); } else { cur_len = dfield_get_len(dfield); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5b09c513e4e..2d6b9881bd3 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -275,9 +275,9 @@ static TYPELIB innodb_checksum_algorithm_typelib = { }; /* The following counter is used to convey information to InnoDB -about server activity: in selects it is not sensible to call -srv_active_wake_master_thread after each fetch or search, we only do -it every INNOBASE_WAKE_INTERVAL'th step. */ +about server activity: in case of normal DML ops it is not +sensible to call srv_active_wake_master_thread after each +operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */ #define INNOBASE_WAKE_INTERVAL 32 static ulong innobase_active_counter = 0; @@ -743,6 +743,14 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_rows_read, SHOW_LONG}, {"rows_updated", (char*) &export_vars.innodb_rows_updated, SHOW_LONG}, + {"system_rows_deleted", + (char*) &export_vars.innodb_system_rows_deleted, SHOW_LONG}, + {"system_rows_inserted", + (char*) &export_vars.innodb_system_rows_inserted, SHOW_LONG}, + {"system_rows_read", + (char*) &export_vars.innodb_system_rows_read, SHOW_LONG}, + {"system_rows_updated", + (char*) &export_vars.innodb_system_rows_updated, SHOW_LONG}, {"num_open_files", (char*) &export_vars.innodb_num_open_files, SHOW_LONG}, {"truncated_status_writes", @@ -2690,11 +2698,25 @@ innobase_invalidate_query_cache( above the InnoDB trx_sys_t->lock. The caller of this function must not have latches of a lower rank. */ - /* Argument TRUE below means we are using transactions */ #ifdef HAVE_QUERY_CACHE + char qcache_key_name[2 * (NAME_LEN + 1)]; + size_t tabname_len; + size_t dbname_len; + + /* Construct the key("db-name\0table$name\0") for the query cache using + the path name("db@002dname\0table@0024name\0") of the table in its + canonical form. */ + dbname_len = filename_to_tablename(full_name, qcache_key_name, + sizeof(qcache_key_name)); + tabname_len = filename_to_tablename(full_name + strlen(full_name) + 1, + qcache_key_name + dbname_len + 1, + sizeof(qcache_key_name) + - dbname_len - 1); + + /* Argument TRUE below means we are using transactions */ mysql_query_cache_invalidate4(trx->mysql_thd, - full_name, - (uint32) full_name_len, + qcache_key_name, + (dbname_len + tabname_len + 2), TRUE); #endif } @@ -3333,7 +3355,7 @@ innobase_change_buffering_inited_ok: " cannot be set higher than" " innodb_max_dirty_pages_pct.\n" "InnoDB: Setting" - " innodb_max_dirty_pages_pct_lwm to %lu\n", + " innodb_max_dirty_pages_pct_lwm to %lf\n", srv_max_buf_pool_modified_pct); srv_max_dirty_pages_pct_lwm = srv_max_buf_pool_modified_pct; @@ -3988,10 +4010,6 @@ innobase_commit( innobase_srv_conc_force_exit_innodb(trx); - /* Tell the InnoDB server that there might be work for utility - threads: */ - srv_active_wake_master_thread(); - DBUG_RETURN(0); } @@ -8736,7 +8754,8 @@ ha_innobase::index_read( row_sel_convert_mysql_key_to_innobase( prebuilt->search_tuple, - srch_key_val1, sizeof(srch_key_val1), + prebuilt->srch_key_val1, + prebuilt->srch_key_val_len, index, (byte*) key_ptr, (ulint) key_len, @@ -8782,7 +8801,13 @@ ha_innobase::index_read( case DB_SUCCESS: error = 0; table->status = 0; - srv_stats.n_rows_read.add((size_t) prebuilt->trx->id, 1); + if (prebuilt->table->is_system_db) { + srv_stats.n_system_rows_read.add( + (size_t) prebuilt->trx->id, 1); + } else { + srv_stats.n_rows_read.add( + (size_t) prebuilt->trx->id, 1); + } break; case DB_RECORD_NOT_FOUND: error = HA_ERR_KEY_NOT_FOUND; @@ -9058,7 +9083,13 @@ ha_innobase::general_fetch( case DB_SUCCESS: error = 0; table->status = 0; - srv_stats.n_rows_read.add((size_t) prebuilt->trx->id, 1); + if (prebuilt->table->is_system_db) { + srv_stats.n_system_rows_read.add( + (size_t) prebuilt->trx->id, 1); + } else { + srv_stats.n_rows_read.add( + (size_t) prebuilt->trx->id, 1); + } break; case DB_RECORD_NOT_FOUND: error = HA_ERR_END_OF_FILE; @@ -11866,11 +11897,6 @@ ha_innobase::delete_table( log_buffer_flush_to_disk(); - /* Tell the InnoDB server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - innobase_commit_low(trx); trx_free_for_mysql(trx); @@ -12017,11 +12043,6 @@ innobase_drop_database( log_buffer_flush_to_disk(); - /* Tell the InnoDB server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - innobase_commit_low(trx); trx_free_for_mysql(trx); } @@ -12171,11 +12192,6 @@ ha_innobase::rename_table( DEBUG_SYNC(thd, "after_innobase_rename_table"); - /* Tell the InnoDB server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - innobase_commit_low(trx); trx_free_for_mysql(trx); @@ -12291,7 +12307,8 @@ ha_innobase::records_in_range( row_sel_convert_mysql_key_to_innobase( range_start, - srch_key_val1, sizeof(srch_key_val1), + prebuilt->srch_key_val1, + prebuilt->srch_key_val_len, index, (byte*) (min_key ? min_key->key : (const uchar*) 0), @@ -12303,7 +12320,8 @@ ha_innobase::records_in_range( row_sel_convert_mysql_key_to_innobase( range_end, - srch_key_val2, sizeof(srch_key_val2), + prebuilt->srch_key_val2, + prebuilt->srch_key_val_len, index, (byte*) (max_key ? max_key->key : (const uchar*) 0), @@ -12322,7 +12340,7 @@ ha_innobase::records_in_range( n_rows = btr_estimate_n_rows_in_range(index, range_start, mode1, range_end, - mode2); + mode2, prebuilt->trx); } else { n_rows = HA_POS_ERROR; @@ -15534,11 +15552,6 @@ innobase_xa_prepare( trx_mark_sql_stat_end(trx); } - /* Tell the InnoDB server that there might be work for utility - threads: */ - - srv_active_wake_master_thread(); - return(error); } @@ -15739,14 +15752,17 @@ innodb_io_capacity_max_update( { ulong in_val = *static_cast<const ulong*>(save); if (in_val < srv_io_capacity) { - in_val = srv_io_capacity; push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, - "innodb_io_capacity_max cannot be" - " set lower than innodb_io_capacity."); + "Setting innodb_io_capacity_max %lu" + " lower than innodb_io_capacity %lu.", + in_val, srv_io_capacity); + + srv_io_capacity = in_val; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, - "Setting innodb_io_capacity_max to %lu", + "Setting innodb_io_capacity to %lu", srv_io_capacity); } @@ -15769,15 +15785,19 @@ innodb_io_capacity_update( from check function */ { ulong in_val = *static_cast<const ulong*>(save); + if (in_val > srv_max_io_capacity) { - in_val = srv_max_io_capacity; push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, - "innodb_io_capacity cannot be set" - " higher than innodb_io_capacity_max."); + "Setting innodb_io_capacity to %lu" + " higher than innodb_io_capacity_max %lu", + in_val, srv_max_io_capacity); + + srv_max_io_capacity = in_val * 2; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, - "Setting innodb_io_capacity to %lu", + "Setting innodb_max_io_capacity to %lu", srv_max_io_capacity); } @@ -15799,7 +15819,7 @@ innodb_max_dirty_pages_pct_update( const void* save) /*!< in: immediate result from check function */ { - ulong in_val = *static_cast<const ulong*>(save); + double in_val = *static_cast<const double*>(save); if (in_val < srv_max_dirty_pages_pct_lwm) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, @@ -15809,7 +15829,7 @@ innodb_max_dirty_pages_pct_update( push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, "Lowering" - " innodb_max_dirty_page_pct_lwm to %lu", + " innodb_max_dirty_page_pct_lwm to %lf", in_val); srv_max_dirty_pages_pct_lwm = in_val; @@ -15833,7 +15853,7 @@ innodb_max_dirty_pages_pct_lwm_update( const void* save) /*!< in: immediate result from check function */ { - ulong in_val = *static_cast<const ulong*>(save); + double in_val = *static_cast<const double*>(save); if (in_val > srv_max_buf_pool_modified_pct) { in_val = srv_max_buf_pool_modified_pct; push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, @@ -15844,7 +15864,7 @@ innodb_max_dirty_pages_pct_lwm_update( push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, "Setting innodb_max_dirty_page_pct_lwm" - " to %lu", + " to %lf", in_val); } @@ -17567,9 +17587,8 @@ innodb_status_output_update( const void* save __attribute__((unused))) { *static_cast<my_bool*>(var_ptr) = *static_cast<const my_bool*>(save); - /* The lock timeout monitor thread also takes care of this - output. */ - os_event_set(lock_sys->timeout_event); + /* Wakeup server monitor thread. */ + os_event_set(srv_monitor_event); } static SHOW_VAR innodb_status_variables_export[]= { @@ -18087,22 +18106,22 @@ static MYSQL_SYSVAR_STR(log_group_home_dir, srv_log_group_home_dir, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Path to InnoDB log files.", NULL, NULL, NULL); -static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, +static MYSQL_SYSVAR_DOUBLE(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, PLUGIN_VAR_RQCMDARG, "Percentage of dirty pages allowed in bufferpool.", - NULL, innodb_max_dirty_pages_pct_update, 75, 0, 99, 0); + NULL, innodb_max_dirty_pages_pct_update, 75.0, 0.001, 99.999, 0); -static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct_lwm, +static MYSQL_SYSVAR_DOUBLE(max_dirty_pages_pct_lwm, srv_max_dirty_pages_pct_lwm, PLUGIN_VAR_RQCMDARG, "Percentage of dirty pages at which flushing kicks in.", - NULL, innodb_max_dirty_pages_pct_lwm_update, 0, 0, 99, 0); + NULL, innodb_max_dirty_pages_pct_lwm_update, 0.001, 0.000, 99.999, 0); -static MYSQL_SYSVAR_ULONG(adaptive_flushing_lwm, +static MYSQL_SYSVAR_DOUBLE(adaptive_flushing_lwm, srv_adaptive_flushing_lwm, PLUGIN_VAR_RQCMDARG, "Percentage of log capacity below which no adaptive flushing happens.", - NULL, NULL, 10, 0, 70, 0); + NULL, NULL, 10.0, 0.0, 70.0, 0); static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing, PLUGIN_VAR_NOCMDARG, @@ -18177,6 +18196,16 @@ static MYSQL_SYSVAR_ULONGLONG(stats_persistent_sample_pages, "statistics (by ANALYZE, default 20)", NULL, NULL, 20, 1, ~0ULL, 0); +static MYSQL_SYSVAR_ULONGLONG(stats_modified_counter, srv_stats_modified_counter, + PLUGIN_VAR_RQCMDARG, + "The number of rows modified before we calculate new statistics (default 0 = current limits)", + NULL, NULL, 0, 0, ~0ULL, 0); + +static MYSQL_SYSVAR_BOOL(stats_traditional, srv_stats_sample_traditional, + PLUGIN_VAR_RQCMDARG, + "Enable traditional statistic calculation based on number of configured pages (default true)", + NULL, NULL, TRUE); + static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled, PLUGIN_VAR_OPCMDARG, "Enable InnoDB adaptive hash index (enabled by default). " @@ -18952,6 +18981,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(stats_persistent), MYSQL_SYSVAR(stats_persistent_sample_pages), MYSQL_SYSVAR(stats_auto_recalc), + MYSQL_SYSVAR(stats_modified_counter), + MYSQL_SYSVAR(stats_traditional), MYSQL_SYSVAR(adaptive_hash_index), MYSQL_SYSVAR(stats_method), MYSQL_SYSVAR(replication_delay), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index c1706a059e2..6da31c8ecc6 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -88,13 +88,6 @@ class ha_innobase: public handler uchar* upd_buf; /*!< buffer used in updates */ ulint upd_buf_size; /*!< the size of upd_buf in bytes */ - uchar srch_key_val1[MAX_KEY_LENGTH + MAX_REF_PARTS*2]; - uchar srch_key_val2[MAX_KEY_LENGTH + MAX_REF_PARTS*2]; - /*!< buffers used in converting - search key values from MySQL format - to InnoDB format. For each column - 2 bytes are used to store length, - hence MAX_REF_PARTS*2. */ Table_flags int_table_flags; uint primary_key; ulong start_of_scan; /*!< this is set to 1 when we are diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 74eb8d4a5b6..d08fe25d377 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -22,6 +22,7 @@ this program; if not, write to the Free Software Foundation, Inc., Smart ALTER TABLE *******************************************************/ +#include <my_global.h> #include <unireg.h> #include <mysqld_error.h> #include <log.h> @@ -2255,7 +2256,7 @@ innobase_check_foreigns_low( /* Check if any FOREIGN KEY constraints are defined on this column. */ - for (dict_foreign_set::iterator it = user_table->foreign_set.begin(); + for (dict_foreign_set::const_iterator it = user_table->foreign_set.begin(); it != user_table->foreign_set.end(); ++it) { @@ -2292,7 +2293,7 @@ innobase_check_foreigns_low( /* Check if any FOREIGN KEY constraints in other tables are referring to the column that is being dropped. */ - for (dict_foreign_set::iterator it + for (dict_foreign_set::const_iterator it = user_table->referenced_set.begin(); it != user_table->referenced_set.end(); ++it) { @@ -2478,7 +2479,7 @@ innobase_build_col_map( innobase_build_col_map_add( heap, dtuple_get_nth_field(add_cols, i), - altered_table->s->field[sql_idx], + altered_table->field[sql_idx], dict_table_is_comp(new_table)); found_col: i++; @@ -3262,9 +3263,6 @@ err_exit: delete ctx; ha_alter_info->handler_ctx = NULL; - /* There might be work for utility threads.*/ - srv_active_wake_master_thread(); - DBUG_RETURN(true); } @@ -4311,7 +4309,6 @@ func_exit: } trx_commit_for_mysql(prebuilt->trx); - srv_active_wake_master_thread(); MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); DBUG_RETURN(fail); } @@ -4485,7 +4482,7 @@ err_exit: rename_foreign: trx->op_info = "renaming column in SYS_FOREIGN_COLS"; - for (dict_foreign_set::iterator it = user_table->foreign_set.begin(); + for (dict_foreign_set::const_iterator it = user_table->foreign_set.begin(); it != user_table->foreign_set.end(); ++it) { @@ -4520,7 +4517,7 @@ rename_foreign: } } - for (dict_foreign_set::iterator it + for (dict_foreign_set::const_iterator it = user_table->referenced_set.begin(); it != user_table->referenced_set.end(); ++it) { @@ -4824,14 +4821,17 @@ innobase_update_foreign_try( /** Update the foreign key constraint definitions in the data dictionary cache after the changes to data dictionary tables were committed. @param ctx In-place ALTER TABLE context +@param user_thd MySQL connection @return InnoDB error code (should always be DB_SUCCESS) */ static __attribute__((nonnull, warn_unused_result)) dberr_t innobase_update_foreign_cache( /*==========================*/ - ha_innobase_inplace_ctx* ctx) + ha_innobase_inplace_ctx* ctx, + THD* user_thd) { dict_table_t* user_table; + dberr_t err = DB_SUCCESS; DBUG_ENTER("innobase_update_foreign_cache"); @@ -4866,9 +4866,34 @@ innobase_update_foreign_cache( /* Load the old or added foreign keys from the data dictionary and prevent the table from being evicted from the data dictionary cache (work around the lack of WL#6049). */ - DBUG_RETURN(dict_load_foreigns(user_table->name, - ctx->col_names, false, true, - DICT_ERR_IGNORE_NONE)); + err = dict_load_foreigns(user_table->name, + ctx->col_names, false, true, + DICT_ERR_IGNORE_NONE); + + if (err == DB_CANNOT_ADD_CONSTRAINT) { + /* It is possible there are existing foreign key are + loaded with "foreign_key checks" off, + so let's retry the loading with charset_check is off */ + err = dict_load_foreigns(user_table->name, + ctx->col_names, false, false, + DICT_ERR_IGNORE_NONE); + + /* The load with "charset_check" off is successful, warn + the user that the foreign key has loaded with mis-matched + charset */ + if (err == DB_SUCCESS) { + push_warning_printf( + user_thd, + Sql_condition::WARN_LEVEL_WARN, + ER_ALTER_INFO, + "Foreign key constraints for table '%s'" + " are loaded with charset check off", + user_table->name); + + } + } + + DBUG_RETURN(err); } /** Commit the changes made during prepare_inplace_alter_table() @@ -5744,12 +5769,12 @@ ha_innobase::commit_inplace_alter_table( /* Rename the tablespace files. */ commit_cache_rebuild(ctx); - error = innobase_update_foreign_cache(ctx); + error = innobase_update_foreign_cache(ctx, user_thd); if (error != DB_SUCCESS) { goto foreign_fail; } } else { - error = innobase_update_foreign_cache(ctx); + error = innobase_update_foreign_cache(ctx, user_thd); if (error != DB_SUCCESS) { foreign_fail: diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index f1e4406fcf7..d0fd5c2158a 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -561,7 +561,8 @@ btr_estimate_n_rows_in_range( const dtuple_t* tuple1, /*!< in: range start, may also be empty tuple */ ulint mode1, /*!< in: search mode for range start */ const dtuple_t* tuple2, /*!< in: range end, may also be empty tuple */ - ulint mode2); /*!< in: search mode for range end */ + ulint mode2, /*!< in: search mode for range end */ + trx_t* trx); /*!< in: trx */ /*******************************************************************//** Estimates the number of different key values in a given index, for each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index). @@ -697,7 +698,8 @@ btr_copy_externally_stored_field_prefix( field containing also the reference to the external part; must be protected by a lock or a page latch */ - ulint local_len);/*!< in: length of data, in bytes */ + ulint local_len,/*!< in: length of data, in bytes */ + trx_t* trx); /*!< in: transaction handle */ /*******************************************************************//** Copies an externally stored field of a record to mem heap. The clustered index record must be protected by a lock or a page latch. @@ -714,7 +716,8 @@ btr_copy_externally_stored_field( ulint zip_size,/*!< in: nonzero=compressed BLOB page size, zero for uncompressed BLOBs */ ulint local_len,/*!< in: length of data */ - mem_heap_t* heap); /*!< in: mem heap */ + mem_heap_t* heap, /*!< in: mem heap */ + trx_t* trx); /*!< in: transaction handle */ /*******************************************************************//** Copies an externally stored field of a record to mem heap. @return the field copied to heap, or NULL if the field is incomplete */ @@ -729,7 +732,8 @@ btr_rec_copy_externally_stored_field( zero for uncompressed BLOBs */ ulint no, /*!< in: field number */ ulint* len, /*!< out: length of the field */ - mem_heap_t* heap); /*!< in: mem heap */ + mem_heap_t* heap, /*!< in: mem heap */ + trx_t* trx); /*!< in: transaction handle */ /*******************************************************************//** Flags the data tuple fields that are marked as extern storage in the update vector. We use this function to remember which fields we must diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 4917b57f325..7ea29169a48 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -795,7 +795,7 @@ Returns the ratio in percents of modified pages in the buffer pool / database pages in the buffer pool. @return modified page percentage ratio */ UNIV_INTERN -ulint +double buf_get_modified_ratio_pct(void); /*============================*/ /**********************************************************************//** diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 6528ee39acc..1d59bc09f6d 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -50,6 +50,7 @@ Created 1/8/1996 Heikki Tuuri #include "os0once.h" #include <set> #include <algorithm> +#include <iterator> /* Forward declaration. */ struct ib_rbt_t; @@ -307,6 +308,14 @@ dict_mem_table_create( ulint n_cols, /*!< in: number of columns */ ulint flags, /*!< in: table flags */ ulint flags2); /*!< in: table flags2 */ +/**********************************************************************//** +Determines if a table belongs to a system database +@return */ +UNIV_INTERN +bool +dict_mem_table_is_system( +/*==================*/ + char *name); /*!< in: table name */ /****************************************************************//** Free a table memory object. */ UNIV_INTERN @@ -435,16 +444,29 @@ dict_mem_referenced_table_name_lookup_set( dict_foreign_t* foreign, /*!< in/out: foreign struct */ ibool do_alloc); /*!< in: is an alloc needed */ -/*******************************************************************//** -Create a temporary tablename. -@return temporary tablename suitable for InnoDB use */ -UNIV_INTERN __attribute__((nonnull, warn_unused_result)) +/** Create a temporary tablename like "#sql-ibtid-inc where + tid = the Table ID + inc = a randomly initialized number that is incremented for each file +The table ID is a 64 bit integer, can use up to 20 digits, and is +initialized at bootstrap. The second number is 32 bits, can use up to 10 +digits, and is initialized at startup to a randomly distributed number. +It is hoped that the combination of these two numbers will provide a +reasonably unique temporary file name. +@param[in] heap A memory heap +@param[in] dbtab Table name in the form database/table name +@param[in] id Table id +@return A unique temporary tablename suitable for InnoDB use */ +UNIV_INTERN char* dict_mem_create_temporary_tablename( -/*================================*/ - mem_heap_t* heap, /*!< in: memory heap */ - const char* dbtab, /*!< in: database/table name */ - table_id_t id); /*!< in: InnoDB table id */ + mem_heap_t* heap, + const char* dbtab, + table_id_t id); + +/** Initialize dict memory variables */ + +void +dict_mem_init(void); /** Data structure for a column in a table */ struct dict_col_t{ @@ -785,6 +807,22 @@ struct dict_foreign_t{ dict_index_t* referenced_index;/*!< referenced index */ }; +std::ostream& +operator<< (std::ostream& out, const dict_foreign_t& foreign); + +struct dict_foreign_print { + + dict_foreign_print(std::ostream& out) + : m_out(out) + {} + + void operator()(const dict_foreign_t* foreign) { + m_out << *foreign; + } +private: + std::ostream& m_out; +}; + /** Compare two dict_foreign_t objects using their ids. Used in the ordering of dict_table_t::foreign_set and dict_table_t::referenced_set. It returns true if the first argument is considered to go before the second in the @@ -854,6 +892,40 @@ struct dict_foreign_matches_id { typedef std::set<dict_foreign_t*, dict_foreign_compare> dict_foreign_set; +std::ostream& +operator<< (std::ostream& out, const dict_foreign_set& fk_set); + +/** Function object to check if a foreign key object is there +in the given foreign key set or not. It returns true if the +foreign key is not found, false otherwise */ +struct dict_foreign_not_exists { + dict_foreign_not_exists(const dict_foreign_set& obj_) + : m_foreigns(obj_) + {} + + /* Return true if the given foreign key is not found */ + bool operator()(dict_foreign_t* const & foreign) const { + return(m_foreigns.find(foreign) == m_foreigns.end()); + } +private: + const dict_foreign_set& m_foreigns; +}; + +/** Validate the search order in the foreign key set. +@param[in] fk_set the foreign key set to be validated +@return true if search order is fine in the set, false otherwise. */ +bool +dict_foreign_set_validate( + const dict_foreign_set& fk_set); + +/** Validate the search order in the foreign key sets of the table +(foreign_set and referenced_set). +@param[in] table table whose foreign key sets are to be validated +@return true if foreign key sets are fine, false otherwise. */ +bool +dict_foreign_set_validate( + const dict_table_t& table); + /*********************************************************************//** Frees a foreign key struct. */ inline @@ -955,6 +1027,10 @@ struct dict_table_t{ the string contains n_cols, it will be allocated from a temporary heap. The final string will be allocated from table->heap. */ + bool is_system_db; + /*!< True if the table belongs to a system + database (mysql, information_schema or + performance_schema) */ #ifndef UNIV_HOTBACKUP hash_node_t name_hash; /*!< hash chain node */ hash_node_t id_hash; /*!< hash chain node */ diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 5f471d1a45f..35430e8ea62 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -86,6 +86,7 @@ typedef enum { /** Prefix for tmp tables, adopted from sql/table.h */ #define tmp_file_prefix "#sql" #define tmp_file_prefix_length 4 +#define TEMP_FILE_PREFIX_INNODB "#sql-ib" #define TEMP_TABLE_PREFIX "#sql" #define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 5148773d95c..9c453d3f4ca 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -34,6 +34,7 @@ Created 10/25/1995 Heikki Tuuri #include "dict0types.h" #include "ut0byte.h" #include "os0file.h" +#include "hash0hash.h" #ifndef UNIV_HOTBACKUP #include "sync0rw.h" #include "ibuf0types.h" @@ -215,6 +216,184 @@ struct fsp_open_info { #endif /* UNIV_LOG_ARCHIVE */ }; +struct fil_space_t; + +/** File node of a tablespace or the log data space */ +struct fil_node_t { + fil_space_t* space; /*!< backpointer to the space where this node + belongs */ + char* name; /*!< path to the file */ + ibool open; /*!< TRUE if file open */ + os_file_t handle; /*!< OS handle to the file, if file open */ + os_event_t sync_event;/*!< Condition event to group and + serialize calls to fsync */ + ibool is_raw_disk;/*!< TRUE if the 'file' is actually a raw + device or a raw disk partition */ + ulint size; /*!< size of the file in database pages, 0 if + not known yet; the possible last incomplete + megabyte may be ignored if space == 0 */ + ulint n_pending; + /*!< count of pending i/o's on this file; + closing of the file is not allowed if + this is > 0 */ + ulint n_pending_flushes; + /*!< count of pending flushes on this file; + closing of the file is not allowed if + this is > 0 */ + ibool being_extended; + /*!< TRUE if the node is currently + being extended. */ + ib_int64_t modification_counter;/*!< when we write to the file we + increment this by one */ + ib_int64_t flush_counter;/*!< up to what + modification_counter value we have + flushed the modifications to disk */ + ulint file_block_size;/*!< file system block size */ + UT_LIST_NODE_T(fil_node_t) chain; + /*!< link field for the file chain */ + UT_LIST_NODE_T(fil_node_t) LRU; + /*!< link field for the LRU list */ + ulint magic_n;/*!< FIL_NODE_MAGIC_N */ +}; + +/** Value of fil_node_t::magic_n */ +#define FIL_NODE_MAGIC_N 89389 + +/** Tablespace or log data space: let us call them by a common name space */ +struct fil_space_t { + char* name; /*!< space name = the path to the first file in + it */ + ulint id; /*!< space id */ + ib_int64_t tablespace_version; + /*!< in DISCARD/IMPORT this timestamp + is used to check if we should ignore + an insert buffer merge request for a + page because it actually was for the + previous incarnation of the space */ + ibool mark; /*!< this is set to TRUE at database startup if + the space corresponds to a table in the InnoDB + data dictionary; so we can print a warning of + orphaned tablespaces */ + ibool stop_ios;/*!< TRUE if we want to rename the + .ibd file of tablespace and want to + stop temporarily posting of new i/o + requests on the file */ + ibool stop_new_ops; + /*!< we set this TRUE when we start + deleting a single-table tablespace. + When this is set following new ops + are not allowed: + * read IO request + * ibuf merge + * file flush + Note that we can still possibly have + new write operations because we don't + check this flag when doing flush + batches. */ + ulint purpose;/*!< FIL_TABLESPACE, FIL_LOG, or + FIL_ARCH_LOG */ + UT_LIST_BASE_NODE_T(fil_node_t) chain; + /*!< base node for the file chain */ + ulint size; /*!< space size in pages; 0 if a single-table + tablespace whose size we do not know yet; + last incomplete megabytes in data files may be + ignored if space == 0 */ + ulint flags; /*!< tablespace flags; see + fsp_flags_is_valid(), + fsp_flags_get_zip_size() */ + ulint n_reserved_extents; + /*!< number of reserved free extents for + ongoing operations like B-tree page split */ + ulint n_pending_flushes; /*!< this is positive when flushing + the tablespace to disk; dropping of the + tablespace is forbidden if this is positive */ + ulint n_pending_ops;/*!< this is positive when we + have pending operations against this + tablespace. The pending operations can + be ibuf merges or lock validation code + trying to read a block. + Dropping of the tablespace is forbidden + if this is positive */ + hash_node_t hash; /*!< hash chain node */ + hash_node_t name_hash;/*!< hash chain the name_hash table */ +#ifndef UNIV_HOTBACKUP + rw_lock_t latch; /*!< latch protecting the file space storage + allocation */ +#endif /* !UNIV_HOTBACKUP */ + UT_LIST_NODE_T(fil_space_t) unflushed_spaces; + /*!< list of spaces with at least one unflushed + file we have written to */ + bool is_in_unflushed_spaces; + /*!< true if this space is currently in + unflushed_spaces */ + UT_LIST_NODE_T(fil_space_t) space_list; + /*!< list of all spaces */ + ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ +}; + +/** Value of fil_space_t::magic_n */ +#define FIL_SPACE_MAGIC_N 89472 + +/** The tablespace memory cache; also the totality of logs (the log +data space) is stored here; below we talk about tablespaces, but also +the ib_logfiles form a 'space' and it is handled here */ +struct fil_system_t { +#ifndef UNIV_HOTBACKUP + ib_mutex_t mutex; /*!< The mutex protecting the cache */ +#endif /* !UNIV_HOTBACKUP */ + hash_table_t* spaces; /*!< The hash table of spaces in the + system; they are hashed on the space + id */ + hash_table_t* name_hash; /*!< hash table based on the space + name */ + UT_LIST_BASE_NODE_T(fil_node_t) LRU; + /*!< base node for the LRU list of the + most recently used open files with no + pending i/o's; if we start an i/o on + the file, we first remove it from this + list, and return it to the start of + the list when the i/o ends; + log files and the system tablespace are + 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 */ + ib_int64_t modification_counter;/*!< when we write to a file we + increment this by one */ + ulint max_assigned_id;/*!< maximum space id in the existing + tables, or assigned during the time + mysqld has been up; at an InnoDB + startup we scan the data dictionary + and set here the maximum of the + space id's of the tables there */ + ib_int64_t tablespace_version; + /*!< a counter which is incremented for + every space object memory creation; + every space mem object gets a + 'timestamp' from this; in DISCARD/ + IMPORT this is used to check if we + should ignore an insert buffer merge + request */ + UT_LIST_BASE_NODE_T(fil_space_t) space_list; + /*!< list of all file spaces */ + ibool space_id_reuse_warned; + /* !< TRUE if fil_space_create() + has issued a warning about + potential space_id reuse */ +}; + +/** The tablespace memory cache. This variable is NULL before the module is +initialized. */ +extern fil_system_t* fil_system; + #ifndef UNIV_HOTBACKUP /*******************************************************************//** Returns the version number of a tablespace, -1 if not found. diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 7c79eb96ca9..38ed2b51a4e 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -442,14 +442,14 @@ lsn_t log_get_lsn_nowait(void) /*=============*/ { - lsn_t lsn; + lsn_t lsn=0; - if (mutex_enter_nowait(&(log_sys->mutex))) - return 0; + if (!mutex_enter_nowait(&(log_sys->mutex))) { - lsn = log_sys->lsn; + lsn = log_sys->lsn; - mutex_exit(&(log_sys->mutex)); + mutex_exit(&(log_sys->mutex)); + } return(lsn); } diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index ed7fd76d425..b91dbd0353c 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -35,6 +35,7 @@ Created 11/26/1995 Heikki Tuuri #include "ut0byte.h" #include "mtr0types.h" #include "page0types.h" +#include "trx0types.h" /* Logging modes for a mini-transaction */ #define MTR_LOG_ALL 21 /* default mode: log all operations @@ -204,10 +205,22 @@ functions). The page number parameter was originally written as 0. @{ */ Starts a mini-transaction. */ UNIV_INLINE void +mtr_start_trx( +/*======*/ + mtr_t* mtr, /*!< out: mini-transaction */ + trx_t* trx) /*!< in: transaction */ + __attribute__((nonnull (1))); +/***************************************************************//** +Starts a mini-transaction. */ +UNIV_INLINE +void mtr_start( /*======*/ mtr_t* mtr) /*!< out: mini-transaction */ - __attribute__((nonnull)); +{ + mtr_start_trx(mtr, NULL); +} + __attribute__((nonnull)) /***************************************************************//** Commits a mini-transaction. */ UNIV_INTERN @@ -403,6 +416,7 @@ struct mtr_t{ #ifdef UNIV_DEBUG ulint magic_n; #endif /* UNIV_DEBUG */ + trx_t* trx; /*!< transaction */ }; #ifdef UNIV_DEBUG diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index a9f02430220..44d548e9b64 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -43,9 +43,10 @@ mtr_block_dirtied( Starts a mini-transaction. */ UNIV_INLINE void -mtr_start( +mtr_start_trx( /*======*/ - mtr_t* mtr) /*!< out: mini-transaction */ + mtr_t* mtr, /*!< out: mini-transaction */ + trx_t* trx) /*!< in: transaction */ { UNIV_MEM_INVALID(mtr, sizeof *mtr); @@ -58,6 +59,7 @@ mtr_start( mtr->made_dirty = FALSE; mtr->n_log_recs = 0; mtr->n_freed_pages = 0; + mtr->trx = trx; ut_d(mtr->state = MTR_ACTIVE); ut_d(mtr->magic_n = MTR_MAGIC_N); diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index e82ef17f718..8f8aef4f45c 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -140,6 +140,7 @@ enum os_file_create_t { /* @} */ /** Error codes from os_file_get_last_error @{ */ +#define OS_FILE_NAME_TOO_LONG 36 #define OS_FILE_NOT_FOUND 71 #define OS_FILE_DISK_FULL 72 #define OS_FILE_ALREADY_EXISTS 73 diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h index 8bf57677ecf..b16a99b51c0 100644 --- a/storage/innobase/include/os0sync.h +++ b/storage/innobase/include/os0sync.h @@ -322,12 +322,29 @@ pfs_os_fast_mutex_unlock( #endif /* UNIV_PFS_MUTEX */ /**********************************************************//** +Acquires ownership of a fast mutex. Implies a full memory barrier even on +platforms such as PowerPC where this is not normally required. +@return 0 if success, != 0 if was reserved by another thread */ +UNIV_INLINE +ulint +os_fast_mutex_trylock_full_barrier( +/*==================*/ + os_fast_mutex_t* fast_mutex); /*!< in: mutex to acquire */ +/**********************************************************//** Releases ownership of a fast mutex. */ UNIV_INTERN void os_fast_mutex_unlock_func( /*======================*/ fast_mutex_t* fast_mutex); /*!< in: mutex to release */ +/**********************************************************//** +Releases ownership of a fast mutex. Implies a full memory barrier even on +platforms such as PowerPC where this is not normally required. */ +UNIV_INTERN +void +os_fast_mutex_unlock_full_barrier( +/*=================*/ + os_fast_mutex_t* fast_mutex); /*!< in: mutex to release */ /*********************************************************//** Initializes an operating system fast mutex semaphore. */ UNIV_INTERN @@ -432,14 +449,31 @@ amount to decrement. */ /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ -# define os_atomic_test_and_set_byte(ptr, new_val) \ - __sync_lock_test_and_set(ptr, (byte) new_val) - # define os_atomic_test_and_set_ulint(ptr, new_val) \ __sync_lock_test_and_set(ptr, new_val) -# define os_atomic_lock_release_byte(ptr) \ - __sync_lock_release(ptr) +#ifdef __powerpc__ +/* + os_atomic_test_and_set_byte_release() should imply a release barrier before + setting, and a full barrier after. But __sync_lock_test_and_set() is only + documented as an aquire barrier. So on PowerPC we need to add the full + barrier explicitly. */ +# define os_atomic_test_and_set_byte_release(ptr, new_val) \ + do { __sync_lock_release(ptr); \ + __sync_synchronize(); } while (0) +#else +/* + On x86, __sync_lock_test_and_set() happens to be full barrier, due to + LOCK prefix. +*/ +# define os_atomic_test_and_set_byte_release(ptr, new_val) \ + __sync_lock_test_and_set(ptr, (byte) new_val) +#endif +/* + os_atomic_test_and_set_byte_acquire() is a full memory barrier on x86. But + in general, just an aquire barrier should be sufficient. */ +# define os_atomic_test_and_set_byte_acquire(ptr, new_val) \ + __sync_lock_test_and_set(ptr, (byte) new_val) #elif defined(HAVE_IB_SOLARIS_ATOMICS) @@ -517,14 +551,14 @@ amount to decrement. */ /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ -# define os_atomic_test_and_set_byte(ptr, new_val) \ - atomic_swap_uchar(ptr, new_val) - # define os_atomic_test_and_set_ulint(ptr, new_val) \ atomic_swap_ulong(ptr, new_val) -# define os_atomic_lock_release_byte(ptr) \ - (void) atomic_swap_uchar(ptr, 0) +# define os_atomic_test_and_set_byte_acquire(ptr, new_val) \ + atomic_swap_uchar(ptr, new_val) + +# define os_atomic_test_and_set_byte_release(ptr, new_val) \ + atomic_swap_uchar(ptr, new_val) #elif defined(HAVE_WINDOWS_ATOMICS) @@ -644,7 +678,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val. InterlockedExchange() operates on LONG, and the LONG will be clobbered */ -# define os_atomic_test_and_set_byte(ptr, new_val) \ +# define os_atomic_test_and_set_byte_acquire(ptr, new_val) \ + ((byte) InterlockedExchange(ptr, new_val)) +# define os_atomic_test_and_set_byte_release(ptr, new_val) \ ((byte) InterlockedExchange(ptr, new_val)) # define os_atomic_test_and_set_ulong(ptr, new_val) \ @@ -713,11 +749,7 @@ architecture. Disable memory barrier for Intel architecture for now. */ # define HAVE_MEMORY_BARRIER # define os_rmb __atomic_thread_fence(__ATOMIC_ACQUIRE) # define os_wmb __atomic_thread_fence(__ATOMIC_RELEASE) -#ifdef __powerpc__ -# define os_isync __asm __volatile ("isync":::"memory") -#else -#define os_isync do { } while(0) -#endif +# define os_mb __atomic_thread_fence(__ATOMIC_SEQ_CST) # define IB_MEMORY_BARRIER_STARTUP_MSG \ "GCC builtin __atomic_thread_fence() is used for memory barrier" @@ -726,7 +758,7 @@ architecture. Disable memory barrier for Intel architecture for now. */ # define HAVE_MEMORY_BARRIER # define os_rmb __sync_synchronize() # define os_wmb __sync_synchronize() -# define os_isync __sync_synchronize() +# define os_mb __sync_synchronize() # define IB_MEMORY_BARRIER_STARTUP_MSG \ "GCC builtin __sync_synchronize() is used for memory barrier" @@ -735,7 +767,7 @@ architecture. Disable memory barrier for Intel architecture for now. */ # include <mbarrier.h> # define os_rmb __machine_r_barrier() # define os_wmb __machine_w_barrier() -# define os_isync os_rmb; os_wmb +# define os_mb __machine_rw_barrier() # define IB_MEMORY_BARRIER_STARTUP_MSG \ "Solaris memory ordering functions are used for memory barrier" @@ -744,17 +776,14 @@ architecture. Disable memory barrier for Intel architecture for now. */ # include <intrin.h> # define os_rmb _mm_lfence() # define os_wmb _mm_sfence() -# define os_isync os_rmb; os_wmb +# define os_mb _mm_mfence() # define IB_MEMORY_BARRIER_STARTUP_MSG \ "_mm_lfence() and _mm_sfence() are used for memory barrier" -# define os_atomic_lock_release_byte(ptr) \ - (void) InterlockedExchange(ptr, 0) - #else # define os_rmb do { } while(0) # define os_wmb do { } while(0) -# define os_isync do { } while(0) +# define os_mb do { } while(0) # define IB_MEMORY_BARRIER_STARTUP_MSG \ "Memory barrier is not used" #endif diff --git a/storage/innobase/include/os0sync.ic b/storage/innobase/include/os0sync.ic index 9a7e520ece6..4ebf84dba98 100644 --- a/storage/innobase/include/os0sync.ic +++ b/storage/innobase/include/os0sync.ic @@ -232,3 +232,35 @@ win_cmp_and_xchg_dword( #endif /* HAVE_WINDOWS_ATOMICS */ + +/**********************************************************//** +Acquires ownership of a fast mutex. Implies a full memory barrier even on +platforms such as PowerPC where this is not normally required. +@return 0 if success, != 0 if was reserved by another thread */ +UNIV_INLINE +ulint +os_fast_mutex_trylock_full_barrier( +/*==================*/ + os_fast_mutex_t* fast_mutex) /*!< in: mutex to acquire */ +{ +#ifdef __WIN__ + if (TryEnterCriticalSection(&fast_mutex->mutex)) { + + return(0); + } else { + + return(1); + } +#else + /* NOTE that the MySQL my_pthread.h redefines pthread_mutex_trylock + so that it returns 0 on success. In the operating system + libraries, HP-UX-10.20 follows the old Posix 1003.4a Draft 4 and + returns 1 on success (but MySQL remaps that to 0), while Linux, + FreeBSD, Solaris, AIX, Tru64 Unix, HP-UX-11.0 return 0 on success. */ + +#ifdef __powerpc__ + os_mb; +#endif + return((ulint) pthread_mutex_trylock(&fast_mutex->mutex)); +#endif +} diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 3cff5a41b8e..440001410f0 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -879,6 +879,14 @@ struct row_prebuilt_t { unsigned innodb_api:1; /*!< whether this is a InnoDB API query */ const rec_t* innodb_api_rec; /*!< InnoDB API search result */ + byte* srch_key_val1; /*!< buffer used in converting + search key values from MySQL format + to InnoDB format.*/ + byte* srch_key_val2; /*!< buffer used in converting + search key values from MySQL format + to InnoDB format.*/ + uint srch_key_val_len; /*!< Size of search key */ + }; /** Callback for row_mysql_sys_index_iterate() */ diff --git a/storage/innobase/include/srv0mon.h b/storage/innobase/include/srv0mon.h index beac1605345..0a47d514e1b 100644 --- a/storage/innobase/include/srv0mon.h +++ b/storage/innobase/include/srv0mon.h @@ -391,6 +391,10 @@ enum monitor_id_t { MONITOR_OLVD_ROW_INSERTED, MONITOR_OLVD_ROW_DELETED, MONITOR_OLVD_ROW_UPDTATED, + MONITOR_OLVD_SYSTEM_ROW_READ, + MONITOR_OLVD_SYSTEM_ROW_INSERTED, + MONITOR_OLVD_SYSTEM_ROW_DELETED, + MONITOR_OLVD_SYSTEM_ROW_UPDATED, /* Data DDL related counters */ MONITOR_MODULE_DDL_STATS, diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index e87750b7540..52f2f22b372 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -158,6 +158,18 @@ struct srv_stats_t { /** Number of rows inserted */ ulint_ctr_64_t n_rows_inserted; + /** Number of system rows read. */ + ulint_ctr_64_t n_system_rows_read; + + /** Number of system rows updated */ + ulint_ctr_64_t n_system_rows_updated; + + /** Number of system rows deleted */ + ulint_ctr_64_t n_system_rows_deleted; + + /** Number of system rows inserted */ + ulint_ctr_64_t n_system_rows_inserted; + /** Number of times secondary index lookup triggered cluster lookup */ ulint_ctr_64_t n_sec_rec_cluster_reads; @@ -401,10 +413,10 @@ extern ulint srv_win_file_flush_method; extern ulint srv_max_n_open_files; -extern ulong srv_max_dirty_pages_pct; -extern ulong srv_max_dirty_pages_pct_lwm; +extern double srv_max_dirty_pages_pct; +extern double srv_max_dirty_pages_pct_lwm; -extern ulong srv_adaptive_flushing_lwm; +extern double srv_adaptive_flushing_lwm; extern ulong srv_flushing_avg_loops; extern ulong srv_force_recovery; @@ -425,6 +437,8 @@ extern unsigned long long srv_stats_transient_sample_pages; extern my_bool srv_stats_persistent; extern unsigned long long srv_stats_persistent_sample_pages; extern my_bool srv_stats_auto_recalc; +extern unsigned long long srv_stats_modified_counter; +extern my_bool srv_stats_sample_traditional; extern ibool srv_use_doublewrite_buf; extern ulong srv_doublewrite_batch_size; @@ -432,7 +446,7 @@ extern ulong srv_checksum_algorithm; extern my_bool srv_force_primary_key; -extern ulong srv_max_buf_pool_modified_pct; +extern double srv_max_buf_pool_modified_pct; extern ulong srv_max_purge_lag; extern ulong srv_max_purge_lag_delay; @@ -928,6 +942,10 @@ struct export_var_t{ ulint innodb_rows_inserted; /*!< srv_n_rows_inserted */ ulint innodb_rows_updated; /*!< srv_n_rows_updated */ ulint innodb_rows_deleted; /*!< srv_n_rows_deleted */ + ulint innodb_system_rows_read; /*!< srv_n_system_rows_read */ + ulint innodb_system_rows_inserted; /*!< srv_n_system_rows_inserted */ + ulint innodb_system_rows_updated; /*!< srv_n_system_rows_updated */ + ulint innodb_system_rows_deleted; /*!< srv_n_system_rows_deleted*/ ulint innodb_num_open_files; /*!< fil_n_file_opened */ ulint innodb_truncated_status_writes; /*!< srv_truncated_status_writes */ ulint innodb_available_undo_logs; /*!< srv_available_undo_logs diff --git a/storage/innobase/include/sync0arr.h b/storage/innobase/include/sync0arr.h index 15dbdcb540d..0e735192024 100644 --- a/storage/innobase/include/sync0arr.h +++ b/storage/innobase/include/sync0arr.h @@ -148,6 +148,12 @@ sync_array_t* sync_array_get(void); /*================*/ +/**********************************************************************//** +Prints info of the wait array without using any mutexes/semaphores. */ +UNIV_INTERN +void +sync_array_print_innodb(void); + #ifndef UNIV_NONINL #include "sync0arr.ic" #endif diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index b1d99f7244c..f26e66f1a87 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -49,8 +49,6 @@ extern "C" my_bool timed_mutexes; #ifdef HAVE_WINDOWS_ATOMICS typedef LONG lock_word_t; /*!< On Windows, InterlockedExchange operates on LONG variable */ -#elif defined(HAVE_ATOMIC_BUILTINS) && !defined(HAVE_ATOMIC_BUILTINS_BYTE) -typedef ulint lock_word_t; #else typedef byte lock_word_t; #endif diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic index f9017230497..a5887b1fd6f 100644 --- a/storage/innobase/include/sync0sync.ic +++ b/storage/innobase/include/sync0sync.ic @@ -80,15 +80,11 @@ ib_mutex_test_and_set( ib_mutex_t* mutex) /*!< in: mutex */ { #if defined(HAVE_ATOMIC_BUILTINS) -# if defined(HAVE_ATOMIC_BUILTINS_BYTE) - return(os_atomic_test_and_set_byte(&mutex->lock_word, 1)); -# else - return(os_atomic_test_and_set_ulint(&mutex->lock_word, 1)); -# endif + return(os_atomic_test_and_set_byte_acquire(&mutex->lock_word, 1)); #else ibool ret; - ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex)); + ret = os_fast_mutex_trylock_full_barrier(&(mutex->os_fast_mutex)); if (ret == 0) { /* We check that os_fast_mutex_trylock does not leak @@ -96,7 +92,6 @@ ib_mutex_test_and_set( ut_a(mutex->lock_word == 0); mutex->lock_word = 1; - os_wmb; } return((byte) ret); @@ -113,11 +108,14 @@ mutex_reset_lock_word( ib_mutex_t* mutex) /*!< in: mutex */ { #if defined(HAVE_ATOMIC_BUILTINS) - os_atomic_lock_release_byte(&mutex->lock_word); + /* In theory __sync_lock_release should be used to release the lock. + Unfortunately, it does not work properly alone. The workaround is + that more conservative __sync_lock_test_and_set is used instead. */ + os_atomic_test_and_set_byte_release(&mutex->lock_word, 0); #else mutex->lock_word = 0; - os_fast_mutex_unlock(&(mutex->os_fast_mutex)); + os_fast_mutex_unlock_full_barrier(&(mutex->os_fast_mutex)); #endif } @@ -149,7 +147,6 @@ mutex_get_waiters( ptr = &(mutex->waiters); - os_rmb; return(*ptr); /* Here we assume that the read of a single word from memory is atomic */ } @@ -184,7 +181,6 @@ mutex_exit_func( to wake up possible hanging threads if they are missed in mutex_signal_object. */ - os_isync; if (mutex_get_waiters(mutex) != 0) { mutex_signal_object(mutex); diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index 61b0dabb1e6..660551961a6 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -243,22 +243,13 @@ Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end_func( +trx_undo_truncate_end( /*=======================*/ -#ifdef UNIV_DEBUG - const trx_t* trx, /*!< in: transaction whose undo log it is */ -#endif /* UNIV_DEBUG */ + trx_t* trx, /*!< in: transaction whose undo log it is */ trx_undo_t* undo, /*!< in/out: undo log */ undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ __attribute__((nonnull)); -#ifdef UNIV_DEBUG -# define trx_undo_truncate_end(trx,undo,limit) \ - trx_undo_truncate_end_func(trx,undo,limit) -#else /* UNIV_DEBUG */ -# define trx_undo_truncate_end(trx,undo,limit) \ - trx_undo_truncate_end_func(undo,limit) -#endif /* UNIV_DEBUG */ /***********************************************************************//** Truncates an undo log from the start. This function is used during a purge diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 685d89dc854..a4c401134f9 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -45,7 +45,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 20 +#define INNODB_VERSION_BUGFIX 21 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; diff --git a/storage/innobase/include/ut0counter.h b/storage/innobase/include/ut0counter.h index fe0f36dfff2..63a133a175d 100644 --- a/storage/innobase/include/ut0counter.h +++ b/storage/innobase/include/ut0counter.h @@ -32,7 +32,11 @@ Created 2012/04/12 by Sunny Bains #include "os0thread.h" /** CPU cache line size */ +#ifdef __powerpc__ +#define CACHE_LINE_SIZE 128 +#else #define CACHE_LINE_SIZE 64 +#endif /** Default number of slots to use in ib_counter_t */ #define IB_N_SLOTS 64 diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 8dbe1668e36..42719fcc3cd 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -6504,6 +6504,7 @@ lock_rec_insert_check_and_lock( lock_t* lock; dberr_t err; ulint next_rec_heap_no; + ibool inherit_in = *inherit; #ifdef WITH_WSREP lock_t* c_lock=NULL; #endif @@ -6539,7 +6540,7 @@ lock_rec_insert_check_and_lock( lock_mutex_exit(); - if (!dict_index_is_clust(index)) { + if (inherit_in && !dict_index_is_clust(index)) { /* Update the page max trx id field */ page_update_max_trx_id(block, buf_block_get_page_zip(block), @@ -6600,7 +6601,7 @@ lock_rec_insert_check_and_lock( err = DB_SUCCESS; /* fall through */ case DB_SUCCESS: - if (dict_index_is_clust(index)) { + if (!inherit_in || dict_index_is_clust(index)) { break; } /* Update the page max trx id field */ diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc index a1c35e20ead..4f4a0eb223b 100644 --- a/storage/innobase/lock/lock0wait.cc +++ b/storage/innobase/lock/lock0wait.cc @@ -259,10 +259,6 @@ lock_wait_suspend_thread( } } - /* Wake the lock timeout monitor thread, if it is suspended */ - - os_event_set(lock_sys->timeout_event); - lock_wait_mutex_exit(); trx_mutex_exit(trx); diff --git a/storage/innobase/mysql-test/storage_engine/disabled.def b/storage/innobase/mysql-test/storage_engine/disabled.def index 2f3793047f4..bad10099bbf 100644 --- a/storage/innobase/mysql-test/storage_engine/disabled.def +++ b/storage/innobase/mysql-test/storage_engine/disabled.def @@ -1,4 +1,3 @@ -autoinc_vars : MySQL:65225 (InnoDB miscalculates auto-increment) tbl_opt_ai : MySQL:65901 (AUTO_INCREMENT option on InnoDB table is ignored if added before autoinc column) delete_low_prio : InnoDB does not use table-level locking insert_high_prio : InnoDB does not use table-level locking diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 3ea3df0227c..89c8bf373f7 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -616,6 +616,8 @@ os_file_get_last_error_low( return(OS_FILE_OPERATION_ABORTED); } else if (err == ERROR_ACCESS_DENIED) { return(OS_FILE_ACCESS_VIOLATION); + } else if (err == ERROR_BUFFER_OVERFLOW) { + return(OS_FILE_NAME_TOO_LONG); } else { return(OS_FILE_ERROR_MAX + err); } @@ -690,6 +692,8 @@ os_file_get_last_error_low( return(OS_FILE_NOT_FOUND); case EEXIST: return(OS_FILE_ALREADY_EXISTS); + case ENAMETOOLONG: + return(OS_FILE_NAME_TOO_LONG); case EXDEV: case ENOTDIR: case EISDIR: @@ -3354,7 +3358,7 @@ os_file_status( struct _stat64 statinfo; ret = _stat64(path, &statinfo); - if (ret && (errno == ENOENT || errno == ENOTDIR)) { + if (ret && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG)) { /* file does not exist */ *exists = FALSE; return(TRUE); @@ -3382,7 +3386,7 @@ os_file_status( struct stat statinfo; ret = stat(path, &statinfo); - if (ret && (errno == ENOENT || errno == ENOTDIR)) { + if (ret && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG)) { /* file does not exist */ *exists = FALSE; return(TRUE); diff --git a/storage/innobase/os/os0sync.cc b/storage/innobase/os/os0sync.cc index 779152a3a56..451ba5285e3 100644 --- a/storage/innobase/os/os0sync.cc +++ b/storage/innobase/os/os0sync.cc @@ -890,6 +890,25 @@ os_fast_mutex_unlock_func( } /**********************************************************//** +Releases ownership of a fast mutex. Implies a full memory barrier even on +platforms such as PowerPC where this is not normally required. */ +UNIV_INTERN +void +os_fast_mutex_unlock_full_barrier( +/*=================*/ + os_fast_mutex_t* fast_mutex) /*!< in: mutex to release */ +{ +#ifdef __WIN__ + LeaveCriticalSection(&fast_mutex->mutex); +#else + pthread_mutex_unlock(&fast_mutex->mutex); +#ifdef __powerpc__ + os_mb; +#endif +#endif +} + +/**********************************************************//** Frees a mutex object. */ UNIV_INTERN void diff --git a/storage/innobase/row/row0ext.cc b/storage/innobase/row/row0ext.cc index 32b78391d6a..ad852577ad2 100644 --- a/storage/innobase/row/row0ext.cc +++ b/storage/innobase/row/row0ext.cc @@ -78,7 +78,8 @@ row_ext_cache_fill( crashed during the execution of btr_free_externally_stored_field(). */ ext->len[i] = btr_copy_externally_stored_field_prefix( - buf, ext->max_len, zip_size, field, f_len); + buf, ext->max_len, zip_size, field, f_len, + NULL); } } } diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index c0c3452e241..eb032246416 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -660,7 +660,8 @@ loop: doc.text.f_str = btr_copy_externally_stored_field( &doc.text.f_len, data, - zip_size, data_len, blob_heap); + zip_size, data_len, blob_heap, + NULL); } else { doc.text.f_str = data; doc.text.f_len = data_len; diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index c45d6554627..44c9ac32d16 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1314,7 +1314,7 @@ row_ins_foreign_check_on_constraint( row_mysql_freeze_data_dictionary(thr_get_trx(thr)); - mtr_start(mtr); + mtr_start_trx(mtr, trx); /* Restore pcur position */ @@ -1342,7 +1342,7 @@ nonstandard_exit_func: btr_pcur_store_position(pcur, mtr); mtr_commit(mtr); - mtr_start(mtr); + mtr_start_trx(mtr, trx); btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr); @@ -1550,7 +1550,7 @@ run_again: } } - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); /* Store old value on n_fields_cmp */ @@ -1973,7 +1973,7 @@ row_ins_scan_sec_index_for_duplicate( do { const rec_t* rec = btr_pcur_get_rec(&pcur); const buf_block_t* block = btr_pcur_get_block(&pcur); - ulint lock_type; + const ulint lock_type = LOCK_ORDINARY; if (page_rec_is_infimum(rec)) { @@ -1983,16 +1983,6 @@ row_ins_scan_sec_index_for_duplicate( offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &offsets_heap); - /* If the transaction isolation level is no stronger than - READ COMMITTED, then avoid gap locks. */ - if (!page_rec_is_supremum(rec) - && thr_get_trx(thr)->isolation_level - <= TRX_ISO_READ_COMMITTED) { - lock_type = LOCK_REC_NOT_GAP; - } else { - lock_type = LOCK_ORDINARY; - } - if (flags & BTR_NO_LOCKING_FLAG) { /* Set no locks when applying log in online table rebuild. */ @@ -2358,7 +2348,7 @@ row_ins_clust_index_entry_low( || n_uniq == dict_index_get_n_unique(index)); ut_ad(!n_uniq || n_uniq == dict_index_get_n_unique(index)); - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); if (mode == BTR_MODIFY_LEAF && dict_index_is_online_ddl(index)) { mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED; @@ -2571,9 +2561,10 @@ Starts a mini-transaction and checks if the index will be dropped. @return true if the index is to be dropped */ static __attribute__((nonnull, warn_unused_result)) bool -row_ins_sec_mtr_start_and_check_if_aborted( +row_ins_sec_mtr_start_trx_and_check_if_aborted( /*=======================================*/ mtr_t* mtr, /*!< out: mini-transaction */ + trx_t* trx, /*!< in: transaction handle */ dict_index_t* index, /*!< in/out: secondary index */ bool check, /*!< in: whether to check */ ulint search_mode) @@ -2581,7 +2572,7 @@ row_ins_sec_mtr_start_and_check_if_aborted( { ut_ad(!dict_index_is_clust(index)); - mtr_start(mtr); + mtr_start_trx(mtr, trx); if (!check) { return(false); @@ -2639,13 +2630,14 @@ row_ins_sec_index_entry_low( ulint n_unique; mtr_t mtr; ulint* offsets = NULL; + trx_t* trx = thr_get_trx(thr); ut_ad(!dict_index_is_clust(index)); ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE); cursor.thr = thr; ut_ad(thr_get_trx(thr)->id); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); /* Ensure that we acquire index->lock when inserting into an index with index->online_status == ONLINE_INDEX_COMPLETE, but @@ -2706,8 +2698,8 @@ row_ins_sec_index_entry_low( DEBUG_SYNC_C("row_ins_sec_index_unique"); - if (row_ins_sec_mtr_start_and_check_if_aborted( - &mtr, index, check, search_mode)) { + if (row_ins_sec_mtr_start_trx_and_check_if_aborted( + &mtr, trx, index, check, search_mode)) { goto func_exit; } @@ -2741,8 +2733,8 @@ row_ins_sec_index_entry_low( return(err); } - if (row_ins_sec_mtr_start_and_check_if_aborted( - &mtr, index, check, search_mode)) { + if (row_ins_sec_mtr_start_trx_and_check_if_aborted( + &mtr, trx, index, check, search_mode)) { goto func_exit; } diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index b01b481c501..caed087b439 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -988,7 +988,7 @@ row_log_table_get_pk_col( mem_heap_alloc(heap, field_len)); len = btr_copy_externally_stored_field_prefix( - blob_field, field_len, zip_size, field, len); + blob_field, field_len, zip_size, field, len, NULL); if (len >= max_len + 1) { return(DB_TOO_BIG_INDEX_COL); } @@ -1379,7 +1379,7 @@ row_log_table_apply_convert_mrec( data = btr_rec_copy_externally_stored_field( mrec, offsets, dict_table_zip_size(index->table), - i, &len, heap); + i, &len, heap, NULL); ut_a(data); dfield_set_data(dfield, data, len); blob_done: diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 8cd9463fcef..c79bd6c62ec 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -23,6 +23,7 @@ New index creation routines using a merge sort Created 12/4/2005 Jan Lindstrom Completed by Sunny Bains and Marko Makela *******************************************************/ +#include <my_config.h> #include <log.h> #include "row0merge.h" @@ -2320,7 +2321,7 @@ row_merge_copy_blobs( BLOB pointers are read (row_merge_read_clustered_index()) and dereferenced (below). */ data = btr_rec_copy_externally_stored_field( - mrec, offsets, zip_size, i, &len, heap); + mrec, offsets, zip_size, i, &len, heap, NULL); /* Because we have locked the table, any records written by incomplete transactions must have been rolled back already. There must not be any incomplete diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index c5f4680f4ff..86248b87c66 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -33,6 +33,7 @@ Created 9/17/2000 Heikki Tuuri #include <debug_sync.h> #include <my_dbug.h> +#include <sql_const.h> #include "row0ins.h" #include "row0merge.h" #include "row0sel.h" @@ -712,8 +713,10 @@ row_create_prebuilt( row_prebuilt_t* prebuilt; mem_heap_t* heap; dict_index_t* clust_index; + dict_index_t* temp_index; dtuple_t* ref; ulint ref_len; + uint srch_key_len = 0; ulint search_tuple_n_fields; search_tuple_n_fields = 2 * dict_table_get_n_cols(table); @@ -725,6 +728,14 @@ row_create_prebuilt( ref_len = dict_index_get_n_unique(clust_index); + + /* Maximum size of the buffer needed for conversion of INTs from + little endian format to big endian format in an index. An index + can have maximum 16 columns (MAX_REF_PARTS) in it. Therfore + Max size for PK: 16 * 8 bytes (BIGINT's size) = 128 bytes + Max size Secondary index: 16 * 8 bytes + PK = 256 bytes. */ +#define MAX_SRCH_KEY_VAL_BUFFER 2* (8 * MAX_REF_PARTS) + #define PREBUILT_HEAP_INITIAL_SIZE \ ( \ sizeof(*prebuilt) \ @@ -753,10 +764,38 @@ row_create_prebuilt( + sizeof(que_thr_t) \ ) + /* Calculate size of key buffer used to store search key in + InnoDB format. MySQL stores INTs in little endian format and + InnoDB stores INTs in big endian format with the sign bit + flipped. All other field types are stored/compared the same + in MySQL and InnoDB, so we must create a buffer containing + the INT key parts in InnoDB format.We need two such buffers + since both start and end keys are used in records_in_range(). */ + + for (temp_index = dict_table_get_first_index(table); temp_index; + temp_index = dict_table_get_next_index(temp_index)) { + DBUG_EXECUTE_IF("innodb_srch_key_buffer_max_value", + ut_a(temp_index->n_user_defined_cols + == MAX_REF_PARTS);); + uint temp_len = 0; + for (uint i = 0; i < temp_index->n_uniq; i++) { + if (temp_index->fields[i].col->mtype == DATA_INT) { + temp_len += + temp_index->fields[i].fixed_len; + } + } + srch_key_len = max(srch_key_len,temp_len); + } + + ut_a(srch_key_len <= MAX_SRCH_KEY_VAL_BUFFER); + + DBUG_EXECUTE_IF("innodb_srch_key_buffer_max_value", + ut_a(srch_key_len == MAX_SRCH_KEY_VAL_BUFFER);); + /* We allocate enough space for the objects that are likely to be created later in order to minimize the number of malloc() calls */ - heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE); + heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE + 2 * srch_key_len); prebuilt = static_cast<row_prebuilt_t*>( mem_heap_zalloc(heap, sizeof(*prebuilt))); @@ -769,6 +808,18 @@ row_create_prebuilt( prebuilt->sql_stat_start = TRUE; prebuilt->heap = heap; + prebuilt->srch_key_val_len = srch_key_len; + if (prebuilt->srch_key_val_len) { + prebuilt->srch_key_val1 = static_cast<byte*>( + mem_heap_alloc(prebuilt->heap, + 2 * prebuilt->srch_key_val_len)); + prebuilt->srch_key_val2 = prebuilt->srch_key_val1 + + prebuilt->srch_key_val_len; + } else { + prebuilt->srch_key_val1 = NULL; + prebuilt->srch_key_val2 = NULL; + } + btr_pcur_reset(&prebuilt->pcur); btr_pcur_reset(&prebuilt->clust_pcur); @@ -1056,8 +1107,11 @@ row_update_statistics_if_needed( since the last time a statistics batch was run. We calculate statistics at most every 16th round, since we may have a counter table which is very small and updated very often. */ + ib_uint64_t threshold= 16 + n_rows / 16; /* 6.25% */ + if (srv_stats_modified_counter) + threshold= ut_min(srv_stats_modified_counter, threshold); - if (counter > 16 + n_rows / 16 /* 6.25% */) { + if (counter > threshold) { ut_ad(!mutex_own(&dict_sys->mutex)); /* this will reset table->stat_modified_counter to 0 */ @@ -1395,7 +1449,11 @@ error_exit: que_thr_stop_for_mysql_no_error(thr, trx); - srv_stats.n_rows_inserted.add((size_t)trx->id, 1); + if (table->is_system_db) { + srv_stats.n_system_rows_inserted.add((size_t)trx->id, 1); + } else { + srv_stats.n_rows_inserted.add((size_t)trx->id, 1); + } /* Not protected by dict_table_stats_lock() for performance reasons, we would rather get garbage in stat_n_rows (which is @@ -1785,9 +1843,20 @@ run_again: with a latch. */ dict_table_n_rows_dec(prebuilt->table); - srv_stats.n_rows_deleted.add((size_t)trx->id, 1); + if (table->is_system_db) { + srv_stats.n_system_rows_deleted.add( + (size_t)trx->id, 1); + } else { + srv_stats.n_rows_deleted.add((size_t)trx->id, 1); + } + } else { - srv_stats.n_rows_updated.add((size_t)trx->id, 1); + if (table->is_system_db) { + srv_stats.n_system_rows_updated.add( + (size_t)trx->id, 1); + } else { + srv_stats.n_rows_updated.add((size_t)trx->id, 1); + } } /* We update table statistics only if it is a DELETE or UPDATE @@ -1851,7 +1920,7 @@ row_unlock_for_mysql( trx_id_t rec_trx_id; mtr_t mtr; - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); /* Restore the cursor position and find the record */ @@ -2011,9 +2080,19 @@ run_again: with a latch. */ dict_table_n_rows_dec(table); - srv_stats.n_rows_deleted.add((size_t)trx->id, 1); + if (table->is_system_db) { + srv_stats.n_system_rows_deleted.add( + (size_t)trx->id, 1); + } else { + srv_stats.n_rows_deleted.add((size_t)trx->id, 1); + } } else { - srv_stats.n_rows_updated.add((size_t)trx->id, 1); + if (table->is_system_db) { + srv_stats.n_system_rows_updated.add( + (size_t)trx->id, 1); + } else { + srv_stats.n_rows_updated.add((size_t)trx->id, 1); + } } row_update_statistics_if_needed(table); @@ -2201,23 +2280,23 @@ err_exit: /* The lock timeout monitor thread also takes care of InnoDB monitor prints */ - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); } else if (STR_EQ(table_name, table_name_len, S_innodb_lock_monitor)) { srv_print_innodb_monitor = TRUE; srv_print_innodb_lock_monitor = TRUE; - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); } else if (STR_EQ(table_name, table_name_len, S_innodb_tablespace_monitor)) { srv_print_innodb_tablespace_monitor = TRUE; - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); } else if (STR_EQ(table_name, table_name_len, S_innodb_table_monitor)) { srv_print_innodb_table_monitor = TRUE; - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); #ifdef UNIV_MEM_DEBUG } else if (STR_EQ(table_name, table_name_len, S_innodb_mem_validate)) { @@ -2840,7 +2919,7 @@ row_discard_tablespace_foreign_key_checks( /* Check if the table is referenced by foreign key constraints from some other table (not the table itself) */ - dict_foreign_set::iterator it + dict_foreign_set::const_iterator it = std::find_if(table->referenced_set.begin(), table->referenced_set.end(), dict_foreign_different_tables()); @@ -3413,7 +3492,7 @@ row_truncate_table_for_mysql( index = dict_table_get_next_index(index); } while (index); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); fsp_header_init(space, FIL_IBD_FILE_INITIAL_SIZE, &mtr); mtr_commit(&mtr); @@ -3442,7 +3521,7 @@ row_truncate_table_for_mysql( sys_index = dict_table_get_first_index(dict_sys->sys_indexes); dict_index_copy_types(tuple, sys_index, 1); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF, &pcur, &mtr); for (;;) { @@ -3489,7 +3568,7 @@ row_truncate_table_for_mysql( a page in this mini-transaction, and the rest of this loop could latch another index page. */ mtr_commit(&mtr); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr); } diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 1b836c26c25..8212a7b43e0 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -337,9 +337,24 @@ row_purge_remove_sec_if_poss_tree( if (row_purge_poss_sec(node, index, entry)) { /* Remove the index record, which should have been marked for deletion. */ - ut_ad(REC_INFO_DELETED_FLAG - & rec_get_info_bits(btr_cur_get_rec(btr_cur), - dict_table_is_comp(index->table))); + if (!rec_get_deleted_flag(btr_cur_get_rec(btr_cur), + dict_table_is_comp(index->table))) { + fputs("InnoDB: tried to purge sec index entry not" + " marked for deletion in\n" + "InnoDB: ", stderr); + dict_index_name_print(stderr, NULL, index); + fputs("\n" + "InnoDB: tuple ", stderr); + dtuple_print(stderr, entry); + fputs("\n" + "InnoDB: record ", stderr); + rec_print(stderr, btr_cur_get_rec(btr_cur), index); + putc('\n', stderr); + + ut_ad(0); + + goto func_exit; + } btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0, RB_NONE, &mtr); @@ -428,10 +443,29 @@ row_purge_remove_sec_if_poss_leaf( btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); /* Only delete-marked records should be purged. */ - ut_ad(REC_INFO_DELETED_FLAG - & rec_get_info_bits( - btr_cur_get_rec(btr_cur), - dict_table_is_comp(index->table))); + if (!rec_get_deleted_flag( + btr_cur_get_rec(btr_cur), + dict_table_is_comp(index->table))) { + + fputs("InnoDB: tried to purge sec index" + " entry not marked for deletion in\n" + "InnoDB: ", stderr); + dict_index_name_print(stderr, NULL, index); + fputs("\n" + "InnoDB: tuple ", stderr); + dtuple_print(stderr, entry); + fputs("\n" + "InnoDB: record ", stderr); + rec_print(stderr, btr_cur_get_rec(btr_cur), + index); + putc('\n', stderr); + + ut_ad(0); + + btr_pcur_close(&pcur); + + goto func_exit_no_pcur; + } if (!btr_cur_optimistic_delete(btr_cur, 0, &mtr)) { diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index d888c1ef645..b0e0c89b778 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -133,7 +133,8 @@ row_sel_sec_rec_is_for_blob( len = btr_copy_externally_stored_field_prefix(buf, prefix_len, zip_size, - clust_field, clust_len); + clust_field, clust_len, + NULL); if (UNIV_UNLIKELY(len == 0)) { /* The BLOB was being deleted as the server crashed. @@ -452,7 +453,7 @@ row_sel_fetch_columns( data = btr_rec_copy_externally_stored_field( rec, offsets, dict_table_zip_size(index->table), - field_no, &len, heap); + field_no, &len, heap, NULL); /* data == NULL means that the externally stored field was not @@ -1399,7 +1400,7 @@ table_loop: /* Open a cursor to index, or restore an open cursor position */ - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); if (consistent_read && plan->unique_search && !plan->pcur_is_open && !plan->must_get_clust @@ -1439,7 +1440,7 @@ table_loop: plan_reset_cursor(plan); mtr_commit(&mtr); - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); } if (search_latch_locked) { @@ -2451,13 +2452,12 @@ row_sel_convert_mysql_key_to_innobase( /* Storing may use at most data_len bytes of buf */ if (UNIV_LIKELY(!is_null)) { - ut_a(buf + data_len <= original_buf + buf_len); - row_mysql_store_col_in_innobase_format( - dfield, buf, - FALSE, /* MySQL key value format col */ - key_ptr + data_offset, data_len, - dict_table_is_comp(index->table)); - buf += data_len; + buf = row_mysql_store_col_in_innobase_format( + dfield, buf, + FALSE, /* MySQL key value format col */ + key_ptr + data_offset, data_len, + dict_table_is_comp(index->table)); + ut_a(buf <= original_buf + buf_len); } key_ptr += data_field_len; @@ -2501,9 +2501,6 @@ row_sel_convert_mysql_key_to_innobase( dfield++; } - DBUG_EXECUTE_IF("innodb_srch_key_buffer_full", - ut_a(buf == (original_buf + buf_len));); - ut_a(buf <= original_buf + buf_len); /* We set the length of tuple to n_fields: we assume that the memory @@ -2810,7 +2807,7 @@ row_sel_store_mysql_field_func( data = btr_rec_copy_externally_stored_field( rec, offsets, dict_table_zip_size(prebuilt->table), - field_no, &len, heap); + field_no, &len, heap, NULL); if (UNIV_UNLIKELY(!data)) { /* The externally stored field was not written @@ -3894,7 +3891,7 @@ row_search_for_mysql( } } - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); /*-------------------------------------------------------------*/ /* PHASE 2: Try fast adaptive hash index search if possible */ @@ -4024,7 +4021,7 @@ release_search_latch_if_needed: } mtr_commit(&mtr); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); } } @@ -5069,7 +5066,7 @@ next_rec: mtr_commit(&mtr); mtr_has_extra_clust_latch = FALSE; - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); if (sel_restore_position_for_mysql(&same_user_rec, BTR_SEARCH_LEAF, pcur, moves_up, &mtr)) { @@ -5134,7 +5131,7 @@ lock_table_wait: /* It was a lock wait, and it ended */ thr->lock_state = QUE_THR_LOCK_NOLOCK; - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); /* Table lock waited, go try to obtain table lock again */ diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index e513d3d6d8b..8580aa45145 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -297,7 +297,7 @@ row_undo_mod_clust( pcur = &node->pcur; index = btr_cur_get_index(btr_pcur_get_btr_cur(pcur)); - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); online = dict_index_is_online_ddl(index); if (online) { @@ -326,7 +326,7 @@ row_undo_mod_clust( /* We may have to modify tree structure: do a pessimistic descent down the index tree */ - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); err = row_undo_mod_clust_low( node, &offsets, &offsets_heap, @@ -371,7 +371,7 @@ row_undo_mod_clust( if (err == DB_SUCCESS && node->rec_type == TRX_UNDO_UPD_DEL_REC) { - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); /* It is not necessary to call row_log_table, because the record is delete-marked and would thus @@ -384,7 +384,7 @@ row_undo_mod_clust( /* We may have to modify tree structure: do a pessimistic descent down the index tree */ - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); err = row_undo_mod_remove_clust_low(node, thr, &mtr, BTR_MODIFY_TREE); @@ -431,7 +431,7 @@ row_undo_mod_del_mark_or_remove_sec_low( enum row_search_result search_result; log_free_check(); - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); if (*index->name == TEMP_INDEX_PREFIX) { /* The index->online_status may change if the @@ -487,7 +487,7 @@ row_undo_mod_del_mark_or_remove_sec_low( which cannot be purged yet, requires its existence. If some requires, we should delete mark the record. */ - mtr_start(&mtr_vers); + mtr_start_trx(&mtr_vers, thr_get_trx(thr)); success = btr_pcur_restore_position(BTR_SEARCH_LEAF, &(node->pcur), &mtr_vers); @@ -603,7 +603,7 @@ row_undo_mod_del_unmark_sec_and_undo_update( ut_ad(trx->id); log_free_check(); - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); if (*index->name == TEMP_INDEX_PREFIX) { /* The index->online_status may change if the diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 8a27f325218..0ea4865d15f 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -259,7 +259,7 @@ row_upd_check_references_constraints( DEBUG_SYNC_C("foreign_constraint_check_for_update"); - mtr_start(mtr); + mtr_start_trx(mtr, trx); if (trx->dict_operation_lock_mode == 0) { got_s_lock = TRUE; @@ -1152,7 +1152,7 @@ row_upd_ext_fetch( byte* buf = static_cast<byte*>(mem_heap_alloc(heap, *len)); *len = btr_copy_externally_stored_field_prefix( - buf, *len, zip_size, data, local_len); + buf, *len, zip_size, data, local_len, NULL); /* We should never update records containing a half-deleted BLOB. */ ut_a(*len); @@ -1856,7 +1856,7 @@ row_upd_sec_index_entry( } #endif /* UNIV_DEBUG */ - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); if (*index->name == TEMP_INDEX_PREFIX) { /* The index->online_status may change if the @@ -2391,7 +2391,7 @@ row_upd_clust_rec( /* We may have to modify the tree structure: do a pessimistic descent down the index tree */ - mtr_start(mtr); + mtr_start_trx(mtr, thr_get_trx(thr)); /* NOTE: this transaction has an s-lock or x-lock on the record and therefore other transactions cannot modify the record when we have no @@ -2603,7 +2603,7 @@ row_upd_clust_step( /* We have to restore the cursor to its position */ - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); /* If the restoration does not succeed, then the same transaction has deleted the record on which the cursor was, @@ -2657,7 +2657,7 @@ row_upd_clust_step( mtr_commit(&mtr); - mtr_start(&mtr); + mtr_start_trx(&mtr, thr_get_trx(thr)); success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, &mtr); diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index 14267eedcb8..24cf403c0af 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -1271,6 +1271,26 @@ static monitor_info_t innodb_counter_info[] = MONITOR_EXISTING | MONITOR_DEFAULT_ON), MONITOR_DEFAULT_START, MONITOR_OLVD_ROW_UPDTATED}, + {"dml_system_reads", "dml", "Number of system rows read", + static_cast<monitor_type_t>( + MONITOR_EXISTING | MONITOR_DEFAULT_ON), + MONITOR_DEFAULT_START, MONITOR_OLVD_SYSTEM_ROW_READ}, + + {"dml_system_inserts", "dml", "Number of system rows inserted", + static_cast<monitor_type_t>( + MONITOR_EXISTING | MONITOR_DEFAULT_ON), + MONITOR_DEFAULT_START, MONITOR_OLVD_SYSTEM_ROW_INSERTED}, + + {"dml_system_deletes", "dml", "Number of system rows deleted", + static_cast<monitor_type_t>( + MONITOR_EXISTING | MONITOR_DEFAULT_ON), + MONITOR_DEFAULT_START, MONITOR_OLVD_SYSTEM_ROW_DELETED}, + + {"dml_system_updates", "dml", "Number of system rows updated", + static_cast<monitor_type_t>( + MONITOR_EXISTING | MONITOR_DEFAULT_ON), + MONITOR_DEFAULT_START, MONITOR_OLVD_SYSTEM_ROW_UPDATED}, + /* ========== Counters for DDL operations ========== */ {"module_ddl", "ddl", "Statistics for DDLs", MONITOR_MODULE, @@ -1809,6 +1829,26 @@ srv_mon_process_existing_counter( value = srv_stats.n_rows_updated; break; + /* innodb_system_rows_read */ + case MONITOR_OLVD_SYSTEM_ROW_READ: + value = srv_stats.n_system_rows_read; + break; + + /* innodb_system_rows_inserted */ + case MONITOR_OLVD_SYSTEM_ROW_INSERTED: + value = srv_stats.n_system_rows_inserted; + break; + + /* innodb_system_rows_deleted */ + case MONITOR_OLVD_SYSTEM_ROW_DELETED: + value = srv_stats.n_system_rows_deleted; + break; + + /* innodb_system_rows_updated */ + case MONITOR_OLVD_SYSTEM_ROW_UPDATED: + value = srv_stats.n_system_rows_updated; + break; + /* innodb_row_lock_current_waits */ case MONITOR_OVLD_ROW_LOCK_CURRENT_WAIT: value = srv_stats.n_lock_wait_current_count; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index d56f942f661..bcbce3cd53c 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -303,12 +303,12 @@ in the buffer pool to all database pages in the buffer pool smaller than the following number. But it is not guaranteed that the value stays below that during a time of heavy update/insert activity. */ -UNIV_INTERN ulong srv_max_buf_pool_modified_pct = 75; -UNIV_INTERN ulong srv_max_dirty_pages_pct_lwm = 50; +UNIV_INTERN double srv_max_buf_pool_modified_pct = 75.0; +UNIV_INTERN double srv_max_dirty_pages_pct_lwm = 50.0; /* This is the percentage of log capacity at which adaptive flushing, if enabled, will kick in. */ -UNIV_INTERN ulong srv_adaptive_flushing_lwm = 10; +UNIV_INTERN double srv_adaptive_flushing_lwm = 10.0; /* Number of iterations over which adaptive flushing is averaged. */ UNIV_INTERN ulong srv_flushing_avg_loops = 30; @@ -371,6 +371,14 @@ UNIV_INTERN my_bool srv_stats_persistent = TRUE; UNIV_INTERN unsigned long long srv_stats_persistent_sample_pages = 20; UNIV_INTERN my_bool srv_stats_auto_recalc = TRUE; +/* The number of rows modified before we calculate new statistics (default 0 += current limits) */ +UNIV_INTERN unsigned long long srv_stats_modified_counter = 0; + +/* Enable traditional statistic calculation based on number of configured +pages default true. */ +UNIV_INTERN my_bool srv_stats_sample_traditional = TRUE; + UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE; /** doublewrite buffer is 1MB is size i.e.: it can hold 128 16K pages. @@ -403,6 +411,10 @@ static ulint srv_n_rows_inserted_old = 0; static ulint srv_n_rows_updated_old = 0; static ulint srv_n_rows_deleted_old = 0; static ulint srv_n_rows_read_old = 0; +static ulint srv_n_system_rows_inserted_old = 0; +static ulint srv_n_system_rows_updated_old = 0; +static ulint srv_n_system_rows_deleted_old = 0; +static ulint srv_n_system_rows_read_old = 0; UNIV_INTERN ulint srv_truncated_status_writes = 0; UNIV_INTERN ulint srv_available_undo_logs = 0; @@ -1050,6 +1062,8 @@ srv_init(void) trx_i_s_cache_init(trx_i_s_cache); ut_crc32_init(); + + dict_mem_init(); } /*********************************************************************//** @@ -1167,6 +1181,11 @@ srv_refresh_innodb_monitor_stats(void) srv_n_rows_deleted_old = srv_stats.n_rows_deleted; srv_n_rows_read_old = srv_stats.n_rows_read; + srv_n_system_rows_inserted_old = srv_stats.n_system_rows_inserted; + srv_n_system_rows_updated_old = srv_stats.n_system_rows_updated; + srv_n_system_rows_deleted_old = srv_stats.n_system_rows_deleted; + srv_n_system_rows_read_old = srv_stats.n_system_rows_read; + mutex_exit(&srv_innodb_monitor_mutex); } @@ -1358,11 +1377,33 @@ srv_printf_innodb_monitor( / time_elapsed, ((ulint) srv_stats.n_rows_read - srv_n_rows_read_old) / time_elapsed); - + fprintf(file, + "Number of system rows inserted " ULINTPF + ", updated " ULINTPF ", deleted " ULINTPF + ", read " ULINTPF "\n", + (ulint) srv_stats.n_system_rows_inserted, + (ulint) srv_stats.n_system_rows_updated, + (ulint) srv_stats.n_system_rows_deleted, + (ulint) srv_stats.n_system_rows_read); + fprintf(file, + "%.2f inserts/s, %.2f updates/s," + " %.2f deletes/s, %.2f reads/s\n", + ((ulint) srv_stats.n_system_rows_inserted + - srv_n_system_rows_inserted_old) / time_elapsed, + ((ulint) srv_stats.n_system_rows_updated + - srv_n_system_rows_updated_old) / time_elapsed, + ((ulint) srv_stats.n_system_rows_deleted + - srv_n_system_rows_deleted_old) / time_elapsed, + ((ulint) srv_stats.n_system_rows_read + - srv_n_system_rows_read_old) / time_elapsed); srv_n_rows_inserted_old = srv_stats.n_rows_inserted; srv_n_rows_updated_old = srv_stats.n_rows_updated; srv_n_rows_deleted_old = srv_stats.n_rows_deleted; srv_n_rows_read_old = srv_stats.n_rows_read; + srv_n_system_rows_inserted_old = srv_stats.n_system_rows_inserted; + srv_n_system_rows_updated_old = srv_stats.n_system_rows_updated; + srv_n_system_rows_deleted_old = srv_stats.n_system_rows_deleted; + srv_n_system_rows_read_old = srv_stats.n_system_rows_read; fputs("----------------------------\n" "END OF INNODB MONITOR OUTPUT\n" @@ -1517,6 +1558,17 @@ srv_export_innodb_status(void) export_vars.innodb_rows_deleted = srv_stats.n_rows_deleted; + export_vars.innodb_system_rows_read = srv_stats.n_system_rows_read; + + export_vars.innodb_system_rows_inserted = + srv_stats.n_system_rows_inserted; + + export_vars.innodb_system_rows_updated = + srv_stats.n_system_rows_updated; + + export_vars.innodb_system_rows_deleted = + srv_stats.n_system_rows_deleted; + export_vars.innodb_num_open_files = fil_n_file_opened; export_vars.innodb_truncated_status_writes = diff --git a/storage/innobase/sync/sync0arr.cc b/storage/innobase/sync/sync0arr.cc index f643e5b794f..10c201e990e 100644 --- a/storage/innobase/sync/sync0arr.cc +++ b/storage/innobase/sync/sync0arr.cc @@ -1074,7 +1074,7 @@ sync_array_print_long_waits( (ulong) os_file_n_pending_pwrites); srv_print_innodb_monitor = TRUE; - os_event_set(lock_sys->timeout_event); + os_event_set(srv_monitor_event); os_thread_sleep(30000000); @@ -1219,3 +1219,66 @@ sync_array_get(void) return(sync_wait_array[i % sync_array_size]); } + +/**********************************************************************//** +Prints info of the wait array without using any mutexes/semaphores. */ +UNIV_INTERN +void +sync_array_print_innodb(void) +/*=========================*/ +{ + ulint i; + sync_array_t* arr = sync_array_get(); + + fputs("InnoDB: Semaphore wait debug output started for InnoDB:\n", stderr); + + for (i = 0; i < arr->n_cells; i++) { + void* wait_object; + sync_cell_t* cell; + os_thread_id_t reserver=(os_thread_id_t)ULINT_UNDEFINED; + ulint loop=0; + + cell = sync_array_get_nth_cell(arr, i); + + wait_object = cell->wait_object; + + if (wait_object == NULL || !cell->waiting) { + + continue; + } + + fputs("InnoDB: Warning: semaphore wait:\n", + stderr); + sync_array_cell_print(stderr, cell, &reserver); + + /* Try to output cell information for writer recursive way */ + while (reserver != (os_thread_id_t)ULINT_UNDEFINED) { + sync_cell_t* reserver_wait; + + reserver_wait = sync_array_find_thread(arr, reserver); + + if (reserver_wait && + reserver_wait->wait_object != NULL && + reserver_wait->waiting) { + fputs("InnoDB: Warning: Writer thread is waiting this semaphore:\n", + stderr); + sync_array_cell_print(stderr, reserver_wait, &reserver); + + if (reserver_wait->thread == reserver) { + reserver = (os_thread_id_t)ULINT_UNDEFINED; + } + } else { + reserver = (os_thread_id_t)ULINT_UNDEFINED; + } + + /* This is protection against loop */ + if (loop > 100) { + fputs("InnoDB: Warning: Too many waiting threads.\n", stderr); + break; + } + } + } + + fputs("InnoDB: Semaphore wait debug output ended:\n", stderr); + +} diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 9fc21005d47..aa2b5fa29db 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -457,8 +457,6 @@ mutex_set_waiters( ptr = &(mutex->waiters); - os_wmb; - *ptr = n; /* Here we assume that the write of a single word in memory is atomic */ } @@ -553,6 +551,11 @@ spin_loop: mutex_set_waiters(mutex, 1); + /* Make sure waiters store won't pass over mutex_test_and_set */ +#ifdef __powerpc__ + os_mb; +#endif + /* Try to reserve still a few times */ for (i = 0; i < 4; i++) { if (ib_mutex_test_and_set(mutex) == 0) { diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 01ccfb8a6d0..993006efc6d 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -1639,7 +1639,7 @@ trx_i_s_create_lock_id( } else { /* table lock */ res_len = ut_snprintf(lock_id, lock_id_size, - TRX_ID_FMT":" UINT64PF, + TRX_ID_FMT ":" UINT64PF, row->lock_trx_id, row->lock_table_id); } diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 4d3458ff8bb..fa3fe0904b8 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -466,7 +466,7 @@ trx_undo_page_fetch_ext( { /* Fetch the BLOB. */ ulint ext_len = btr_copy_externally_stored_field_prefix( - ext_buf, prefix_len, zip_size, field, *len); + ext_buf, prefix_len, zip_size, field, *len, NULL); /* BLOBs should always be nonempty. */ ut_a(ext_len); /* Append the BLOB pointer to the prefix. */ @@ -1248,7 +1248,7 @@ trx_undo_report_row_operation( rseg = trx->rseg; - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); mutex_enter(&trx->undo_mutex); /* If the undo log is not assigned yet, assign one */ @@ -1337,7 +1337,7 @@ trx_undo_report_row_operation( latches, such as SYNC_FSP and SYNC_FSP_PAGE. */ mtr_commit(&mtr); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); mutex_enter(&rseg->mutex); trx_undo_free_last_page(trx, undo, &mtr); @@ -1374,7 +1374,7 @@ trx_undo_report_row_operation( /* We have to extend the undo log by one page */ ut_ad(++loop_count < 2); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); /* When we add a page to an undo log, this is analogous to a pessimistic insert in a B-tree, and we must reserve the diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index 1089607c6d1..a64367c4ba7 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -126,6 +126,9 @@ trx_rollback_to_savepoint_low( mem_heap_free(heap); + /* There might be work for utility threads.*/ + srv_active_wake_master_thread(); + MONITOR_DEC(MONITOR_TRX_ACTIVE); } @@ -143,20 +146,10 @@ trx_rollback_to_savepoint( { ut_ad(!trx_mutex_own(trx)); - /* Tell Innobase server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - trx_start_if_not_started_xa(trx); trx_rollback_to_savepoint_low(trx, savept); - /* Tell Innobase server that there might be work for - utility threads: */ - - srv_active_wake_master_thread(); - return(trx->error_state); } @@ -169,8 +162,6 @@ trx_rollback_for_mysql_low( /*=======================*/ trx_t* trx) /*!< in/out: transaction */ { - srv_active_wake_master_thread(); - trx->op_info = "rollback"; /* If we are doing the XA recovery of prepared transactions, @@ -184,8 +175,6 @@ trx_rollback_for_mysql_low( ut_a(trx->error_state == DB_SUCCESS); - srv_active_wake_master_thread(); - return(trx->error_state); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a8f1a7424fd..5410bb98190 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1308,6 +1308,12 @@ trx_commit_in_memory( } trx->commit_lsn = lsn; + + /* Tell server some activity has happened, since the trx + does changes something. Background utility threads like + master thread, purge thread or page_cleaner thread might + have some work to do. */ + srv_active_wake_master_thread(); } /* undo_no is non-zero if we're doing the final commit. */ diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 290271c6cab..edb85a89c17 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1067,11 +1067,9 @@ Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end_func( +trx_undo_truncate_end( /*=======================*/ -#ifdef UNIV_DEBUG - const trx_t* trx, /*!< in: transaction whose undo log it is */ -#endif /* UNIV_DEBUG */ + trx_t* trx, /*!< in: transaction whose undo log it is */ trx_undo_t* undo, /*!< in: undo log */ undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ @@ -1086,7 +1084,7 @@ trx_undo_truncate_end_func( ut_ad(mutex_own(&(trx->rseg->mutex))); for (;;) { - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); trunc_here = NULL; @@ -1773,7 +1771,7 @@ trx_undo_assign_undo( ut_ad(mutex_own(&(trx->undo_mutex))); - mtr_start(&mtr); + mtr_start_trx(&mtr, trx); mutex_enter(&rseg->mutex); |