summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2014-12-02 22:25:16 +0100
committerSergei Golubchik <serg@mariadb.org>2014-12-02 22:25:16 +0100
commit853077ad7e81be1ade20b4beab1b95d5766d87b1 (patch)
tree4c158691947ba7beb4577f26b160f243eabf39ef /storage/innobase
parentbf3b4a23f75de50e0f1ab4a562e5801dabc7305b (diff)
parent2b5db1d5bcd7b46b654d59a07fc119ef6a6b8651 (diff)
downloadmariadb-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')
-rw-r--r--storage/innobase/api/api0api.cc34
-rw-r--r--storage/innobase/api/api0misc.cc1
-rw-r--r--storage/innobase/btr/btr0btr.cc136
-rw-r--r--storage/innobase/btr/btr0cur.cc124
-rw-r--r--storage/innobase/btr/btr0pcur.cc2
-rw-r--r--storage/innobase/buf/buf0buf.cc14
-rw-r--r--storage/innobase/buf/buf0flu.cc9
-rw-r--r--storage/innobase/buf/buf0lru.cc4
-rw-r--r--storage/innobase/dict/dict0dict.cc16
-rw-r--r--storage/innobase/dict/dict0load.cc2
-rw-r--r--storage/innobase/dict/dict0mem.cc163
-rw-r--r--storage/innobase/fil/fil0fil.cc174
-rw-r--r--storage/innobase/fts/fts0fts.cc6
-rw-r--r--storage/innobase/fts/fts0que.cc3
-rw-r--r--storage/innobase/handler/ha_innodb.cc147
-rw-r--r--storage/innobase/handler/ha_innodb.h7
-rw-r--r--storage/innobase/handler/handler0alter.cc55
-rw-r--r--storage/innobase/include/btr0cur.h12
-rw-r--r--storage/innobase/include/buf0buf.h2
-rw-r--r--storage/innobase/include/dict0mem.h92
-rw-r--r--storage/innobase/include/dict0types.h1
-rw-r--r--storage/innobase/include/fil0fil.h179
-rw-r--r--storage/innobase/include/log0log.ic10
-rw-r--r--storage/innobase/include/mtr0mtr.h16
-rw-r--r--storage/innobase/include/mtr0mtr.ic6
-rw-r--r--storage/innobase/include/os0file.h1
-rw-r--r--storage/innobase/include/os0sync.h75
-rw-r--r--storage/innobase/include/os0sync.ic32
-rw-r--r--storage/innobase/include/row0mysql.h8
-rw-r--r--storage/innobase/include/srv0mon.h4
-rw-r--r--storage/innobase/include/srv0srv.h26
-rw-r--r--storage/innobase/include/sync0arr.h6
-rw-r--r--storage/innobase/include/sync0sync.h2
-rw-r--r--storage/innobase/include/sync0sync.ic18
-rw-r--r--storage/innobase/include/trx0undo.h13
-rw-r--r--storage/innobase/include/univ.i2
-rw-r--r--storage/innobase/include/ut0counter.h4
-rw-r--r--storage/innobase/lock/lock0lock.cc5
-rw-r--r--storage/innobase/lock/lock0wait.cc4
-rw-r--r--storage/innobase/mysql-test/storage_engine/disabled.def1
-rw-r--r--storage/innobase/os/os0file.cc8
-rw-r--r--storage/innobase/os/os0sync.cc19
-rw-r--r--storage/innobase/row/row0ext.cc3
-rw-r--r--storage/innobase/row/row0ftsort.cc3
-rw-r--r--storage/innobase/row/row0ins.cc36
-rw-r--r--storage/innobase/row/row0log.cc4
-rw-r--r--storage/innobase/row/row0merge.cc3
-rw-r--r--storage/innobase/row/row0mysql.cc111
-rw-r--r--storage/innobase/row/row0purge.cc48
-rw-r--r--storage/innobase/row/row0sel.cc35
-rw-r--r--storage/innobase/row/row0umod.cc14
-rw-r--r--storage/innobase/row/row0upd.cc12
-rw-r--r--storage/innobase/srv/srv0mon.cc40
-rw-r--r--storage/innobase/srv/srv0srv.cc60
-rw-r--r--storage/innobase/sync/sync0arr.cc65
-rw-r--r--storage/innobase/sync/sync0sync.cc7
-rw-r--r--storage/innobase/trx/trx0i_s.cc2
-rw-r--r--storage/innobase/trx/trx0rec.cc8
-rw-r--r--storage/innobase/trx/trx0roll.cc19
-rw-r--r--storage/innobase/trx/trx0trx.cc8
-rw-r--r--storage/innobase/trx/trx0undo.cc10
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);