diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-11-20 17:05:13 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-11-20 17:05:13 +0100 |
commit | 32ec8625afd2b72afd8f96fd773342c8da9f0be1 (patch) | |
tree | 9d46be3fa61a7f4d5fb8e724c308d9d9fba896a9 /storage/xtradb | |
parent | a9a6bd5256ba5f983eae633c591391f2bf4dfc80 (diff) | |
parent | b1e84da1012081a5c83f0670a9f222816578581b (diff) | |
download | mariadb-git-32ec8625afd2b72afd8f96fd773342c8da9f0be1.tar.gz |
XtraDB 5.6.21-70.0
Diffstat (limited to 'storage/xtradb')
-rw-r--r-- | storage/xtradb/api/api0api.cc | 14 | ||||
-rw-r--r-- | storage/xtradb/btr/btr0btr.cc | 136 | ||||
-rw-r--r-- | storage/xtradb/btr/btr0cur.cc | 29 | ||||
-rw-r--r-- | storage/xtradb/dict/dict0dict.cc | 16 | ||||
-rw-r--r-- | storage/xtradb/dict/dict0load.cc | 2 | ||||
-rw-r--r-- | storage/xtradb/dict/dict0mem.cc | 124 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.cc | 59 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.h | 7 | ||||
-rw-r--r-- | storage/xtradb/handler/handler0alter.cc | 44 | ||||
-rw-r--r-- | storage/xtradb/include/dict0mem.h | 80 | ||||
-rw-r--r-- | storage/xtradb/include/dict0types.h | 1 | ||||
-rw-r--r-- | storage/xtradb/include/row0mysql.h | 8 | ||||
-rw-r--r-- | storage/xtradb/include/univ.i | 4 | ||||
-rw-r--r-- | storage/xtradb/lock/lock0lock.cc | 5 | ||||
-rw-r--r-- | storage/xtradb/log/log0online.cc | 2 | ||||
-rw-r--r-- | storage/xtradb/row/row0ins.cc | 12 | ||||
-rw-r--r-- | storage/xtradb/row/row0mysql.cc | 55 | ||||
-rw-r--r-- | storage/xtradb/row/row0purge.cc | 48 | ||||
-rw-r--r-- | storage/xtradb/row/row0sel.cc | 16 | ||||
-rw-r--r-- | storage/xtradb/srv/srv0srv.cc | 2 | ||||
-rw-r--r-- | storage/xtradb/trx/trx0roll.cc | 19 | ||||
-rw-r--r-- | storage/xtradb/trx/trx0trx.cc | 8 |
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. */ |