summaryrefslogtreecommitdiff
path: root/storage/xtradb
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-11-20 17:05:13 +0100
committerSergei Golubchik <sergii@pisem.net>2014-11-20 17:05:13 +0100
commit32ec8625afd2b72afd8f96fd773342c8da9f0be1 (patch)
tree9d46be3fa61a7f4d5fb8e724c308d9d9fba896a9 /storage/xtradb
parenta9a6bd5256ba5f983eae633c591391f2bf4dfc80 (diff)
parentb1e84da1012081a5c83f0670a9f222816578581b (diff)
downloadmariadb-git-32ec8625afd2b72afd8f96fd773342c8da9f0be1.tar.gz
XtraDB 5.6.21-70.0
Diffstat (limited to 'storage/xtradb')
-rw-r--r--storage/xtradb/api/api0api.cc14
-rw-r--r--storage/xtradb/btr/btr0btr.cc136
-rw-r--r--storage/xtradb/btr/btr0cur.cc29
-rw-r--r--storage/xtradb/dict/dict0dict.cc16
-rw-r--r--storage/xtradb/dict/dict0load.cc2
-rw-r--r--storage/xtradb/dict/dict0mem.cc124
-rw-r--r--storage/xtradb/handler/ha_innodb.cc59
-rw-r--r--storage/xtradb/handler/ha_innodb.h7
-rw-r--r--storage/xtradb/handler/handler0alter.cc44
-rw-r--r--storage/xtradb/include/dict0mem.h80
-rw-r--r--storage/xtradb/include/dict0types.h1
-rw-r--r--storage/xtradb/include/row0mysql.h8
-rw-r--r--storage/xtradb/include/univ.i4
-rw-r--r--storage/xtradb/lock/lock0lock.cc5
-rw-r--r--storage/xtradb/log/log0online.cc2
-rw-r--r--storage/xtradb/row/row0ins.cc12
-rw-r--r--storage/xtradb/row/row0mysql.cc55
-rw-r--r--storage/xtradb/row/row0purge.cc48
-rw-r--r--storage/xtradb/row/row0sel.cc16
-rw-r--r--storage/xtradb/srv/srv0srv.cc2
-rw-r--r--storage/xtradb/trx/trx0roll.cc19
-rw-r--r--storage/xtradb/trx/trx0trx.cc8
22 files changed, 558 insertions, 133 deletions
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc
index 4788b78ebd7..3859fb84b81 100644
--- a/storage/xtradb/api/api0api.cc
+++ b/storage/xtradb/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
@@ -707,8 +707,6 @@ ib_trx_rollback(
/* It should always succeed */
ut_a(err == DB_SUCCESS);
- ib_wake_master_thread();
-
return(err);
}
@@ -1658,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);
}
@@ -1952,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);
}
@@ -2094,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/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc
index cce91bdab6e..d240188e772 100644
--- a/storage/xtradb/btr/btr0btr.cc
+++ b/storage/xtradb/btr/btr0btr.cc
@@ -2844,6 +2844,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
@@ -2914,6 +3042,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/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index 99493300382..64f813f282d 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -1347,7 +1347,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;
@@ -1638,7 +1638,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;
@@ -1660,7 +1660,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) {
@@ -1733,10 +1733,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);
}
diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index 5ac932e98a3..56861bd6541 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -1698,6 +1698,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;
@@ -1849,6 +1853,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());
@@ -3261,6 +3269,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()) {
@@ -5595,6 +5606,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/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc
index 013a5fb7b37..874614bfb5c 100644
--- a/storage/xtradb/dict/dict0load.cc
+++ b/storage/xtradb/dict/dict0load.cc
@@ -2539,6 +2539,8 @@ func_exit:
}
}
+ ut_ad(err != DB_SUCCESS || dict_foreign_set_validate(*table));
+
return(table);
}
diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc
index 164d2e36e71..997e630dd15 100644
--- a/storage/xtradb/dict/dict0mem.cc
+++ b/storage/xtradb/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 */
@@ -61,6 +63,10 @@ static const char* innobase_system_databases[] = {
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 */
@@ -669,26 +675,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;
+
+#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 */
- char* name = static_cast<char*>(mem_heap_alloc(heap, size));
+ 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/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index ba3b2506dd0..01c9e4ecdb7 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -295,9 +295,9 @@ static TYPELIB innodb_empty_free_list_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;
@@ -2910,11 +2910,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
}
@@ -4331,10 +4345,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);
}
@@ -8470,7 +8480,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,
@@ -11123,11 +11134,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);
@@ -11216,11 +11222,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);
}
@@ -11375,11 +11376,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);
@@ -11495,7 +11491,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),
@@ -11507,7 +11504,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),
@@ -14756,11 +14754,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();
-
if (thd_sql_command(thd) != SQLCOM_XA_PREPARE
&& (prepare_trx
|| !thd_test_options(
diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h
index dab9c5be53d..823d136d54b 100644
--- a/storage/xtradb/handler/ha_innodb.h
+++ b/storage/xtradb/handler/ha_innodb.h
@@ -72,13 +72,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/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index adb8ad445a6..04caa304f4d 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -3256,9 +3256,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);
}
@@ -4288,7 +4285,6 @@ func_exit:
}
trx_commit_for_mysql(prebuilt->trx);
- srv_active_wake_master_thread();
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
DBUG_RETURN(fail);
}
@@ -4801,14 +4797,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");
@@ -4843,9 +4842,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()
@@ -5723,12 +5747,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/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index f45f664e0c3..d3a713804f0 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -52,6 +52,7 @@ Created 1/8/1996 Heikki Tuuri
#include "os0once.h"
#include <set>
#include <algorithm>
+#include <iterator>
/* Forward declaration. */
struct ib_rbt_t;
@@ -402,16 +403,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{
@@ -732,6 +746,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
@@ -801,6 +831,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
diff --git a/storage/xtradb/include/dict0types.h b/storage/xtradb/include/dict0types.h
index 1299445a8ee..d34b6f7eab3 100644
--- a/storage/xtradb/include/dict0types.h
+++ b/storage/xtradb/include/dict0types.h
@@ -78,6 +78,7 @@ enum ib_quiesce_t {
/** 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/xtradb/include/row0mysql.h b/storage/xtradb/include/row0mysql.h
index cd37a2f69bb..027d76317c4 100644
--- a/storage/xtradb/include/row0mysql.h
+++ b/storage/xtradb/include/row0mysql.h
@@ -872,6 +872,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/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index 8511f87ef87..dc677e4c50c 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -44,10 +44,10 @@ 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
#ifndef PERCONA_INNODB_VERSION
-#define PERCONA_INNODB_VERSION 68.0
+#define PERCONA_INNODB_VERSION 70.0
#endif
/* Enable UNIV_LOG_ARCHIVE in XtraDB */
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index c5938509c22..c9cb0875b68 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -6084,6 +6084,7 @@ lock_rec_insert_check_and_lock(
lock_t* lock;
dberr_t err;
ulint next_rec_heap_no;
+ ibool inherit_in = *inherit;
ut_ad(block->frame == page_align(rec));
ut_ad(!dict_index_is_online_ddl(index)
@@ -6121,7 +6122,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),
@@ -6169,7 +6170,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/xtradb/log/log0online.cc b/storage/xtradb/log/log0online.cc
index 189723a8006..0b9b9aa3205 100644
--- a/storage/xtradb/log/log0online.cc
+++ b/storage/xtradb/log/log0online.cc
@@ -1800,7 +1800,7 @@ log_online_purge_changed_page_bitmaps(
return TRUE;
}
- if (srv_track_changed_pages && lsn >= log_bmp_sys->end_lsn) {
+ if (srv_track_changed_pages && lsn > log_bmp_sys->end_lsn) {
/* If we have to delete the current output file, close it
first. */
os_file_close(log_bmp_sys->out.file);
diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc
index d01f1080e5a..c0ea0304606 100644
--- a/storage/xtradb/row/row0ins.cc
+++ b/storage/xtradb/row/row0ins.cc
@@ -1958,7 +1958,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)) {
@@ -1968,16 +1968,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. */
diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc
index 035c506151d..fc3ec1ff6c3 100644
--- a/storage/xtradb/row/row0mysql.cc
+++ b/storage/xtradb/row/row0mysql.cc
@@ -31,6 +31,8 @@ Created 9/17/2000 Heikki Tuuri
#endif
#include "ha_prototypes.h"
+
+#include <sql_const.h>
#include "row0ins.h"
#include "row0merge.h"
#include "row0sel.h"
@@ -61,7 +63,6 @@ Created 9/17/2000 Heikki Tuuri
#include "row0import.h"
#include "m_string.h"
#include "my_sys.h"
-#include "ha_prototypes.h"
#include <algorithm>
/** Provide optional 4.x backwards compatibility for 5.0 and above */
@@ -710,8 +711,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);
@@ -723,6 +726,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) \
@@ -751,10 +762,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)));
@@ -767,6 +806,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);
diff --git a/storage/xtradb/row/row0purge.cc b/storage/xtradb/row/row0purge.cc
index 1b836c26c25..8212a7b43e0 100644
--- a/storage/xtradb/row/row0purge.cc
+++ b/storage/xtradb/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/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index 75adc341d2e..6c7796e3ee6 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -2454,13 +2454,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;
@@ -2504,9 +2503,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
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index b004810d0ad..a3ec19b223b 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -1157,6 +1157,8 @@ srv_init(void)
trx_i_s_cache_init(trx_i_s_cache);
ut_crc32_init();
+
+ dict_mem_init();
}
/*********************************************************************//**
diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc
index 1089607c6d1..a64367c4ba7 100644
--- a/storage/xtradb/trx/trx0roll.cc
+++ b/storage/xtradb/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/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index d4d4c421070..5ea63295792 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/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
@@ -1497,6 +1497,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. */