InnoDB 5.6.21

This commit is contained in:
Sergei Golubchik 2014-11-20 16:59:22 +01:00
commit a9a6bd5256
22 changed files with 556 additions and 131 deletions

View file

@ -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);
}

View file

@ -2802,6 +2802,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
@ -2872,6 +3000,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

View file

@ -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);
}

View file

@ -4192,6 +4192,7 @@ corrupt:
" because of"
" a corrupt database page.\n",
stderr);
ut_error;
}
}

View file

@ -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());
@ -3257,6 +3265,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()) {
@ -5591,6 +5602,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);

View file

@ -2537,6 +2537,8 @@ func_exit:
}
}
ut_ad(err != DB_SUCCESS || dict_foreign_set_validate(*table));
return(table);
}

View file

@ -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 */
@ -653,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);
}

View file

@ -243,9 +243,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;
@ -2540,11 +2540,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
}
@ -3758,10 +3772,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);
}
@ -7854,7 +7864,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,
@ -10471,11 +10482,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);
@ -10557,11 +10563,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);
}
@ -10711,11 +10712,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);
@ -10831,7 +10827,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),
@ -10843,7 +10840,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),
@ -14043,11 +14041,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);
}

View file

@ -71,13 +71,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

View file

@ -3244,9 +3244,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);
}
@ -4272,7 +4269,6 @@ func_exit:
}
trx_commit_for_mysql(prebuilt->trx);
srv_active_wake_master_thread();
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
DBUG_RETURN(fail);
}
@ -4785,14 +4781,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");
@ -4827,9 +4826,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()
@ -5705,12 +5729,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:

View file

@ -49,6 +49,7 @@ Created 1/8/1996 Heikki Tuuri
#include "os0once.h"
#include <set>
#include <algorithm>
#include <iterator>
/* Forward declaration. */
struct ib_rbt_t;
@ -392,16 +393,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{
@ -718,6 +732,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
@ -787,6 +817,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

View file

@ -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

View file

@ -871,6 +871,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() */

View file

@ -44,7 +44,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;

View file

@ -6037,6 +6037,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)
@ -6069,7 +6070,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),
@ -6117,7 +6118,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 */

View file

@ -1946,7 +1946,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)) {
@ -1956,16 +1956,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. */

View file

@ -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"
@ -711,8 +712,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);
@ -724,6 +727,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) \
@ -752,10 +763,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)));
@ -768,6 +807,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);
@ -1060,7 +1111,6 @@ row_update_statistics_if_needed(
threshold= ut_min(srv_stats_modified_counter, threshold);
if (counter > threshold) {
ib_uint64_t threshold= 16 + n_rows / 16; /* 6.25% */
ut_ad(!mutex_own(&dict_sys->mutex));
/* this will reset table->stat_modified_counter to 0 */

View file

@ -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)) {

View file

@ -2451,13 +2451,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 +2500,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

View file

@ -1005,6 +1005,8 @@ srv_init(void)
trx_i_s_cache_init(trx_i_s_cache);
ut_crc32_init();
dict_mem_init();
}
/*********************************************************************//**

View file

@ -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);
}

View file

@ -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
@ -1282,6 +1282,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. */