diff --git a/mysql-test/r/flush-innodb.result b/mysql-test/r/flush-innodb.result index 6a97d33225e..d596ffbbd51 100644 --- a/mysql-test/r/flush-innodb.result +++ b/mysql-test/r/flush-innodb.result @@ -1,7 +1,7 @@ FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT; UNLOCK TABLES; CREATE TABLE t1 ( m MEDIUMTEXT ) ENGINE=InnoDB; -INSERT INTO t1 VALUES ( REPEAT('i',1048576) ); +INSERT INTO t1 VALUES ( REPEAT('i',65535) ); DROP TABLE t1; # diff --git a/mysql-test/suite/innodb/r/innodb_bug34300.result b/mysql-test/suite/innodb/r/innodb_bug34300.result index ae9fee81ad7..bf07febca73 100644 --- a/mysql-test/suite/innodb/r/innodb_bug34300.result +++ b/mysql-test/suite/innodb/r/innodb_bug34300.result @@ -1,4 +1,3 @@ +ERROR 42000: Row size too large (> ####). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. f4 f8 -xxx zzz f4 f8 -xxx zzz diff --git a/mysql-test/suite/innodb/t/innodb_bug34300.test b/mysql-test/suite/innodb/t/innodb_bug34300.test index 11682ad7828..800f326707d 100644 --- a/mysql-test/suite/innodb/t/innodb_bug34300.test +++ b/mysql-test/suite/innodb/t/innodb_bug34300.test @@ -1,31 +1,32 @@ ---source include/have_innodb.inc # # Bug#34300 Tinyblob & tinytext fields currupted after export/import and alter in 5.1 # http://bugs.mysql.com/34300 # +-- source include/have_innodb.inc + -- disable_query_log -- disable_result_log -call mtr.add_suppression("InnoDB: Warning: a long semaphore wait:"); -call mtr.add_suppression("the age of the last checkpoint is"); +call mtr.add_suppression("InnoDB: The total blob data length"); # set packet size and reconnect let $max_packet=`select @@global.max_allowed_packet`; SET @@global.max_allowed_packet=16777216; --connect (newconn, localhost, root,,) -DROP TABLE IF EXISTS bug34300; +--enable_result_log + CREATE TABLE bug34300 ( f4 TINYTEXT, f6 MEDIUMTEXT, f8 TINYBLOB ) ENGINE=InnoDB; +--replace_regex /\(> [0-9]*\)/(> ####)/ +--error ER_TOO_BIG_ROWSIZE INSERT INTO bug34300 VALUES ('xxx', repeat('a', 8459264), 'zzz'); --- enable_result_log - SELECT f4, f8 FROM bug34300; ALTER TABLE bug34300 ADD COLUMN (f10 INT); diff --git a/mysql-test/t/flush-innodb.test b/mysql-test/t/flush-innodb.test index 7a877b977ce..acf9493693a 100644 --- a/mysql-test/t/flush-innodb.test +++ b/mysql-test/t/flush-innodb.test @@ -4,7 +4,7 @@ FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT; UNLOCK TABLES; CREATE TABLE t1 ( m MEDIUMTEXT ) ENGINE=InnoDB; -INSERT INTO t1 VALUES ( REPEAT('i',1048576) ); +INSERT INTO t1 VALUES ( REPEAT('i',65535) ); DROP TABLE t1; diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index e227d953133..425d0bd0f1c 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -72,7 +72,6 @@ IF(NOT CMAKE_CROSSCOMPILING) long x; long y; long res; - char c; x = 10; y = 123; @@ -93,6 +92,16 @@ IF(NOT CMAKE_CROSSCOMPILING) if (res != 123 + 10 || x != 123 + 10) { return(1); } + return(0); + }" + HAVE_IB_GCC_ATOMIC_BUILTINS + ) + CHECK_C_SOURCE_RUNS( + " + int main() + { + long res; + char c; c = 10; res = __sync_lock_test_and_set(&c, 123); @@ -101,7 +110,7 @@ IF(NOT CMAKE_CROSSCOMPILING) } return(0); }" - HAVE_IB_GCC_ATOMIC_BUILTINS + HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE ) CHECK_C_SOURCE_RUNS( "#include @@ -148,6 +157,10 @@ IF(HAVE_IB_GCC_ATOMIC_BUILTINS) ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1) ENDIF() +IF(HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE) + ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_BYTE=1) +ENDIF() + IF(HAVE_IB_GCC_ATOMIC_BUILTINS_64) ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_64=1) ENDIF() diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc index bb65dd82216..a060cbc7270 100644 --- a/storage/innobase/api/api0api.cc +++ b/storage/innobase/api/api0api.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2008, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2008, 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 @@ -2044,6 +2044,8 @@ ib_cursor_delete_row( const rec_t* rec; ib_bool_t page_format; mtr_t mtr; + rec_t* copy = NULL; + byte ptr[UNIV_PAGE_SIZE_MAX]; page_format = static_cast( dict_table_is_comp(index->table)); @@ -2052,16 +2054,27 @@ ib_cursor_delete_row( if (btr_pcur_restore_position( BTR_SEARCH_LEAF, pcur, &mtr)) { + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + + rec_offs_init(offsets_); rec = btr_pcur_get_rec(pcur); - } else { - rec = NULL; + + /* Since mtr will be commited, the rec + will not be protected. Make a copy of + the rec. */ + offsets = rec_get_offsets( + rec, index, offsets, ULINT_UNDEFINED, &heap); + ut_ad(rec_offs_size(offsets) < UNIV_PAGE_SIZE_MAX); + copy = rec_copy(ptr, rec, offsets); } mtr_commit(&mtr); - if (rec && !rec_get_deleted_flag(rec, page_format)) { - err = ib_delete_row(cursor, pcur, rec); + if (copy && !rec_get_deleted_flag(copy, page_format)) { + err = ib_delete_row(cursor, pcur, copy); } else { err = DB_RECORD_NOT_FOUND; } diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 34a72f360be..bd3d688a0c2 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -2557,6 +2557,31 @@ make_external: ut_ad(flags & BTR_KEEP_POS_FLAG); } + if (big_rec_vec) { + const ulint redo_10p = srv_log_file_size * UNIV_PAGE_SIZE / 10; + ulint total_blob_len = 0; + + /* Calculate the total number of bytes for blob data */ + for (ulint i = 0; i < big_rec_vec->n_fields; i++) { + total_blob_len += big_rec_vec->fields[i].len; + } + + if (total_blob_len > redo_10p) { + ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data" + " length (" ULINTPF ") is greater than" + " 10%% of the redo log file size (" UINT64PF + "). Please increase innodb_log_file_size.", + total_blob_len, srv_log_file_size); + if (n_reserved > 0) { + fil_space_release_free_extents( + index->space, n_reserved); + } + + err = DB_TOO_BIG_RECORD; + goto err_exit; + } + } + /* Store state of explicit locks on rec on the page infimum record, before deleting rec. The page infimum acts as a dummy carrier of the locks, taking care also of lock releases, before we can move the locks @@ -4378,6 +4403,7 @@ btr_store_big_rec_extern_fields( buf_block_t** freed_pages = NULL; ulint n_freed_pages = 0; dberr_t error = DB_SUCCESS; + ulint total_blob_len = 0; ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); @@ -4397,6 +4423,23 @@ btr_store_big_rec_extern_fields( rec_page_no = buf_block_get_page_no(rec_block); ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX); + const ulint redo_10p = (srv_log_file_size * UNIV_PAGE_SIZE / 10); + + /* Calculate the total number of bytes for blob data */ + for (ulint i = 0; i < big_rec_vec->n_fields; i++) { + total_blob_len += big_rec_vec->fields[i].len; + } + + if (total_blob_len > redo_10p) { + ut_ad(op == BTR_STORE_INSERT); + ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data length" + " (" ULINTPF ") is greater than 10%% of the" + " redo log file size (" UINT64PF "). Please" + " increase innodb_log_file_size.", + total_blob_len, srv_log_file_size); + return(DB_TOO_BIG_RECORD); + } + if (page_zip) { int err; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 4bae962e7d3..6f00d2e43b5 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2882,12 +2882,6 @@ got_block: ut_ad(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE); -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no padding in buf_page_t. On - other systems, Valgrind could complain about uninitialized pad - bytes. */ - UNIV_MEM_ASSERT_RW(&fix_block->page, sizeof(fix_block->page)); -#endif #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH) @@ -5401,7 +5395,7 @@ buf_get_free_list_len(void) #else /* !UNIV_HOTBACKUP */ /********************************************************************//** -Inits a page to the buffer buf_pool, for use in ibbackup --restore. */ +Inits a page to the buffer buf_pool, for use in mysqlbackup --restore. */ UNIV_INTERN void buf_page_init_for_backup_restore( diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 64409e1993d..8574a6101e7 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -1818,13 +1818,6 @@ buf_LRU_free_page( rw_lock_x_lock(hash_lock); mutex_enter(block_mutex); -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no padding in buf_page_t. On - other systems, Valgrind could complain about uninitialized pad - bytes. */ - UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); -#endif - if (!buf_page_can_relocate(bpage)) { /* Do not free buffer fixed or I/O-fixed blocks. */ @@ -1862,12 +1855,6 @@ func_exit: ut_ad(buf_page_in_file(bpage)); ut_ad(bpage->in_LRU_list); ut_ad(!bpage->in_flush_list == !bpage->oldest_modification); -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no padding in buf_page_t. On - other systems, Valgrind could complain about uninitialized pad - bytes. */ - UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); -#endif #ifdef UNIV_DEBUG if (buf_debug_prints) { @@ -1940,13 +1927,6 @@ func_exit: ut_ad(prev_b->in_LRU_list); ut_ad(buf_page_in_file(prev_b)); -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no - padding in buf_page_t. On other - systems, Valgrind could complain about - uninitialized pad bytes. */ - UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b); -#endif UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, prev_b, b); @@ -2172,13 +2152,6 @@ buf_LRU_block_remove_hashed( ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE); ut_a(bpage->buf_fix_count == 0); -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no padding in - buf_page_t. On other systems, Valgrind could complain - about uninitialized pad bytes. */ - UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); -#endif - buf_LRU_remove_block(bpage); buf_pool->freed_page_clock += 1; diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index ff892749d4f..30523ff2af4 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.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 @@ -1611,26 +1611,25 @@ dict_create_add_foreign_to_dictionary( return(error); } -/********************************************************************//** -Adds foreign key definitions to data dictionary tables in the database. -@return error code or DB_SUCCESS */ +/** Adds the given set of foreign key objects to the dictionary tables +in the database. This function does not modify the dictionary cache. The +caller must ensure that all foreign key objects contain a valid constraint +name in foreign->id. +@param[in] local_fk_set set of foreign key objects, to be added to +the dictionary tables +@param[in] table table to which the foreign key objects in +local_fk_set belong to +@param[in,out] trx transaction +@return error code or DB_SUCCESS */ UNIV_INTERN dberr_t dict_create_add_foreigns_to_dictionary( /*===================================*/ - ulint start_id,/*!< in: if we are actually doing ALTER TABLE - ADD CONSTRAINT, we want to generate constraint - numbers which are bigger than in the table so - far; we number the constraints from - start_id + 1 up; start_id should be set to 0 if - we are creating a new table, or if the table - so far has no constraints for which the name - was generated here */ - dict_table_t* table, /*!< in: table */ - trx_t* trx) /*!< in: transaction */ + const dict_foreign_set& local_fk_set, + const dict_table_t* table, + trx_t* trx) { dict_foreign_t* foreign; - ulint number = start_id + 1; dberr_t error; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1643,17 +1642,12 @@ dict_create_add_foreigns_to_dictionary( return(DB_ERROR); } - for (foreign = UT_LIST_GET_FIRST(table->foreign_list); - foreign; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + for (dict_foreign_set::const_iterator it = local_fk_set.begin(); + it != local_fk_set.end(); + ++it) { - error = dict_create_add_foreign_id(&number, table->name, - foreign); - - if (error != DB_SUCCESS) { - - return(error); - } + foreign = *it; + ut_ad(foreign->id != NULL); error = dict_create_add_foreign_to_dictionary(table->name, foreign, trx); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 30266262f37..51e62fefa6b 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -27,6 +27,7 @@ Created 1/8/1996 Heikki Tuuri #include "dict0dict.h" #include "fts0fts.h" #include "fil0fil.h" +#include #ifdef UNIV_NONINL #include "dict0dict.ic" @@ -1251,8 +1252,8 @@ dict_table_can_be_evicted( #endif /* UNIV_SYNC_DEBUG */ ut_a(table->can_be_evicted); - ut_a(UT_LIST_GET_LEN(table->foreign_list) == 0); - ut_a(UT_LIST_GET_LEN(table->referenced_list) == 0); + ut_a(table->foreign_set.empty()); + ut_a(table->referenced_set.empty()); if (table->n_ref_count == 0) { dict_index_t* index; @@ -1468,6 +1469,22 @@ dict_index_find_on_id_low( return(NULL); } +/** Function object to remove a foreign key constraint from the +referenced_set of the referenced table. The foreign key object is +also removed from the dictionary cache. The foreign key constraint +is not removed from the foreign_set of the table containing the +constraint. */ +struct dict_foreign_remove_partial +{ + void operator()(dict_foreign_t* foreign) { + dict_table_t* table = foreign->referenced_table; + if (table != NULL) { + table->referenced_set.erase(foreign); + } + dict_foreign_free(foreign); + } +}; + /**********************************************************************//** Renames a table object. @return TRUE if success */ @@ -1642,27 +1659,25 @@ dict_table_rename_in_cache( system tables through a call of dict_load_foreigns. */ /* Remove the foreign constraints from the cache */ - foreign = UT_LIST_GET_LAST(table->foreign_list); - - while (foreign != NULL) { - dict_foreign_remove_from_cache(foreign); - foreign = UT_LIST_GET_LAST(table->foreign_list); - } + std::for_each(table->foreign_set.begin(), + table->foreign_set.end(), + dict_foreign_remove_partial()); + table->foreign_set.clear(); /* Reset table field in referencing constraints */ + for (dict_foreign_set::iterator it + = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign != NULL) { + foreign = *it; foreign->referenced_table = NULL; foreign->referenced_index = NULL; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); } - /* Make the list of referencing constraints empty */ - - UT_LIST_INIT(table->referenced_list); + /* Make the set of referencing constraints empty */ + table->referenced_set.clear(); return(DB_SUCCESS); } @@ -1671,9 +1686,19 @@ dict_table_rename_in_cache( the constraint id of new format >= 4.0.18 constraints. Note that at this point we have already changed table->name to the new name. */ - foreign = UT_LIST_GET_FIRST(table->foreign_list); + dict_foreign_set fk_set; + + for (;;) { + + dict_foreign_set::iterator it + = table->foreign_set.begin(); + + if (it == table->foreign_set.end()) { + break; + } + + foreign = *it; - while (foreign != NULL) { if (ut_strlen(foreign->foreign_table_name) < ut_strlen(table->name)) { /* Allocate a longer name buffer; @@ -1823,12 +1848,18 @@ dict_table_rename_in_cache( mem_free(old_id); } - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + table->foreign_set.erase(it); + fk_set.insert(foreign); } - for (foreign = UT_LIST_GET_FIRST(table->referenced_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + ut_a(table->foreign_set.empty()); + table->foreign_set.swap(fk_set); + + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + + foreign = *it; if (ut_strlen(foreign->referenced_table_name) < ut_strlen(table->name)) { @@ -1898,27 +1929,17 @@ dict_table_remove_from_cache_low( ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); -#if 0 - fputs("Removing table ", stderr); - ut_print_name(stderr, table->name, ULINT_UNDEFINED); - fputs(" from dictionary cache\n", stderr); -#endif - /* Remove the foreign constraints from the cache */ - - for (foreign = UT_LIST_GET_LAST(table->foreign_list); - foreign != NULL; - foreign = UT_LIST_GET_LAST(table->foreign_list)) { - - dict_foreign_remove_from_cache(foreign); - } + std::for_each(table->foreign_set.begin(), table->foreign_set.end(), + dict_foreign_remove_partial()); + table->foreign_set.clear(); /* Reset table field in referencing constraints */ + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { - for (foreign = UT_LIST_GET_FIRST(table->referenced_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { - + foreign = *it; foreign->referenced_table = NULL; foreign->referenced_index = NULL; } @@ -3134,7 +3155,7 @@ dict_table_is_referenced_by_foreign_key( /*====================================*/ const dict_table_t* table) /*!< in: InnoDB table */ { - return(UT_LIST_GET_LEN(table->referenced_list) > 0); + return(!table->referenced_set.empty()); } /*********************************************************************//** @@ -3154,9 +3175,11 @@ dict_table_get_referenced_constraint( ut_ad(index != NULL); ut_ad(table != NULL); - for (foreign = UT_LIST_GET_FIRST(table->referenced_list); - foreign; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + + foreign = *it; if (foreign->referenced_index == index) { @@ -3185,9 +3208,11 @@ dict_table_get_foreign_constraint( ut_ad(index != NULL); ut_ad(table != NULL); - for (foreign = UT_LIST_GET_FIRST(table->foreign_list); - foreign; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + for (dict_foreign_set::iterator it = table->foreign_set.begin(); + it != table->foreign_set.end(); + ++it) { + + foreign = *it; if (foreign->foreign_index == index) { @@ -3198,17 +3223,6 @@ dict_table_get_foreign_constraint( return(NULL); } -/*********************************************************************//** -Frees a foreign key struct. */ -UNIV_INTERN -void -dict_foreign_free( -/*==============*/ - dict_foreign_t* foreign) /*!< in, own: foreign key struct */ -{ - mem_heap_free(foreign->heap); -} - /**********************************************************************//** Removes a foreign constraint struct from the dictionary cache. */ UNIV_INTERN @@ -3220,16 +3234,12 @@ dict_foreign_remove_from_cache( ut_ad(mutex_own(&(dict_sys->mutex))); ut_a(foreign); - if (foreign->referenced_table) { - UT_LIST_REMOVE(referenced_list, - foreign->referenced_table->referenced_list, - foreign); + if (foreign->referenced_table != NULL) { + foreign->referenced_table->referenced_set.erase(foreign); } - if (foreign->foreign_table) { - UT_LIST_REMOVE(foreign_list, - foreign->foreign_table->foreign_list, - foreign); + if (foreign->foreign_table != NULL) { + foreign->foreign_table->foreign_set.erase(foreign); } dict_foreign_free(foreign); @@ -3243,33 +3253,21 @@ static dict_foreign_t* dict_foreign_find( /*==============*/ - dict_table_t* table, /*!< in: table object */ - const char* id) /*!< in: foreign constraint id */ + dict_table_t* table, /*!< in: table object */ + dict_foreign_t* foreign) /*!< in: foreign constraint */ { - dict_foreign_t* foreign; - ut_ad(mutex_own(&(dict_sys->mutex))); - foreign = UT_LIST_GET_FIRST(table->foreign_list); + dict_foreign_set::iterator it = table->foreign_set.find(foreign); - while (foreign) { - if (ut_strcmp(id, foreign->id) == 0) { - - return(foreign); - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + if (it != table->foreign_set.end()) { + return(*it); } - foreign = UT_LIST_GET_FIRST(table->referenced_list); + it = table->referenced_set.find(foreign); - while (foreign) { - if (ut_strcmp(id, foreign->id) == 0) { - - return(foreign); - } - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + if (it != table->referenced_set.end()) { + return(*it); } return(NULL); @@ -3407,11 +3405,11 @@ dict_foreign_add_to_cache( ut_a(for_table || ref_table); if (for_table) { - for_in_cache = dict_foreign_find(for_table, foreign->id); + for_in_cache = dict_foreign_find(for_table, foreign); } if (!for_in_cache && ref_table) { - for_in_cache = dict_foreign_find(ref_table, foreign->id); + for_in_cache = dict_foreign_find(ref_table, foreign); } if (for_in_cache) { @@ -3448,9 +3446,12 @@ dict_foreign_add_to_cache( for_in_cache->referenced_table = ref_table; for_in_cache->referenced_index = index; - UT_LIST_ADD_LAST(referenced_list, - ref_table->referenced_list, - for_in_cache); + + std::pair ret + = ref_table->referenced_set.insert(for_in_cache); + + ut_a(ret.second); /* second is true if the insertion + took place */ added_to_referenced_list = TRUE; } @@ -3479,10 +3480,13 @@ dict_foreign_add_to_cache( if (for_in_cache == foreign) { if (added_to_referenced_list) { - UT_LIST_REMOVE( - referenced_list, - ref_table->referenced_list, - for_in_cache); + const dict_foreign_set::size_type n + = ref_table->referenced_set + .erase(for_in_cache); + + ut_a(n == 1); /* the number of + elements removed must + be one */ } mem_heap_free(foreign->heap); @@ -3493,9 +3497,11 @@ dict_foreign_add_to_cache( for_in_cache->foreign_table = for_table; for_in_cache->foreign_index = index; - UT_LIST_ADD_LAST(foreign_list, - for_table->foreign_list, - for_in_cache); + std::pair ret + = for_table->foreign_set.insert(for_in_cache); + + ut_a(ret.second); /* second is true if the insertion + took place */ } /* We need to move the table to the non-LRU end of the table LRU @@ -4073,9 +4079,12 @@ dict_table_get_highest_foreign_id( ut_a(table); len = ut_strlen(table->name); - foreign = UT_LIST_GET_FIRST(table->foreign_list); - while (foreign) { + for (dict_foreign_set::iterator it = table->foreign_set.begin(); + it != table->foreign_set.end(); + ++it) { + foreign = *it; + if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len && 0 == ut_memcmp(foreign->id, table->name, len) && 0 == ut_memcmp(foreign->id + len, @@ -4094,8 +4103,6 @@ dict_table_get_highest_foreign_id( } } } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); } return(biggest_id); @@ -4156,6 +4163,7 @@ dict_create_foreign_constraints_low( dict_table_t* referenced_table; dict_table_t* table_to_alter; ulint highest_id_so_far = 0; + ulint number = 1; dict_index_t* index; dict_foreign_t* foreign; const char* ptr = sql_string; @@ -4174,6 +4182,8 @@ dict_create_foreign_constraints_low( const dict_col_t*columns[500]; const char* column_names[500]; const char* referenced_table_name; + dict_foreign_set local_fk_set; + dict_foreign_set_free local_fk_set_free(local_fk_set); ut_ad(!srv_read_only_mode); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -4238,6 +4248,7 @@ dict_create_foreign_constraints_low( table_to_alter); } + number = highest_id_so_far + 1; /* Scan for foreign key declarations in a loop */ loop: /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */ @@ -4282,7 +4293,7 @@ loop: command, determine if there are any foreign keys, and if so, immediately reject the command if the table is a temporary one. For now, this kludge will work. */ - if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) { + if (reject_fks && !local_fk_set.empty()) { return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4292,7 +4303,17 @@ loop: to the data dictionary system tables on disk */ error = dict_create_add_foreigns_to_dictionary( - highest_id_so_far, table, trx); + local_fk_set, table, trx); + + if (error == DB_SUCCESS) { + + table->foreign_set.insert(local_fk_set.begin(), + local_fk_set.end()); + std::for_each(local_fk_set.begin(), + local_fk_set.end(), + dict_foreign_add_to_referenced_table()); + local_fk_set.clear(); + } return(error); } @@ -4451,6 +4472,24 @@ col_loop1: strcpy(foreign->id + db_len + 1, constraint_name); } + if (foreign->id == NULL) { + error = dict_create_add_foreign_id(&number, + table->name, foreign); + if (error != DB_SUCCESS) { + dict_foreign_free(foreign); + return(error); + } + } + + std::pair ret + = local_fk_set.insert(foreign); + + if (!ret.second) { + /* A duplicate foreign key name has been found */ + dict_foreign_free(foreign); + return(DB_CANNOT_ADD_CONSTRAINT); + } + foreign->foreign_table = table; foreign->foreign_table_name = mem_heap_strdup( foreign->heap, table->name); @@ -4476,8 +4515,6 @@ col_loop1: checking of foreign key constraints! */ if (!success || (!referenced_table && trx->check_foreigns)) { - dict_foreign_free(foreign); - mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); fprintf(ef, "%s:\nCannot resolve table name close to:\n" @@ -4491,7 +4528,6 @@ col_loop1: ptr = dict_accept(cs, ptr, "(", &success); if (!success) { - dict_foreign_free(foreign); dict_foreign_report_syntax_err(name, start_of_latest_foreign, ptr); return(DB_CANNOT_ADD_CONSTRAINT); @@ -4506,7 +4542,6 @@ col_loop2: i++; if (!success) { - dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); @@ -4527,7 +4562,6 @@ col_loop2: ptr = dict_accept(cs, ptr, ")", &success); if (!success || foreign->n_fields != i) { - dict_foreign_free(foreign); dict_foreign_report_syntax_err(name, start_of_latest_foreign, ptr); @@ -4553,7 +4587,6 @@ scan_on_conditions: ptr = dict_accept(cs, ptr, "UPDATE", &success); if (!success) { - dict_foreign_free(foreign); dict_foreign_report_syntax_err( name, start_of_latest_foreign, ptr); @@ -4591,7 +4624,6 @@ scan_on_conditions: ptr = dict_accept(cs, ptr, "ACTION", &success); if (!success) { - dict_foreign_free(foreign); dict_foreign_report_syntax_err( name, start_of_latest_foreign, ptr); @@ -4610,7 +4642,6 @@ scan_on_conditions: ptr = dict_accept(cs, ptr, "SET", &success); if (!success) { - dict_foreign_free(foreign); dict_foreign_report_syntax_err(name, start_of_latest_foreign, ptr); return(DB_CANNOT_ADD_CONSTRAINT); @@ -4619,7 +4650,6 @@ scan_on_conditions: ptr = dict_accept(cs, ptr, "NULL", &success); if (!success) { - dict_foreign_free(foreign); dict_foreign_report_syntax_err(name, start_of_latest_foreign, ptr); return(DB_CANNOT_ADD_CONSTRAINT); @@ -4632,8 +4662,6 @@ scan_on_conditions: /* It is not sensible to define SET NULL if the column is not allowed to be NULL! */ - dict_foreign_free(foreign); - mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); fprintf(ef, "%s:\n" @@ -4659,8 +4687,6 @@ try_find_index: if (n_on_deletes > 1 || n_on_updates > 1) { /* It is an error to define more than 1 action */ - dict_foreign_free(foreign); - mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); fprintf(ef, "%s:\n" @@ -4682,7 +4708,6 @@ try_find_index: foreign->foreign_index, TRUE, FALSE); if (!index) { - dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); fprintf(ef, "%s:\n" @@ -4726,16 +4751,6 @@ try_find_index: = mem_heap_strdup(foreign->heap, column_names[i]); } - /* We found an ok constraint definition: add to the lists */ - - UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign); - - if (referenced_table) { - UT_LIST_ADD_LAST(referenced_list, - referenced_table->referenced_list, - foreign); - } - goto loop; } /************************************************************************** @@ -4821,7 +4836,6 @@ dict_foreign_parse_drop_constraints( const char*** constraints_to_drop) /*!< out: id's of the constraints to drop */ { - dict_foreign_t* foreign; ibool success; char* str; size_t len; @@ -4898,25 +4912,10 @@ loop: (*constraints_to_drop)[*n] = id; (*n)++; - /* Look for the given constraint id */ - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign != NULL) { - if (0 == innobase_strcasecmp(foreign->id, id) - || (strchr(foreign->id, '/') - && 0 == innobase_strcasecmp( - id, - dict_remove_db_name(foreign->id)))) { - /* Found */ - break; - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - - if (foreign == NULL) { + if (std::find_if(table->foreign_set.begin(), + table->foreign_set.end(), + dict_foreign_matches_id(id)) + == table->foreign_set.end()) { if (!srv_read_only_mode) { FILE* ef = dict_foreign_err_file; @@ -5243,7 +5242,6 @@ dict_table_print( dict_table_t* table) /*!< in: table */ { dict_index_t* index; - dict_foreign_t* foreign; ulint i; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -5282,19 +5280,13 @@ dict_table_print( dict_table_stats_unlock(table, RW_X_LATCH); - foreign = UT_LIST_GET_FIRST(table->foreign_list); + std::for_each(table->foreign_set.begin(), + table->foreign_set.end(), + dict_foreign_print_low); - while (foreign != NULL) { - dict_foreign_print_low(foreign); - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign != NULL) { - dict_foreign_print_low(foreign); - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } + std::for_each(table->referenced_set.begin(), + table->referenced_set.end(), + dict_foreign_print_low); } /**********************************************************************//** @@ -5502,15 +5494,12 @@ dict_print_info_on_foreign_keys( mutex_enter(&(dict_sys->mutex)); - foreign = UT_LIST_GET_FIRST(table->foreign_list); + for (dict_foreign_set::iterator it = table->foreign_set.begin(); + it != table->foreign_set.end(); + ++it) { - if (foreign == NULL) { - mutex_exit(&(dict_sys->mutex)); + foreign = *it; - return; - } - - while (foreign != NULL) { if (create_table_format) { dict_print_info_on_foreign_key_in_create_format( file, trx, foreign, TRUE); @@ -5567,8 +5556,6 @@ dict_print_info_on_foreign_keys( fputs(" ON UPDATE NO ACTION", file); } } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); } mutex_exit(&(dict_sys->mutex)); @@ -5900,10 +5887,11 @@ dict_foreign_replace_index( ut_ad(index->to_be_dropped); ut_ad(index->table == table); - for (foreign = UT_LIST_GET_FIRST(table->foreign_list); - foreign; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + for (dict_foreign_set::iterator it = table->foreign_set.begin(); + it != table->foreign_set.end(); + ++it) { + foreign = *it; if (foreign->foreign_index == index) { ut_ad(foreign->foreign_table == index->table); @@ -5923,10 +5911,11 @@ dict_foreign_replace_index( } } - for (foreign = UT_LIST_GET_FIRST(table->referenced_list); - foreign; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + foreign = *it; if (foreign->referenced_index == index) { ut_ad(foreign->referenced_table == index->table); @@ -6246,24 +6235,24 @@ dict_table_schema_check( } } - if (req_schema->n_foreign != UT_LIST_GET_LEN(table->foreign_list)) { + if (req_schema->n_foreign != table->foreign_set.size()) { ut_snprintf( errstr, errstr_sz, - "Table %s has %lu foreign key(s) pointing to other " - "tables, but it must have %lu.", + "Table %s has " ULINTPF " foreign key(s) pointing" + " to other tables, but it must have %lu.", ut_format_name(req_schema->table_name, TRUE, buf, sizeof(buf)), - UT_LIST_GET_LEN(table->foreign_list), + static_cast(table->foreign_set.size()), req_schema->n_foreign); return(DB_ERROR); } - if (req_schema->n_referenced != UT_LIST_GET_LEN(table->referenced_list)) { + if (req_schema->n_referenced != table->referenced_set.size()) { ut_snprintf( errstr, errstr_sz, - "There are %lu foreign key(s) pointing to %s, " + "There are " ULINTPF " foreign key(s) pointing to %s, " "but there must be %lu.", - UT_LIST_GET_LEN(table->referenced_list), + static_cast(table->referenced_set.size()), ut_format_name(req_schema->table_name, TRUE, buf, sizeof(buf)), req_schema->n_referenced); diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 6310b2fd225..885627a61bc 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -124,6 +124,9 @@ dict_mem_table_create( } #endif /* !UNIV_HOTBACKUP */ + new(&table->foreign_set) dict_foreign_set(); + new(&table->referenced_set) dict_foreign_set(); + return(table); } @@ -156,6 +159,9 @@ dict_mem_table_free( dict_table_stats_latch_destroy(table); + table->foreign_set.~dict_foreign_set(); + table->referenced_set.~dict_foreign_set(); + ut_free(table->name); mem_heap_free(table->heap); } @@ -326,10 +332,15 @@ dict_mem_table_col_rename_low( table->col_names = col_names; } + dict_foreign_t* foreign; + /* Replace the field names in every foreign key constraint. */ - for (dict_foreign_t* foreign = UT_LIST_GET_FIRST(table->foreign_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + for (dict_foreign_set::iterator it = table->foreign_set.begin(); + it != table->foreign_set.end(); + ++it) { + + foreign = *it; + for (unsigned f = 0; f < foreign->n_fields; f++) { /* These can point straight to table->col_names, because the foreign key @@ -341,10 +352,12 @@ dict_mem_table_col_rename_low( } } - for (dict_foreign_t* foreign = UT_LIST_GET_FIRST( - table->referenced_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + + foreign = *it; + for (unsigned f = 0; f < foreign->n_fields; f++) { /* foreign->referenced_col_names[] need to be copies, because the constraint may become diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index f4e5721caa7..08839f751ff 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -112,7 +112,7 @@ completes, we decrement the count and return the file node to the LRU-list if the count drops to zero. */ /** When mysqld is run, the default directory "." is the mysqld datadir, -but in the MySQL Embedded Server Library and ibbackup it is not the default +but in the MySQL Embedded Server Library and mysqlbackup it is not the default directory, and we must set the base file path explicitly */ UNIV_INTERN const char* fil_path_to_mysql_datadir = "."; @@ -2017,8 +2017,8 @@ fil_check_first_page( } /*******************************************************************//** -Reads the flushed lsn, arch no, and tablespace flag fields from a data -file at database startup. +Reads the flushed lsn, arch no, space_id and tablespace flag fields from +the first page of a data file at database startup. @retval NULL on success, or if innodb_force_recovery is set @return pointer to an error message string */ UNIV_INTERN @@ -2055,16 +2055,19 @@ fil_read_first_page( os_file_read(data_file, page, 0, UNIV_PAGE_SIZE); - *flags = fsp_header_get_flags(page); - - *space_id = fsp_header_get_space_id(page); - - flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); - + /* The FSP_HEADER on page 0 is only valid for the first file + in a tablespace. So if this is not the first datafile, leave + *flags and *space_id as they were read from the first file and + do not validate the first page. */ if (!one_read_already) { + *flags = fsp_header_get_flags(page); + *space_id = fsp_header_get_space_id(page); + check_msg = fil_check_first_page(page); } + flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); + ut_free(buf); if (check_msg) { @@ -2272,13 +2275,13 @@ exists and the space id in it matches. Replays the create operation if a file at that path does not exist yet. If the database directory for the file to be created does not exist, then we create the directory, too. -Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the -datadir that we should use in replaying the file operations. +Note that mysqlbackup --apply-log sets fil_path_to_mysql_datadir to point to +the datadir that we should use in replaying the file operations. InnoDB recovery does not replay these fully since it always sets the space id -to zero. But ibbackup does replay them. TODO: If remote tablespaces are used, -ibbackup will only create tables in the default directory since MLOG_FILE_CREATE -and MLOG_FILE_CREATE2 only know the tablename, not the path. +to zero. But mysqlbackup does replay them. TODO: If remote tablespaces are +used, mysqlbackup will only create tables in the default directory since +MLOG_FILE_CREATE and MLOG_FILE_CREATE2 only know the tablename, not the path. @return end of log record, or NULL if the record was not completely contained between ptr and end_ptr */ @@ -2365,11 +2368,11 @@ fil_op_log_parse_or_replay( } /* Let us try to perform the file operation, if sensible. Note that - ibbackup has at this stage already read in all space id info to the + mysqlbackup has at this stage already read in all space id info to the fil0fil.cc data structures. NOTE that our algorithm is not guaranteed to work correctly if there - were renames of tables during the backup. See ibbackup code for more + were renames of tables during the backup. See mysqlbackup code for more on the problem. */ switch (type) { @@ -2784,12 +2787,12 @@ fil_delete_tablespace( if (err == DB_SUCCESS) { #ifndef UNIV_HOTBACKUP /* Write a log record about the deletion of the .ibd - file, so that ibbackup can replay it in the + file, so that mysqlbackup can replay it in the --apply-log phase. We use a dummy mtr and the familiar log write mechanism. */ mtr_t mtr; - /* When replaying the operation in ibbackup, do not try + /* When replaying the operation in mysqlbackup, do not try to write any log record */ mtr_start(&mtr); @@ -4463,7 +4466,7 @@ will_not_choose: " (< 4 pages 16 kB each),\n" "InnoDB: or the space id in the file header" " is not sensible.\n" - "InnoDB: This can happen in an ibbackup run," + "InnoDB: This can happen in an mysqlbackup run," " and is not dangerous.\n", fsp->filepath, fsp->id, fsp->filepath, size); os_file_close(fsp->file); @@ -4500,7 +4503,7 @@ will_not_choose: "InnoDB: because space %s with the same id\n" "InnoDB: was scanned earlier. This can happen" " if you have renamed tables\n" - "InnoDB: during an ibbackup run.\n", + "InnoDB: during an mysqlbackup run.\n", fsp->filepath, fsp->id, fsp->filepath, space->name); os_file_close(fsp->file); @@ -5213,9 +5216,9 @@ file_extended: #ifdef UNIV_HOTBACKUP /********************************************************************//** Extends all tablespaces to the size stored in the space header. During the -ibbackup --apply-log phase we extended the spaces on-demand so that log records -could be applied, but that may have left spaces still too small compared to -the size stored in the space header. */ +mysqlbackup --apply-log phase we extended the spaces on-demand so that log +records could be applied, but that may have left spaces still too small +compared to the size stored in the space header. */ UNIV_INTERN void fil_extend_tablespaces_to_stored_len(void) @@ -5712,7 +5715,7 @@ fil_io( ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0); #ifdef UNIV_HOTBACKUP - /* In ibbackup do normal i/o, not aio */ + /* In mysqlbackup do normal i/o, not aio */ if (type == OS_FILE_READ) { ret = os_file_read(node->handle, buf, offset, len); } else { diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index d6c19c0050a..dd48ffee14d 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -83,11 +83,11 @@ UNIV_INTERN fts_ast_node_t* fts_ast_create_node_term( /*=====================*/ - void* arg, /*!< in: ast state instance */ - const char* ptr) /*!< in: ast term string */ + void* arg, /*!< in: ast state instance */ + const fts_ast_string_t* ptr) /*!< in: ast term string */ { fts_ast_state_t* state = static_cast(arg); - ulint len = strlen(ptr); + ulint len = ptr->len; ulint cur_pos = 0; fts_ast_node_t* node = NULL; fts_ast_node_t* node_list = NULL; @@ -101,8 +101,9 @@ fts_ast_create_node_term( cur_len = innobase_mysql_fts_get_token( state->charset, - reinterpret_cast(ptr) + cur_pos, - reinterpret_cast(ptr) + len, &str, &offset); + reinterpret_cast(ptr->str) + cur_pos, + reinterpret_cast(ptr->str) + len, + &str, &offset); if (cur_len == 0) { break; @@ -124,10 +125,8 @@ fts_ast_create_node_term( node->type = FTS_AST_TERM; - node->term.ptr = static_cast(ut_malloc( - str.f_len + 1)); - memcpy(node->term.ptr, str.f_str, str.f_len); - node->term.ptr[str.f_len] = '\0'; + node->term.ptr = fts_ast_string_create( + str.f_str, str.f_len); fts_ast_state_add_node( static_cast(arg), node); @@ -160,25 +159,21 @@ UNIV_INTERN fts_ast_node_t* fts_ast_create_node_text( /*=====================*/ - void* arg, /*!< in: ast state instance */ - const char* ptr) /*!< in: ast text string */ + void* arg, /*!< in: ast state instance */ + const fts_ast_string_t* ptr) /*!< in: ast text string */ { - ulint len = strlen(ptr); + ulint len = ptr->len; fts_ast_node_t* node = NULL; + /* Once we come here, the string must have at least 2 quotes "" + around the query string, which could be empty. Also the query + string may contain 0x00 in it, we don't treat it as null-terminated. */ + ut_ad(len >= 2); + ut_ad(ptr->str[0] == '\"' && ptr->str[len - 1] == '\"'); - ut_ad(len >= 1); - - if (len <= 2) { - /* There is a way to directly supply null terminator - in the query string (by using 0x220022) and get here, - and certainly it would not make a valid query text */ - ut_ad(ptr[0] == '\"'); - - if (len == 2) { - ut_ad(ptr[1] == '\"'); - } - + if (len == 2) { + /* If the query string contains nothing except quotes, + it's obviously an invalid query. */ return(NULL); } @@ -188,11 +183,9 @@ fts_ast_create_node_text( len -= 2; node->type = FTS_AST_TEXT; - node->text.ptr = static_cast(ut_malloc(len + 1)); - /*!< Skip copying the first quote */ - memcpy(node->text.ptr, ptr + 1, len); - node->text.ptr[len] = 0; + node->text.ptr = fts_ast_string_create( + reinterpret_cast(ptr->str + 1), len); node->text.distance = ULINT_UNDEFINED; fts_ast_state_add_node((fts_ast_state_t*) arg, node); @@ -275,14 +268,14 @@ fts_ast_free_node( switch (node->type) { case FTS_AST_TEXT: if (node->text.ptr) { - ut_free(node->text.ptr); + fts_ast_string_free(node->text.ptr); node->text.ptr = NULL; } break; case FTS_AST_TERM: if (node->term.ptr) { - ut_free(node->term.ptr); + fts_ast_string_free(node->term.ptr); node->term.ptr = NULL; } break; @@ -421,10 +414,10 @@ fts_ast_state_free( fts_ast_node_t* next = node->next_alloc; if (node->type == FTS_AST_TEXT && node->text.ptr) { - ut_free(node->text.ptr); + fts_ast_string_free(node->text.ptr); node->text.ptr = NULL; } else if (node->type == FTS_AST_TERM && node->term.ptr) { - ut_free(node->term.ptr); + fts_ast_string_free(node->term.ptr); node->term.ptr = NULL; } @@ -445,11 +438,13 @@ fts_ast_node_print( { switch (node->type) { case FTS_AST_TEXT: - printf("TEXT: %s\n", node->text.ptr); + printf("TEXT: "); + fts_ast_string_print(node->text.ptr); break; case FTS_AST_TERM: - printf("TERM: %s\n", node->term.ptr); + printf("TERM: "); + fts_ast_string_print(node->term.ptr); break; case FTS_AST_LIST: @@ -628,3 +623,74 @@ fts_ast_visit( return(error); } + +/** +Create an ast string object, with NUL-terminator, so the string +has one more byte than len +@param[in] str pointer to string +@param[in] len length of the string +@return ast string with NUL-terminator */ +UNIV_INTERN +fts_ast_string_t* +fts_ast_string_create( + const byte* str, + ulint len) +{ + fts_ast_string_t* ast_str; + + ut_ad(len > 0); + + ast_str = static_cast + (ut_malloc(sizeof(fts_ast_string_t))); + ast_str->str = static_cast(ut_malloc(len + 1)); + + ast_str->len = len; + memcpy(ast_str->str, str, len); + ast_str->str[len] = '\0'; + + return(ast_str); +} + +/** +Free an ast string instance +@param[in,out] ast_str string to free */ +UNIV_INTERN +void +fts_ast_string_free( + fts_ast_string_t* ast_str) +{ + if (ast_str != NULL) { + ut_free(ast_str->str); + ut_free(ast_str); + } +} + +/** +Translate ast string of type FTS_AST_NUMB to unsigned long by strtoul +@param[in] str string to translate +@param[in] base the base +@return translated number */ +UNIV_INTERN +ulint +fts_ast_string_to_ul( + const fts_ast_string_t* ast_str, + int base) +{ + return(strtoul(reinterpret_cast(ast_str->str), + NULL, base)); +} + +/** +Print the ast string +@param[in] str string to print */ +UNIV_INTERN +void +fts_ast_string_print( + const fts_ast_string_t* ast_str) +{ + for (ulint i = 0; i < ast_str->len; ++i) { + printf("%c", ast_str->str[i]); + } + + printf("\n"); +} diff --git a/storage/innobase/fts/fts0blex.cc b/storage/innobase/fts/fts0blex.cc index f83523825d2..7d0acb00a3b 100644 --- a/storage/innobase/fts/fts0blex.cc +++ b/storage/innobase/fts/fts0blex.cc @@ -451,7 +451,7 @@ static yyconst flex_int16_t yy_chk[32] = #line 1 "fts0blex.l" /***************************************************************************** -Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -806,7 +806,7 @@ case 3: YY_RULE_SETUP #line 53 "fts0blex.l" { - val->token = strdup(fts0bget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner)); return(FTS_NUMB); } @@ -815,7 +815,7 @@ case 4: YY_RULE_SETUP #line 59 "fts0blex.l" { - val->token = strdup(fts0bget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner)); return(FTS_TERM); } @@ -824,7 +824,7 @@ case 5: YY_RULE_SETUP #line 65 "fts0blex.l" { - val->token = strdup(fts0bget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner)); return(FTS_TEXT); } diff --git a/storage/innobase/fts/fts0blex.l b/storage/innobase/fts/fts0blex.l index 6193f0df187..ae6e8ffaa48 100644 --- a/storage/innobase/fts/fts0blex.l +++ b/storage/innobase/fts/fts0blex.l @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -51,19 +51,19 @@ this program; if not, write to the Free Software Foundation, Inc., } [0-9]+ { - val->token = strdup(fts0bget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner)); return(FTS_NUMB); } [^" \n*()+\-<>~@%]* { - val->token = strdup(fts0bget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner)); return(FTS_TERM); } \"[^\"\n]*\" { - val->token = strdup(fts0bget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner)); return(FTS_TEXT); } diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index f503cc487b7..848d60f6e3f 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -608,8 +608,10 @@ fts_cache_init( cache->total_size = 0; + mutex_enter((ib_mutex_t*) &cache->deleted_lock); cache->deleted_doc_ids = ib_vector_create( cache->sync_heap, sizeof(fts_update_t), 4); + mutex_exit((ib_mutex_t*) &cache->deleted_lock); /* Reset the cache data for all the FTS indexes. */ for (i = 0; i < ib_vector_size(cache->indexes); ++i) { @@ -1137,7 +1139,10 @@ fts_cache_clear( cache->sync_heap->arg = NULL; cache->total_size = 0; + + mutex_enter((ib_mutex_t*) &cache->deleted_lock); cache->deleted_doc_ids = NULL; + mutex_exit((ib_mutex_t*) &cache->deleted_lock); } /*********************************************************************//** @@ -1954,10 +1959,15 @@ fts_create_one_index_table( char* table_name = fts_get_table_name(fts_table); dberr_t error; CHARSET_INFO* charset; + ulint flags2 = 0; ut_ad(index->type & DICT_FTS); - new_table = dict_mem_table_create(table_name, 0, 5, 1, 0); + if (srv_file_per_table) { + flags2 = DICT_TF2_USE_TABLESPACE; + } + + new_table = dict_mem_table_create(table_name, 0, 5, 1, flags2); field = dict_index_get_nth_field(index, 0); charset = innobase_get_fts_charset( @@ -1986,7 +1996,7 @@ fts_create_one_index_table( dict_mem_table_add_col(new_table, heap, "ilist", DATA_BLOB, 4130048, 0); - error = row_create_table_for_mysql(new_table, trx, true); + error = row_create_table_for_mysql(new_table, trx, false); if (error != DB_SUCCESS) { trx->error_state = error; @@ -2251,11 +2261,15 @@ static fts_trx_t* fts_trx_create( /*===========*/ - trx_t* trx) /*!< in: InnoDB transaction */ + trx_t* trx) /*!< in/out: InnoDB + transaction */ { - fts_trx_t* ftt; - ib_alloc_t* heap_alloc; - mem_heap_t* heap = mem_heap_create(1024); + fts_trx_t* ftt; + ib_alloc_t* heap_alloc; + mem_heap_t* heap = mem_heap_create(1024); + trx_named_savept_t* savep; + + ut_a(trx->fts_trx == NULL); ftt = static_cast(mem_heap_alloc(heap, sizeof(fts_trx_t))); ftt->trx = trx; @@ -2273,6 +2287,14 @@ fts_trx_create( fts_savepoint_create(ftt->savepoints, NULL, NULL); fts_savepoint_create(ftt->last_stmt, NULL, NULL); + /* Copy savepoints that already set before. */ + for (savep = UT_LIST_GET_FIRST(trx->trx_savepoints); + savep != NULL; + savep = UT_LIST_GET_NEXT(trx_savepoints, savep)) { + + fts_savepoint_take(trx, ftt, savep->name); + } + return(ftt); } @@ -4366,6 +4388,7 @@ fts_sync_commit( /* We need to do this within the deleted lock since fts_delete() can attempt to add a deleted doc id to the cache deleted id array. */ fts_cache_clear(cache); + DEBUG_SYNC_C("fts_deleted_doc_ids_clear"); fts_cache_init(cache); rw_lock_x_unlock(&cache->lock); @@ -5167,6 +5190,12 @@ fts_cache_append_deleted_doc_ids( mutex_enter((ib_mutex_t*) &cache->deleted_lock); + if (cache->deleted_doc_ids == NULL) { + mutex_exit((ib_mutex_t*) &cache->deleted_lock); + return; + } + + for (i = 0; i < ib_vector_size(cache->deleted_doc_ids); ++i) { fts_update_t* update; @@ -5452,16 +5481,15 @@ void fts_savepoint_take( /*===============*/ trx_t* trx, /*!< in: transaction */ + fts_trx_t* fts_trx, /*!< in: fts transaction */ const char* name) /*!< in: savepoint name */ { mem_heap_t* heap; - fts_trx_t* fts_trx; fts_savepoint_t* savepoint; fts_savepoint_t* last_savepoint; ut_a(name != NULL); - fts_trx = trx->fts_trx; heap = fts_trx->heap; /* The implied savepoint must exist. */ @@ -5778,7 +5806,7 @@ fts_savepoint_rollback( ut_a(ib_vector_size(savepoints) > 0); /* Restore the savepoint. */ - fts_savepoint_take(trx, name); + fts_savepoint_take(trx, trx->fts_trx, name); } } diff --git a/storage/innobase/fts/fts0pars.cc b/storage/innobase/fts/fts0pars.cc index 83d465b0988..7f0ba4e0c1b 100644 --- a/storage/innobase/fts/fts0pars.cc +++ b/storage/innobase/fts/fts0pars.cc @@ -100,6 +100,8 @@ extern int ftserror(const char* p); #define YYPARSE_PARAM state #define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer +#define YYTOKENFREE(token) fts_ast_string_free((token)) + typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); typedef int (*fts_scanner)(); @@ -154,9 +156,9 @@ typedef union YYSTYPE /* Line 293 of yacc.c */ #line 61 "fts0pars.y" - int oper; - char* token; - fts_ast_node_t* node; + int oper; + fts_ast_string_t* token; + fts_ast_node_t* node; @@ -632,6 +634,19 @@ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 +#define YYERRCLEANUP \ +do \ + switch (yylastchar) \ + { \ + case FTS_NUMB: \ + case FTS_TEXT: \ + case FTS_TERM: \ + YYTOKENFREE(yylval.token); \ + break; \ + default: \ + break; \ + } \ +while (YYID (0)) /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends @@ -1169,6 +1184,8 @@ yyparse () { /* The lookahead symbol. */ int yychar; +/* The backup of yychar when there is an error and we're in yyerrlab. */ +int yylastchar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; @@ -1524,8 +1541,8 @@ yyreduce: /* Line 1806 of yacc.c */ #line 141 "fts0pars.y" { - fts_ast_term_set_distance((yyvsp[(1) - (3)].node), strtoul((yyvsp[(3) - (3)].token), NULL, 10)); - free((yyvsp[(3) - (3)].token)); + fts_ast_term_set_distance((yyvsp[(1) - (3)].node), fts_ast_string_to_ul((yyvsp[(3) - (3)].token), 10)); + fts_ast_string_free((yyvsp[(3) - (3)].token)); } break; @@ -1557,8 +1574,8 @@ yyreduce: { (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node)); fts_ast_add_node((yyval.node), (yyvsp[(2) - (4)].node)); - fts_ast_term_set_distance((yyvsp[(2) - (4)].node), strtoul((yyvsp[(4) - (4)].token), NULL, 10)); - free((yyvsp[(4) - (4)].token)); + fts_ast_term_set_distance((yyvsp[(2) - (4)].node), fts_ast_string_to_ul((yyvsp[(4) - (4)].token), 10)); + fts_ast_string_free((yyvsp[(4) - (4)].token)); } break; @@ -1623,7 +1640,7 @@ yyreduce: #line 191 "fts0pars.y" { (yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token)); - free((yyvsp[(1) - (1)].token)); + fts_ast_string_free((yyvsp[(1) - (1)].token)); } break; @@ -1633,7 +1650,7 @@ yyreduce: #line 196 "fts0pars.y" { (yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token)); - free((yyvsp[(1) - (1)].token)); + fts_ast_string_free((yyvsp[(1) - (1)].token)); } break; @@ -1652,7 +1669,7 @@ yyreduce: #line 207 "fts0pars.y" { (yyval.node) = fts_ast_create_node_text(state, (yyvsp[(1) - (1)].token)); - free((yyvsp[(1) - (1)].token)); + fts_ast_string_free((yyvsp[(1) - (1)].token)); } break; @@ -1700,6 +1717,8 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: + /* Backup yychar, in case we would change it. */ + yylastchar = yychar; /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); @@ -1755,7 +1774,11 @@ yyerrlab: { /* Return failure if at end of input. */ if (yychar == YYEOF) - YYABORT; + { + /* Since we don't need the token, we have to free it first. */ + YYERRCLEANUP; + YYABORT; + } } else { @@ -1812,7 +1835,11 @@ yyerrlab1: /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) - YYABORT; + { + /* Since we don't need the error token, we have to free it first. */ + YYERRCLEANUP; + YYABORT; + } yydestruct ("Error: popping", diff --git a/storage/innobase/fts/fts0pars.y b/storage/innobase/fts/fts0pars.y index ff22e9a9873..e48036e82fe 100644 --- a/storage/innobase/fts/fts0pars.y +++ b/storage/innobase/fts/fts0pars.y @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -59,9 +59,9 @@ struct fts_lexer_struct { %} %union { - int oper; - char* token; - fts_ast_node_t* node; + int oper; + fts_ast_string_t* token; + fts_ast_node_t* node; }; /* Enable re-entrant parser */ @@ -139,8 +139,8 @@ expr : term { } | text '@' FTS_NUMB { - fts_ast_term_set_distance($1, strtoul($3, NULL, 10)); - free($3); + fts_ast_term_set_distance($1, fts_ast_string_to_ul($3, 10)); + fts_ast_string_free($3); } | prefix term '*' { @@ -157,8 +157,8 @@ expr : term { | prefix text '@' FTS_NUMB { $$ = fts_ast_create_node_list(state, $1); fts_ast_add_node($$, $2); - fts_ast_term_set_distance($2, strtoul($4, NULL, 10)); - free($4); + fts_ast_term_set_distance($2, fts_ast_string_to_ul($4, 10)); + fts_ast_string_free($4); } | prefix text { @@ -190,12 +190,12 @@ prefix : '-' { term : FTS_TERM { $$ = fts_ast_create_node_term(state, $1); - free($1); + fts_ast_string_free($1); } | FTS_NUMB { $$ = fts_ast_create_node_term(state, $1); - free($1); + fts_ast_string_free($1); } /* Ignore leading '*' */ @@ -206,7 +206,7 @@ term : FTS_TERM { text : FTS_TEXT { $$ = fts_ast_create_node_text(state, $1); - free($1); + fts_ast_string_free($1); } ; %% diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index adbf433e608..f26fd89ac76 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -2800,20 +2800,19 @@ fts_query_get_token( ulint str_len; byte* new_ptr = NULL; - str_len = ut_strlen((char*) node->term.ptr); + str_len = node->term.ptr->len; ut_a(node->type == FTS_AST_TERM); token->f_len = str_len; - token->f_str = node->term.ptr; + token->f_str = node->term.ptr->str; if (node->term.wildcard) { token->f_str = static_cast(ut_malloc(str_len + 2)); token->f_len = str_len + 1; - /* Need to copy the NUL character too. */ - memcpy(token->f_str, node->term.ptr, str_len + 1); + memcpy(token->f_str, node->term.ptr->str, str_len); token->f_str[str_len] = '%'; token->f_str[token->f_len] = 0; @@ -2848,8 +2847,8 @@ fts_query_visitor( switch (node->type) { case FTS_AST_TEXT: - token.f_str = node->text.ptr; - token.f_len = ut_strlen((char*) token.f_str); + token.f_str = node->text.ptr->str; + token.f_len = node->text.ptr->len; if (query->oper == FTS_EXIST) { ut_ad(query->intersection == NULL); @@ -2878,8 +2877,8 @@ fts_query_visitor( break; case FTS_AST_TERM: - token.f_str = node->term.ptr; - token.f_len = ut_strlen(reinterpret_cast(token.f_str)); + token.f_str = node->term.ptr->str; + token.f_len = node->term.ptr->len; /* Add the word to our RB tree that will be used to calculate this terms per document frequency. */ @@ -3191,13 +3190,9 @@ fts_query_read_node( to assign the frequency on search string behalf. */ if (query->cur_node->type == FTS_AST_TERM && query->cur_node->term.wildcard) { - - /* These cast are safe since we only care about the - terminating NUL character as an end of string marker. */ - term.f_len = ut_strlen(reinterpret_cast - (query->cur_node->term.ptr)); + term.f_len = query->cur_node->term.ptr->len; ut_ad(FTS_MAX_WORD_LEN >= term.f_len); - memcpy(term.f_str, query->cur_node->term.ptr, term.f_len); + memcpy(term.f_str, query->cur_node->term.ptr->str, term.f_len); } else { term.f_len = word->f_len; ut_ad(FTS_MAX_WORD_LEN >= word->f_len); @@ -3507,14 +3502,15 @@ fts_query_prepare_result( doc_freq = rbt_value(fts_doc_freq_t, node); /* Don't put deleted docs into result */ - if (fts_bsearch(array, 0, static_cast(size), doc_freq->doc_id) - >= 0) { + if (fts_bsearch(array, 0, static_cast(size), + doc_freq->doc_id) >= 0) { + /* one less matching doc count */ + --word_freq->doc_count; continue; } ranking.doc_id = doc_freq->doc_id; - ranking.rank = static_cast( - doc_freq->freq * word_freq->idf * word_freq->idf); + ranking.rank = static_cast(doc_freq->freq); ranking.words = NULL; fts_query_add_ranking(query, result->rankings_by_id, @@ -3527,6 +3523,25 @@ fts_query_prepare_result( } } + /* Calculate IDF only after we exclude the deleted items */ + fts_query_calculate_idf(query); + + node = rbt_first(query->word_freqs); + word_freq = rbt_value(fts_word_freq_t, node); + + /* Calculate the ranking for each doc */ + for (node = rbt_first(result->rankings_by_id); + node != NULL; + node = rbt_next(result->rankings_by_id, node)) { + + fts_ranking_t* ranking; + + ranking = rbt_value(fts_ranking_t, node); + + ranking->rank = static_cast( + ranking->rank * word_freq->idf * word_freq->idf); + } + return(result); } @@ -3900,6 +3915,7 @@ fts_query( /* Get the deleted doc ids that are in the cache. */ fts_cache_append_deleted_doc_ids( index->table->fts->cache, query.deleted->doc_ids); + DEBUG_SYNC_C("fts_deleted_doc_ids_append"); /* Sort the vector so that we can do a binary search over the ids. */ ib_vector_sort(query.deleted->doc_ids, fts_update_doc_id_cmp); @@ -3956,7 +3972,8 @@ fts_query( } /* Calculate the inverse document frequency of the terms. */ - if (query.error == DB_SUCCESS) { + if (query.error == DB_SUCCESS + && query.flags != FTS_OPT_RANKING) { fts_query_calculate_idf(&query); } diff --git a/storage/innobase/fts/fts0tlex.cc b/storage/innobase/fts/fts0tlex.cc index ef17ab1acf2..b744fbf0763 100644 --- a/storage/innobase/fts/fts0tlex.cc +++ b/storage/innobase/fts/fts0tlex.cc @@ -447,7 +447,7 @@ static yyconst flex_int16_t yy_chk[29] = #line 1 "fts0tlex.l" /***************************************************************************** -Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -802,7 +802,7 @@ case 3: YY_RULE_SETUP #line 54 "fts0tlex.l" { - val->token = strdup(fts0tget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner)); return(FTS_TEXT); } @@ -811,7 +811,7 @@ case 4: YY_RULE_SETUP #line 60 "fts0tlex.l" { - val->token = strdup(fts0tget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner)); return(FTS_TERM); } diff --git a/storage/innobase/fts/fts0tlex.l b/storage/innobase/fts/fts0tlex.l index a18c2a55081..4f55a83afe5 100644 --- a/storage/innobase/fts/fts0tlex.l +++ b/storage/innobase/fts/fts0tlex.l @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -52,13 +52,13 @@ this program; if not, write to the Free Software Foundation, Inc., } \"[^\"\n]*\" { - val->token = strdup(fts0tget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner)); return(FTS_TEXT); } [^" \n\%]* { - val->token = strdup(fts0tget_text(yyscanner)); + val->token = fts_ast_string_create(reinterpret_cast(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner)); return(FTS_TERM); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 50af060e15f..388032f3c96 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3572,7 +3572,7 @@ innobase_commit_ordered_2( { DBUG_ENTER("innobase_commit_ordered_2"); - /* We need current binlog position for ibbackup to work. + /* We need current binlog position for mysqlbackup to work. Note, the position is current because commit_ordered is guaranteed to be called in same sequenece as writing to binlog. */ @@ -4144,7 +4144,7 @@ innobase_savepoint( error = trx_savepoint_for_mysql(trx, name, (ib_int64_t)0); if (error == DB_SUCCESS && trx->fts_trx != NULL) { - fts_savepoint_take(trx, name); + fts_savepoint_take(trx, trx->fts_trx, name); } DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); @@ -12169,9 +12169,13 @@ ha_innobase::get_foreign_key_list( mutex_enter(&(dict_sys->mutex)); - for (foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + for (dict_foreign_set::iterator it + = prebuilt->table->foreign_set.begin(); + it != prebuilt->table->foreign_set.end(); + ++it) { + + foreign = *it; + pf_key_info = get_foreign_key_info(thd, foreign); if (pf_key_info) { f_key_list->push_back(pf_key_info); @@ -12207,9 +12211,13 @@ ha_innobase::get_parent_foreign_key_list( mutex_enter(&(dict_sys->mutex)); - for (foreign = UT_LIST_GET_FIRST(prebuilt->table->referenced_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + for (dict_foreign_set::iterator it + = prebuilt->table->referenced_set.begin(); + it != prebuilt->table->referenced_set.end(); + ++it) { + + foreign = *it; + pf_key_info = get_foreign_key_info(thd, foreign); if (pf_key_info) { f_key_list->push_back(pf_key_info); @@ -12242,8 +12250,8 @@ ha_innobase::can_switch_engines(void) "determining if there are foreign key constraints"; row_mysql_freeze_data_dictionary(prebuilt->trx); - can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list) - && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list); + can_switch = prebuilt->table->referenced_set.empty() + && prebuilt->table->foreign_set.empty(); row_mysql_unfreeze_data_dictionary(prebuilt->trx); prebuilt->trx->op_info = ""; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 810de051c9b..cb5faa42199 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -590,15 +590,9 @@ innobase_init_foreign( /* Check if any existing foreign key has the same id, this is needed only if user supplies the constraint name */ - for (const dict_foreign_t* existing_foreign - = UT_LIST_GET_FIRST(table->foreign_list); - existing_foreign != 0; - existing_foreign = UT_LIST_GET_NEXT( - foreign_list, existing_foreign)) { - - if (ut_strcmp(existing_foreign->id, foreign->id) == 0) { - return(false); - } + if (table->foreign_set.find(foreign) + != table->foreign_set.end()) { + return(false); } } @@ -2236,14 +2230,18 @@ innobase_check_foreigns_low( const char* col_name, bool drop) { + dict_foreign_t* foreign; ut_ad(mutex_own(&dict_sys->mutex)); /* Check if any FOREIGN KEY constraints are defined on this column. */ - for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST( - user_table->foreign_list); - foreign; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + + for (dict_foreign_set::iterator it = user_table->foreign_set.begin(); + it != user_table->foreign_set.end(); + ++it) { + + foreign = *it; + if (!drop && !(foreign->type & (DICT_FOREIGN_ON_DELETE_SET_NULL | DICT_FOREIGN_ON_UPDATE_SET_NULL))) { @@ -2275,10 +2273,13 @@ innobase_check_foreigns_low( /* Check if any FOREIGN KEY constraints in other tables are referring to the column that is being dropped. */ - for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST( - user_table->referenced_list); - foreign; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + for (dict_foreign_set::iterator it + = user_table->referenced_set.begin(); + it != user_table->referenced_set.end(); + ++it) { + + foreign = *it; + if (innobase_dropping_foreign(foreign, drop_fk, n_drop_fk)) { continue; } @@ -3598,11 +3599,12 @@ check_if_ok_to_rename: continue; } - for (dict_foreign_t* foreign = UT_LIST_GET_FIRST( - prebuilt->table->foreign_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT( - foreign_list, foreign)) { + for (dict_foreign_set::iterator it + = prebuilt->table->foreign_set.begin(); + it != prebuilt->table->foreign_set.end(); + ++it) { + + dict_foreign_t* foreign = *it; const char* fid = strchr(foreign->id, '/'); DBUG_ASSERT(fid); @@ -4443,10 +4445,12 @@ err_exit: rename_foreign: trx->op_info = "renaming column in SYS_FOREIGN_COLS"; - for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST( - user_table->foreign_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + for (dict_foreign_set::iterator it = user_table->foreign_set.begin(); + it != user_table->foreign_set.end(); + ++it) { + + dict_foreign_t* foreign = *it; + for (unsigned i = 0; i < foreign->n_fields; i++) { if (strcmp(foreign->foreign_col_names[i], from)) { continue; @@ -4476,10 +4480,12 @@ rename_foreign: } } - for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST( - user_table->referenced_list); - foreign != NULL; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + for (dict_foreign_set::iterator it + = user_table->referenced_set.begin(); + it != user_table->referenced_set.end(); + ++it) { + + dict_foreign_t* foreign = *it; for (unsigned i = 0; i < foreign->n_fields; i++) { if (strcmp(foreign->referenced_col_names[i], from)) { continue; @@ -4803,8 +4809,8 @@ innobase_update_foreign_cache( column names. No need to pass col_names or to drop constraints from the data dictionary cache. */ DBUG_ASSERT(!ctx->col_names); - DBUG_ASSERT(UT_LIST_GET_LEN(user_table->foreign_list) == 0); - DBUG_ASSERT(UT_LIST_GET_LEN(user_table->referenced_list) == 0); + DBUG_ASSERT(user_table->foreign_set.empty()); + DBUG_ASSERT(user_table->referenced_set.empty()); user_table = ctx->new_table; } else { /* Drop the foreign key constraints if the diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 289de8f42ae..3f2ac4980cf 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -447,7 +447,7 @@ buf_page_create( mtr_t* mtr); /*!< in: mini-transaction handle */ #else /* !UNIV_HOTBACKUP */ /********************************************************************//** -Inits a page to the buffer buf_pool, for use in ibbackup --restore. */ +Inits a page to the buffer buf_pool, for use in mysqlbackup --restore. */ UNIV_INTERN void buf_page_init_for_backup_restore( diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index b15a7fb11b6..6e419674f98 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -1160,12 +1160,6 @@ buf_page_hash_get_low( ut_a(buf_page_in_file(bpage)); ut_ad(bpage->in_page_hash); ut_ad(!bpage->in_zip_hash); -#if UNIV_WORD_SIZE == 4 - /* On 32-bit systems, there is no padding in - buf_page_t. On other systems, Valgrind could complain - about uninitialized pad bytes. */ - UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); -#endif } return(bpage); diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index 6ec1079957b..67eab9058da 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2012, 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 @@ -124,28 +124,24 @@ dict_create_add_foreign_id( const char* name, /*!< in: table name */ dict_foreign_t* foreign)/*!< in/out: foreign key */ __attribute__((nonnull)); -/********************************************************************//** -Adds foreign key definitions to data dictionary tables in the database. We -look at table->foreign_list, and also generate names to constraints that were -not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are -given locally for this table, that is, the number is not global, as in the -old format constraints < 4.0.18 it used to be. -@return error code or DB_SUCCESS */ + +/** Adds the given set of foreign key objects to the dictionary tables +in the database. This function does not modify the dictionary cache. The +caller must ensure that all foreign key objects contain a valid constraint +name in foreign->id. +@param[in] local_fk_set set of foreign key objects, to be added to +the dictionary tables +@param[in] table table to which the foreign key objects in +local_fk_set belong to +@param[in,out] trx transaction +@return error code or DB_SUCCESS */ UNIV_INTERN dberr_t dict_create_add_foreigns_to_dictionary( /*===================================*/ - ulint start_id,/*!< in: if we are actually doing ALTER TABLE - ADD CONSTRAINT, we want to generate constraint - numbers which are bigger than in the table so - far; we number the constraints from - start_id + 1 up; start_id should be set to 0 if - we are creating a new table, or if the table - so far has no constraints for which the name - was generated here */ - dict_table_t* table, /*!< in: table */ - trx_t* trx) /*!< in: transaction */ + const dict_foreign_set& local_fk_set, + const dict_table_t* table, + trx_t* trx) __attribute__((nonnull, warn_unused_result)); /****************************************************************//** Creates the tablespaces and datafiles system tables inside InnoDB diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index f1975456ab1..f5326fbdb41 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -47,6 +47,8 @@ Created 1/8/1996 Heikki Tuuri #include "trx0types.h" #include "fts0fts.h" #include "os0once.h" +#include +#include /* Forward declaration. */ struct ib_rbt_t; @@ -706,12 +708,106 @@ struct dict_foreign_t{ does not generate new indexes implicitly */ dict_index_t* referenced_index;/*!< referenced index */ - UT_LIST_NODE_T(dict_foreign_t) - foreign_list; /*!< list node for foreign keys of the - table */ - UT_LIST_NODE_T(dict_foreign_t) - referenced_list;/*!< list node for referenced - keys of the table */ +}; + +/** 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 +strict weak ordering it defines, and false otherwise. */ +struct dict_foreign_compare { + + bool operator()( + const dict_foreign_t* lhs, + const dict_foreign_t* rhs) const + { + return(ut_strcmp(lhs->id, rhs->id) < 0); + } +}; + +/** A function object to find a foreign key with the given index as the +referenced index. Return the foreign key with matching criteria or NULL */ +struct dict_foreign_with_index { + + dict_foreign_with_index(const dict_index_t* index) + : m_index(index) + {} + + bool operator()(const dict_foreign_t* foreign) const + { + return(foreign->referenced_index == m_index); + } + + const dict_index_t* m_index; +}; + +/* A function object to check if the foreign constraint is between different +tables. Returns true if foreign key constraint is between different tables, +false otherwise. */ +struct dict_foreign_different_tables { + + bool operator()(const dict_foreign_t* foreign) const + { + return(foreign->foreign_table != foreign->referenced_table); + } +}; + +/** A function object to check if the foreign key constraint has the same +name as given. If the full name of the foreign key constraint doesn't match, +then, check if removing the database name from the foreign key constraint +matches. Return true if it matches, false otherwise. */ +struct dict_foreign_matches_id { + + dict_foreign_matches_id(const char* id) + : m_id(id) + {} + + bool operator()(const dict_foreign_t* foreign) const + { + if (0 == innobase_strcasecmp(foreign->id, m_id)) { + return(true); + } + if (const char* pos = strchr(foreign->id, '/')) { + if (0 == innobase_strcasecmp(m_id, pos + 1)) { + return(true); + } + } + return(false); + } + + const char* m_id; +}; + +typedef std::set dict_foreign_set; + +/*********************************************************************//** +Frees a foreign key struct. */ +inline +void +dict_foreign_free( +/*==============*/ + dict_foreign_t* foreign) /*!< in, own: foreign key struct */ +{ + mem_heap_free(foreign->heap); +} + +/** The destructor will free all the foreign key constraints in the set +by calling dict_foreign_free() on each of the foreign key constraints. +This is used to free the allocated memory when a local set goes out +of scope. */ +struct dict_foreign_set_free { + + dict_foreign_set_free(const dict_foreign_set& foreign_set) + : m_foreign_set(foreign_set) + {} + + ~dict_foreign_set_free() + { + std::for_each(m_foreign_set.begin(), + m_foreign_set.end(), + dict_foreign_free); + } + + const dict_foreign_set& m_foreign_set; }; /** The flags for ON_UPDATE and ON_DELETE can be ORed; the default is that @@ -733,6 +829,8 @@ the table, DML from memcached will be blocked. */ /** Data structure for a database table. Most fields will be initialized to 0, NULL or FALSE in dict_mem_table_create(). */ struct dict_table_t{ + + table_id_t id; /*!< id of the table */ mem_heap_t* heap; /*!< memory heap */ char* name; /*!< table name */ @@ -787,13 +885,16 @@ struct dict_table_t{ hash_node_t id_hash; /*!< hash chain node */ UT_LIST_BASE_NODE_T(dict_index_t) indexes; /*!< list of indexes of the table */ - UT_LIST_BASE_NODE_T(dict_foreign_t) - foreign_list;/*!< list of foreign key constraints + + dict_foreign_set foreign_set; + /*!< set of foreign key constraints in the table; these refer to columns in other tables */ - UT_LIST_BASE_NODE_T(dict_foreign_t) - referenced_list;/*!< list of foreign key constraints + + dict_foreign_set referenced_set; + /*!< list of foreign key constraints which refer to this table */ + UT_LIST_NODE_T(dict_table_t) table_LRU; /*!< node of the LRU list of tables */ unsigned fk_max_recusive_level:8; @@ -1035,6 +1136,19 @@ struct dict_table_t{ #endif /* UNIV_DEBUG */ }; +/** A function object to add the foreign key constraint to the referenced set +of the referenced table, if it exists in the dictionary cache. */ +struct dict_foreign_add_to_referenced_table { + void operator()(dict_foreign_t* foreign) const + { + if (dict_table_t* table = foreign->referenced_table) { + std::pair ret + = table->referenced_set.insert(foreign); + ut_a(ret.second); + } + } +}; + #ifndef UNIV_NONINL #include "dict0mem.ic" #endif diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 72b4cfd3bfb..b607ca36d70 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -48,7 +48,7 @@ struct fil_space_t; typedef std::list space_name_list_t; /** When mysqld is run, the default directory "." is the mysqld datadir, -but in the MySQL Embedded Server Library and ibbackup it is not the default +but in the MySQL Embedded Server Library and mysqlbackup it is not the default directory, and we must set the base file path explicitly */ extern const char* fil_path_to_mysql_datadir; @@ -426,8 +426,8 @@ exists and the space id in it matches. Replays the create operation if a file at that path does not exist yet. If the database directory for the file to be created does not exist, then we create the directory, too. -Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the -datadir that we should use in replaying the file operations. +Note that mysqlbackup --apply-log sets fil_path_to_mysql_datadir to point to +the datadir that we should use in replaying the file operations. @return end of log record, or NULL if the record was not completely contained between ptr and end_ptr */ UNIV_INTERN @@ -680,9 +680,9 @@ fil_space_for_table_exists_in_mem( #else /* !UNIV_HOTBACKUP */ /********************************************************************//** Extends all tablespaces to the size stored in the space header. During the -ibbackup --apply-log phase we extended the spaces on-demand so that log records -could be appllied, but that may have left spaces still too small compared to -the size stored in the space header. */ +mysqlbackup --apply-log phase we extended the spaces on-demand so that log +records could be appllied, but that may have left spaces still too small +compared to the size stored in the space header. */ UNIV_INTERN void fil_extend_tablespaces_to_stored_len(void); diff --git a/storage/innobase/include/fts0ast.h b/storage/innobase/include/fts0ast.h index c0aac6d8e4c..50ee587e282 100644 --- a/storage/innobase/include/fts0ast.h +++ b/storage/innobase/include/fts0ast.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 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 @@ -76,6 +76,7 @@ enum fts_ast_oper_t { struct fts_lexer_t; struct fts_ast_node_t; struct fts_ast_state_t; +struct fts_ast_string_t; typedef dberr_t (*fts_ast_callback)(fts_ast_oper_t, fts_ast_node_t*, void*); @@ -101,16 +102,16 @@ extern fts_ast_node_t* fts_ast_create_node_term( /*=====================*/ - void* arg, /*!< in: ast state */ - const char* ptr); /*!< in: term string */ + void* arg, /*!< in: ast state */ + const fts_ast_string_t* ptr); /*!< in: term string */ /******************************************************************** Create an AST text node */ extern fts_ast_node_t* fts_ast_create_node_text( /*=====================*/ - void* arg, /*!< in: ast state */ - const char* ptr); /*!< in: text string */ + void* arg, /*!< in: ast state */ + const fts_ast_string_t* ptr); /*!< in: text string */ /******************************************************************** Create an AST expr list node */ extern @@ -233,16 +234,66 @@ fts_lexer_free( free */ __attribute__((nonnull)); +/** +Create an ast string object, with NUL-terminator, so the string +has one more byte than len +@param[in] str pointer to string +@param[in] len length of the string +@return ast string with NUL-terminator */ +UNIV_INTERN +fts_ast_string_t* +fts_ast_string_create( + const byte* str, + ulint len); + +/** +Free an ast string instance +@param[in,out] ast_str string to free */ +UNIV_INTERN +void +fts_ast_string_free( + fts_ast_string_t* ast_str); + +/** +Translate ast string of type FTS_AST_NUMB to unsigned long by strtoul +@param[in] str string to translate +@param[in] base the base +@return translated number */ +UNIV_INTERN +ulint +fts_ast_string_to_ul( + const fts_ast_string_t* ast_str, + int base); + +/** +Print the ast string +@param[in] str string to print */ +UNIV_INTERN +void +fts_ast_string_print( + const fts_ast_string_t* ast_str); + +/* String of length len. +We always store the string of length len with a terminating '\0', +regardless of there is any 0x00 in the string itself */ +struct fts_ast_string_t { + /*!< Pointer to string. */ + byte* str; + + /*!< Length of the string. */ + ulint len; +}; + /* Query term type */ struct fts_ast_term_t { - byte* ptr; /*!< Pointer to term string.*/ - ibool wildcard; /*!< TRUE if wild card set.*/ + fts_ast_string_t* ptr; /*!< Pointer to term string.*/ + ibool wildcard; /*!< TRUE if wild card set.*/ }; /* Query text type */ struct fts_ast_text_t { - byte* ptr; /*!< Pointer to term string.*/ - ulint distance; /*!< > 0 if proximity distance + fts_ast_string_t* ptr; /*!< Pointer to text string.*/ + ulint distance; /*!< > 0 if proximity distance set */ }; diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 5bea5bc0e97..a2996ecacc8 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -745,6 +745,7 @@ void fts_savepoint_take( /*===============*/ trx_t* trx, /*!< in: transaction */ + fts_trx_t* fts_trx, /*!< in: fts transaction */ const char* name) /*!< in: savepoint name */ __attribute__((nonnull)); /**********************************************************************//** diff --git a/storage/innobase/include/fts0pars.h b/storage/innobase/include/fts0pars.h index 50f636944e5..8108e811599 100644 --- a/storage/innobase/include/fts0pars.h +++ b/storage/innobase/include/fts0pars.h @@ -53,9 +53,9 @@ typedef union YYSTYPE /* Line 2068 of yacc.c */ #line 61 "fts0pars.y" - int oper; - char* token; - fts_ast_node_t* node; + int oper; + fts_ast_string_t* token; + fts_ast_node_t* node; diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 0182d9b00b6..ad9710b1870 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -656,13 +656,13 @@ extern log_t* log_sys; megabyte. This information might have been used - since ibbackup version 0.35 but + since mysqlbackup version 0.35 but before 1.41 to decide if unused ends of non-auto-extending data files in space 0 can be truncated. This information was made obsolete - by ibbackup --compress. */ + by mysqlbackup --compress. */ #define LOG_CHECKPOINT_FSP_MAGIC_N (12 + LOG_CHECKPOINT_ARRAY_END) /*!< Not used (0); This magic number tells if the @@ -691,7 +691,7 @@ extern log_t* log_sys; /* a 32-byte field which contains the string 'ibbackup' and the creation time if the log file was - created by ibbackup --restore; + created by mysqlbackup --restore; when mysqld is first time started on the restored database, it can print helpful info for the user */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 8e2948e2d68..5fea0023220 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -126,7 +126,7 @@ enum os_file_create_t { #define OS_FILE_READ_ONLY 333 #define OS_FILE_READ_WRITE 444 -#define OS_FILE_READ_ALLOW_DELETE 555 /* for ibbackup */ +#define OS_FILE_READ_ALLOW_DELETE 555 /* for mysqlbackup */ /* Options for file_create */ #define OS_FILE_AIO 61 diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h index f62278a1259..534b9940e84 100644 --- a/storage/innobase/include/os0sync.h +++ b/storage/innobase/include/os0sync.h @@ -357,6 +357,10 @@ Atomic compare-and-swap and increment for InnoDB. */ # define HAVE_ATOMIC_BUILTINS +# ifdef HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE +# define HAVE_ATOMIC_BUILTINS_BYTE +# endif + # ifdef HAVE_IB_GCC_ATOMIC_BUILTINS_64 # define HAVE_ATOMIC_BUILTINS_64 # endif @@ -440,6 +444,7 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ #elif defined(HAVE_IB_SOLARIS_ATOMICS) # define HAVE_ATOMIC_BUILTINS +# define HAVE_ATOMIC_BUILTINS_BYTE # define HAVE_ATOMIC_BUILTINS_64 /* If not compiling with GCC or GCC doesn't support the atomic @@ -524,6 +529,7 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ #elif defined(HAVE_WINDOWS_ATOMICS) # define HAVE_ATOMIC_BUILTINS +# define HAVE_ATOMIC_BUILTINS_BYTE # ifndef _WIN32 # define HAVE_ATOMIC_BUILTINS_64 @@ -695,7 +701,15 @@ for synchronization */ } while (0); /** barrier definitions for memory ordering */ -#ifdef HAVE_IB_GCC_ATOMIC_THREAD_FENCE +#if defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64 || defined __WIN__ +/* Performance regression was observed at some conditions for Intel +architecture. Disable memory barrier for Intel architecture for now. */ +# define os_rmb do { } while(0) +# define os_wmb do { } while(0) +# define os_isync do { } while(0) +# define IB_MEMORY_BARRIER_STARTUP_MSG \ + "Memory barrier is not used" +#elif defined(HAVE_IB_GCC_ATOMIC_THREAD_FENCE) # define HAVE_MEMORY_BARRIER # define os_rmb __atomic_thread_fence(__ATOMIC_ACQUIRE) # define os_wmb __atomic_thread_fence(__ATOMIC_RELEASE) @@ -723,7 +737,7 @@ for synchronization */ # define os_wmb __machine_w_barrier() # define os_isync os_rmb; os_wmb # define IB_MEMORY_BARRIER_STARTUP_MSG \ - "Soralis memory ordering functions are used for memory barrier" + "Solaris memory ordering functions are used for memory barrier" #elif defined(HAVE_WINDOWS_MM_FENCE) # define HAVE_MEMORY_BARRIER diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index 7ea910b4719..bb05ae7daf1 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -93,6 +93,7 @@ rw_lock_set_waiter_flag( (void) os_compare_and_swap_ulint(&lock->waiters, 0, 1); #else /* INNODB_RW_LOCKS_USE_ATOMICS */ lock->waiters = 1; + os_wmb; #endif /* INNODB_RW_LOCKS_USE_ATOMICS */ } @@ -110,6 +111,7 @@ rw_lock_reset_waiter_flag( (void) os_compare_and_swap_ulint(&lock->waiters, 1, 0); #else /* INNODB_RW_LOCKS_USE_ATOMICS */ lock->waiters = 0; + os_wmb; #endif /* INNODB_RW_LOCKS_USE_ATOMICS */ } @@ -200,13 +202,16 @@ rw_lock_lock_word_decr( { #ifdef INNODB_RW_LOCKS_USE_ATOMICS lint local_lock_word; - os_rmb; - while ((local_lock_word= lock->lock_word) > 0) { + + os_rmb; + local_lock_word = lock->lock_word; + while (local_lock_word > 0) { if (os_compare_and_swap_lint(&lock->lock_word, local_lock_word, local_lock_word - amount)) { return(TRUE); } + local_lock_word = lock->lock_word; } return(FALSE); #else /* INNODB_RW_LOCKS_USE_ATOMICS */ diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 7b00e16476b..82fb353a41b 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -49,6 +49,8 @@ extern "C" my_bool timed_mutexes; #ifdef HAVE_WINDOWS_ATOMICS typedef LONG lock_word_t; /*!< On Windows, InterlockedExchange operates on LONG variable */ +#elif defined(HAVE_ATOMIC_BUILTINS) && !defined(HAVE_ATOMIC_BUILTINS_BYTE) +typedef ulint lock_word_t; #else typedef byte lock_word_t; #endif diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic index 9c7f3d2cd4b..687f7ee5142 100644 --- a/storage/innobase/include/sync0sync.ic +++ b/storage/innobase/include/sync0sync.ic @@ -80,7 +80,11 @@ ib_mutex_test_and_set( ib_mutex_t* mutex) /*!< in: mutex */ { #if defined(HAVE_ATOMIC_BUILTINS) +# if defined(HAVE_ATOMIC_BUILTINS_BYTE) return(os_atomic_test_and_set_byte(&mutex->lock_word, 1)); +# else + return(os_atomic_test_and_set_ulint(&mutex->lock_word, 1)); +# endif #else ibool ret; @@ -92,7 +96,7 @@ ib_mutex_test_and_set( ut_a(mutex->lock_word == 0); mutex->lock_word = 1; - os_wmb; + os_wmb; } return((byte) ret); diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index bc359746a0b..2635fca3220 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -44,7 +44,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 19 +#define INNODB_VERSION_BUGFIX 20 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 5282e45dddb..53794a0d773 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -1249,7 +1249,7 @@ log_group_file_header_flush( mach_write_to_4(buf + LOG_GROUP_ID, group->id); mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn); - /* Wipe over possible label of ibbackup --restore */ + /* Wipe over possible label of mysqlbackup --restore */ memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, " ", 4); dest_offset = nth_file * group->file_size; @@ -1996,7 +1996,7 @@ log_reset_first_header_and_checkpoint( lsn = start + LOG_BLOCK_HDR_SIZE; - /* Write the label of ibbackup --restore */ + /* Write the label of mysqlbackup --restore */ strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup "); ut_sprintf_timestamp((char*) hdr_buf diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index a521e098598..4fe9620ccaa 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -59,7 +59,7 @@ Created 9/20/1997 Heikki Tuuri /** This is set to FALSE if the backup was originally taken with the -ibbackup --include regexp option: then we do not want to create tables in +mysqlbackup --include regexp option: then we do not want to create tables in directories which were not included */ UNIV_INTERN ibool recv_replay_file_ops = TRUE; #endif /* !UNIV_HOTBACKUP */ @@ -2056,7 +2056,7 @@ recv_apply_log_recs_for_backup(void) /* Extend the tablespace's last file if the page_no does not fall inside its bounds; we assume the last - file is auto-extending, and ibbackup copied the file + file is auto-extending, and mysqlbackup copied the file when it still was smaller */ success = fil_extend_space_to_desired_size( @@ -2427,10 +2427,10 @@ loop: #ifdef UNIV_HOTBACKUP if (recv_replay_file_ops) { - /* In ibbackup --apply-log, replay an .ibd file - operation, if possible; note that - fil_path_to_mysql_datadir is set in ibbackup to - point to the datadir we should use there */ + /* In mysqlbackup --apply-log, replay an .ibd + file operation, if possible; note that + fil_path_to_mysql_datadir is set in mysqlbackup + to point to the datadir we should use there */ if (NULL == fil_op_log_parse_or_replay( body, end_ptr, type, @@ -3090,17 +3090,17 @@ recv_recovery_from_checkpoint_start_func( if (srv_read_only_mode) { ib_logf(IB_LOG_LEVEL_ERROR, - "Cannot restore from ibbackup, InnoDB running " - "in read-only mode!"); + "Cannot restore from mysqlbackup, InnoDB " + "running in read-only mode!"); return(DB_ERROR); } - /* This log file was created by ibbackup --restore: print + /* This log file was created by mysqlbackup --restore: print a note to the user about it */ ib_logf(IB_LOG_LEVEL_INFO, - "The log file was created by ibbackup --apply-log " + "The log file was created by mysqlbackup --apply-log " "at %s. The following crash recovery is part of a " "normal restore.", log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP); diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 3972ef4afe9..162c51425f4 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -1816,7 +1816,7 @@ os_file_delete_if_exists_func( bool ret; ulint count = 0; loop: - /* In Windows, deleting an .ibd file may fail if ibbackup is copying + /* In Windows, deleting an .ibd file may fail if mysqlbackup is copying it */ ret = DeleteFile((LPCTSTR) name); @@ -1841,7 +1841,7 @@ loop: ib_logf(IB_LOG_LEVEL_WARN, "Delete of file %s failed.", name); } - os_thread_sleep(1000000); /* sleep for a second */ + os_thread_sleep(500000); /* sleep for 0.5 second */ if (count > 2000) { @@ -1878,7 +1878,7 @@ os_file_delete_func( BOOL ret; ulint count = 0; loop: - /* In Windows, deleting an .ibd file may fail if ibbackup is copying + /* In Windows, deleting an .ibd file may fail if mysqlbackup is copying it */ ret = DeleteFile((LPCTSTR) name); @@ -1901,7 +1901,7 @@ loop: fprintf(stderr, "InnoDB: Warning: cannot delete file %s\n" - "InnoDB: Are you running ibbackup" + "InnoDB: Are you running mysqlbackup" " to back up the file?\n", name); } diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index 4b19a35925e..6989953cb0c 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -3278,24 +3278,8 @@ page_zip_validate_low( temp_page_buf = static_cast(ut_malloc(2 * UNIV_PAGE_SIZE)); temp_page = static_cast(ut_align(temp_page_buf, UNIV_PAGE_SIZE)); -#ifdef UNIV_DEBUG_VALGRIND - /* Get detailed information on the valid bits in case the - UNIV_MEM_ASSERT_RW() checks fail. The v-bits of page[], - page_zip->data[] or page_zip could be viewed at temp_page[] or - temp_page_zip in a debugger when running valgrind --db-attach. */ - (void) VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE); UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE); -# if UNIV_WORD_SIZE == 4 - VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip); - /* On 32-bit systems, there is no padding in page_zip_des_t. - On other systems, Valgrind could complain about uninitialized - pad bytes. */ - UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip); -# endif - (void) VALGRIND_GET_VBITS(page_zip->data, temp_page, - page_zip_get_size(page_zip)); UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip)); -#endif /* UNIV_DEBUG_VALGRIND */ temp_page_zip = *page_zip; valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE); diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 834dfe6f8eb..49bb5980548 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1711,12 +1711,11 @@ do_possible_lock_wait: table case (check_ref == 0), since MDL lock will prevent concurrent DDL and DML on the same table */ if (!check_ref) { - for (const dict_foreign_t* check_foreign - = UT_LIST_GET_FIRST( table->referenced_list); - check_foreign; - check_foreign = UT_LIST_GET_NEXT( - referenced_list, check_foreign)) { - if (check_foreign == foreign) { + for (dict_foreign_set::iterator it + = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + if (*it == foreign) { verified = true; break; } @@ -1764,12 +1763,15 @@ row_ins_check_foreign_constraints( trx = thr_get_trx(thr); - foreign = UT_LIST_GET_FIRST(table->foreign_list); - DEBUG_SYNC_C_IF_THD(thr_get_trx(thr)->mysql_thd, "foreign_constraint_check_for_ins"); - while (foreign) { + for (dict_foreign_set::iterator it = table->foreign_set.begin(); + it != table->foreign_set.end(); + ++it) { + + foreign = *it; + if (foreign->foreign_index == index) { dict_table_t* ref_table = NULL; dict_table_t* foreign_table = foreign->foreign_table; @@ -1825,8 +1827,6 @@ row_ins_check_foreign_constraints( return(err); } } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); } return(DB_SUCCESS); @@ -2858,7 +2858,7 @@ row_ins_clust_index_entry( dberr_t err; ulint n_uniq; - if (UT_LIST_GET_FIRST(index->table->foreign_list)) { + if (!index->table->foreign_set.empty()) { err = row_ins_check_foreign_constraints( index->table, index, entry, thr); if (err != DB_SUCCESS) { @@ -2916,7 +2916,7 @@ row_ins_sec_index_entry( mem_heap_t* offsets_heap; mem_heap_t* heap; - if (UT_LIST_GET_FIRST(index->table->foreign_list)) { + if (!index->table->foreign_set.empty()) { err = row_ins_check_foreign_constraints(index->table, index, entry, thr); if (err != DB_SUCCESS) { diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index dd7af8a3526..ca70543a97b 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 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 @@ -63,6 +63,7 @@ Created 9/17/2000 Heikki Tuuri #include "m_string.h" #include "my_sys.h" #include "ha_prototypes.h" +#include /** Provide optional 4.x backwards compatibility for 5.0 and above */ UNIV_INTERN ibool row_rollback_on_timeout = FALSE; @@ -1573,8 +1574,6 @@ init_fts_doc_id_for_ref( { dict_foreign_t* foreign; - foreign = UT_LIST_GET_FIRST(table->referenced_list); - table->fk_max_recusive_level = 0; (*depth)++; @@ -1586,17 +1585,25 @@ init_fts_doc_id_for_ref( /* Loop through this table's referenced list and also recursively traverse each table's foreign table list */ - while (foreign && foreign->foreign_table) { - if (foreign->foreign_table->fts) { + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + + foreign = *it; + + if (foreign->foreign_table == NULL) { + break; + } + + if (foreign->foreign_table->fts != NULL) { fts_init_doc_id(foreign->foreign_table); } - if (UT_LIST_GET_LEN(foreign->foreign_table->referenced_list) - > 0 && foreign->foreign_table != table) { - init_fts_doc_id_for_ref(foreign->foreign_table, depth); + if (!foreign->foreign_table->referenced_set.empty() + && foreign->foreign_table != table) { + init_fts_doc_id_for_ref( + foreign->foreign_table, depth); } - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); } } @@ -2825,43 +2832,47 @@ row_discard_tablespace_foreign_key_checks( const trx_t* trx, /*!< in: transaction handle */ const dict_table_t* table) /*!< in: table to be discarded */ { - const dict_foreign_t* foreign; + + if (srv_read_only_mode || !trx->check_foreigns) { + return(DB_SUCCESS); + } /* Check if the table is referenced by foreign key constraints from some other table (not the table itself) */ + dict_foreign_set::iterator it + = std::find_if(table->referenced_set.begin(), + table->referenced_set.end(), + dict_foreign_different_tables()); - for (foreign = UT_LIST_GET_FIRST(table->referenced_list); - foreign && foreign->foreign_table == table; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { - + if (it == table->referenced_set.end()) { + return(DB_SUCCESS); } - if (!srv_read_only_mode && foreign && trx->check_foreigns) { + const dict_foreign_t* foreign = *it; + FILE* ef = dict_foreign_err_file; - FILE* ef = dict_foreign_err_file; + ut_ad(foreign->foreign_table != table); + ut_ad(foreign->referenced_table == table); - /* We only allow discarding a referenced table if - FOREIGN_KEY_CHECKS is set to 0 */ + /* We only allow discarding a referenced table if + FOREIGN_KEY_CHECKS is set to 0 */ - mutex_enter(&dict_foreign_err_mutex); + mutex_enter(&dict_foreign_err_mutex); - rewind(ef); + rewind(ef); - ut_print_timestamp(ef); + ut_print_timestamp(ef); - fputs(" Cannot DISCARD table ", ef); - ut_print_name(stderr, trx, TRUE, table->name); - fputs("\n" - "because it is referenced by ", ef); - ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name); - putc('\n', ef); + fputs(" Cannot DISCARD table ", ef); + ut_print_name(stderr, trx, TRUE, table->name); + fputs("\n" + "because it is referenced by ", ef); + ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name); + putc('\n', ef); - mutex_exit(&dict_foreign_err_mutex); + mutex_exit(&dict_foreign_err_mutex); - return(DB_CANNOT_DROP_CONSTRAINT); - } - - return(DB_SUCCESS); + return(DB_CANNOT_DROP_CONSTRAINT); } /*********************************************************************//** @@ -3164,7 +3175,6 @@ row_truncate_table_for_mysql( dict_table_t* table, /*!< in: table handle */ trx_t* trx) /*!< in: transaction handle */ { - dict_foreign_t* foreign; dberr_t err; mem_heap_t* heap; byte* buf; @@ -3256,18 +3266,17 @@ row_truncate_table_for_mysql( /* Check if the table is referenced by foreign key constraints from some other table (not the table itself) */ - for (foreign = UT_LIST_GET_FIRST(table->referenced_list); - foreign != 0 && foreign->foreign_table == table; - foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { - - /* Do nothing. */ - } + dict_foreign_set::iterator it + = std::find_if(table->referenced_set.begin(), + table->referenced_set.end(), + dict_foreign_different_tables()); if (!srv_read_only_mode - && foreign + && it != table->referenced_set.end() && trx->check_foreigns) { - FILE* ef = dict_foreign_err_file; + FILE* ef = dict_foreign_err_file; + dict_foreign_t* foreign = *it; /* We only allow truncating a referenced table if FOREIGN_KEY_CHECKS is set to 0 */ @@ -3868,42 +3877,45 @@ row_drop_table_for_mysql( /* Check if the table is referenced by foreign key constraints from some other table (not the table itself) */ - foreign = UT_LIST_GET_FIRST(table->referenced_list); + if (!srv_read_only_mode && trx->check_foreigns) { - while (foreign && foreign->foreign_table == table) { -check_next_foreign: - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } + for (dict_foreign_set::iterator it + = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { - if (!srv_read_only_mode - && foreign - && trx->check_foreigns - && !(drop_db && dict_tables_have_same_db( - name, foreign->foreign_table_name_lookup))) { - FILE* ef = dict_foreign_err_file; + foreign = *it; - /* We only allow dropping a referenced table if - FOREIGN_KEY_CHECKS is set to 0 */ + const bool ref_ok = drop_db + && dict_tables_have_same_db( + name, + foreign->foreign_table_name_lookup); - err = DB_CANNOT_DROP_CONSTRAINT; + if (foreign->foreign_table != table && !ref_ok) { - mutex_enter(&dict_foreign_err_mutex); - rewind(ef); - ut_print_timestamp(ef); + FILE* ef = dict_foreign_err_file; - fputs(" Cannot drop table ", ef); - ut_print_name(ef, trx, TRUE, name); - fputs("\n" - "because it is referenced by ", ef); - ut_print_name(ef, trx, TRUE, foreign->foreign_table_name); - putc('\n', ef); - mutex_exit(&dict_foreign_err_mutex); + /* We only allow dropping a referenced table + if FOREIGN_KEY_CHECKS is set to 0 */ - goto funct_exit; - } + err = DB_CANNOT_DROP_CONSTRAINT; - if (foreign && trx->check_foreigns) { - goto check_next_foreign; + mutex_enter(&dict_foreign_err_mutex); + rewind(ef); + ut_print_timestamp(ef); + + fputs(" Cannot drop table ", ef); + ut_print_name(ef, trx, TRUE, name); + fputs("\n" + "because it is referenced by ", ef); + ut_print_name(ef, trx, TRUE, + foreign->foreign_table_name); + putc('\n', ef); + mutex_exit(&dict_foreign_err_mutex); + + goto funct_exit; + } + } } /* TODO: could we replace the counter n_foreign_key_checks_running diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index fb626519132..db810e28735 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -51,7 +51,7 @@ Created 12/27/1996 Heikki Tuuri #include "pars0sym.h" #include "eval0eval.h" #include "buf0lru.h" - +#include /* What kind of latch and lock can we assume when the control comes to ------------------------------------------------------------------- @@ -136,12 +136,10 @@ row_upd_index_is_referenced( trx_t* trx) /*!< in: transaction */ { dict_table_t* table = index->table; - dict_foreign_t* foreign; ibool froze_data_dict = FALSE; ibool is_referenced = FALSE; - if (!UT_LIST_GET_FIRST(table->referenced_list)) { - + if (table->referenced_set.empty()) { return(FALSE); } @@ -150,19 +148,13 @@ row_upd_index_is_referenced( froze_data_dict = TRUE; } - foreign = UT_LIST_GET_FIRST(table->referenced_list); + dict_foreign_set::iterator it + = std::find_if(table->referenced_set.begin(), + table->referenced_set.end(), + dict_foreign_with_index(index)); - while (foreign) { - if (foreign->referenced_index == index) { + is_referenced = (it != table->referenced_set.end()); - is_referenced = TRUE; - goto func_exit; - } - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } - -func_exit: if (froze_data_dict) { row_mysql_unfreeze_data_dictionary(trx); } @@ -200,7 +192,7 @@ row_upd_check_references_constraints( dberr_t err; ibool got_s_lock = FALSE; - if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) { + if (table->referenced_set.empty()) { return(DB_SUCCESS); } @@ -227,9 +219,13 @@ row_upd_check_references_constraints( } run_again: - foreign = UT_LIST_GET_FIRST(table->referenced_list); - while (foreign) { + for (dict_foreign_set::iterator it = table->referenced_set.begin(); + it != table->referenced_set.end(); + ++it) { + + foreign = *it; + /* Note that we may have an update which updates the index record, but does NOT update the first fields which are referenced in a foreign key constraint. Then the update does @@ -282,8 +278,6 @@ run_again: goto func_exit; } } - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); } err = DB_SUCCESS; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 8208d2d46e7..d1be5be9238 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1647,6 +1647,19 @@ innobase_start_or_create_for_mysql(void) ib_logf(IB_LOG_LEVEL_INFO, "" IB_ATOMICS_STARTUP_MSG ""); + ib_logf(IB_LOG_LEVEL_INFO, + "" IB_MEMORY_BARRIER_STARTUP_MSG ""); + +#ifndef HAVE_MEMORY_BARRIER +#if defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64 || defined __WIN__ +#else + ib_logf(IB_LOG_LEVEL_WARN, + "MySQL was built without a memory barrier capability on this" + " architecture, which might allow a mutex/rw_lock violation" + " under high thread concurrency. This may cause a hang."); +#endif /* IA32 or AMD64 */ +#endif /* HAVE_MEMORY_BARRIER */ + ib_logf(IB_LOG_LEVEL_INFO, "Compressed tables use zlib " ZLIB_VERSION #ifdef UNIV_ZIP_DEBUG @@ -2631,13 +2644,6 @@ files_checked: srv_undo_logs = ULONG_UNDEFINED; } - /* Flush the changes made to TRX_SYS_PAGE by trx_sys_create_rsegs()*/ - if (!srv_force_recovery && !srv_read_only_mode) { - bool success = buf_flush_list(ULINT_MAX, LSN_MAX, NULL); - ut_a(success); - buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); - } - if (!srv_read_only_mode) { /* Create the thread which watches the timeouts for lock waits */ diff --git a/storage/innobase/sync/sync0arr.cc b/storage/innobase/sync/sync0arr.cc index 6fad5f7d9ba..f643e5b794f 100644 --- a/storage/innobase/sync/sync0arr.cc +++ b/storage/innobase/sync/sync0arr.cc @@ -749,6 +749,7 @@ sync_arr_cell_can_wake_up( mutex = static_cast(cell->wait_object); + os_rmb; if (mutex_get_lock_word(mutex) == 0) { return(TRUE); @@ -758,7 +759,7 @@ sync_arr_cell_can_wake_up( lock = static_cast(cell->wait_object); - os_rmb; + os_rmb; if (lock->lock_word > 0) { /* Either unlocked or only read locked. */ @@ -770,7 +771,7 @@ sync_arr_cell_can_wake_up( lock = static_cast(cell->wait_object); /* lock_word == 0 means all readers have left */ - os_rmb; + os_rmb; if (lock->lock_word == 0) { return(TRUE); @@ -779,7 +780,7 @@ sync_arr_cell_can_wake_up( lock = static_cast(cell->wait_object); /* lock_word > 0 means no writer or reserved writer */ - os_rmb; + os_rmb; if (lock->lock_word > 0) { return(TRUE); diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc index 49d2a2e21ea..8a211d81af5 100644 --- a/storage/innobase/sync/sync0rw.cc +++ b/storage/innobase/sync/sync0rw.cc @@ -388,7 +388,7 @@ lock_loop: } HMT_medium(); - if (lock->lock_word <= 0) { + if (i >= SYNC_SPIN_ROUNDS) { os_thread_yield(); } @@ -475,9 +475,9 @@ rw_lock_x_lock_wait( counter_index = (size_t) os_thread_get_curr_id(); + os_rmb; ut_ad(lock->lock_word <= 0); - os_rmb; HMT_low(); while (lock->lock_word < 0) { if (srv_spin_wait_delay) { @@ -564,8 +564,11 @@ rw_lock_x_lock_low( } else { os_thread_id_t thread_id = os_thread_get_curr_id(); - if (!pass) + + if (!pass) { os_rmb; + } + /* Decrement failed: relock or failed lock */ if (!pass && lock->recursive && os_thread_eq(lock->writer_thread, thread_id)) { @@ -657,7 +660,7 @@ lock_loop: os_rmb; } HMT_medium(); - if (i == SYNC_SPIN_ROUNDS) { + if (i >= SYNC_SPIN_ROUNDS) { os_thread_yield(); } else { goto lock_loop; diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index cc852b99497..6494191bfe9 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -127,7 +127,7 @@ it and did not see the waiters byte set to 1, a case which would lead the other thread to an infinite wait. LEMMA 1: After a thread resets the event of a mutex (or rw_lock), some -======= +====== thread will eventually call os_event_set() on that particular event. Thus no infinite wait is possible in this case. @@ -140,7 +140,7 @@ os_event_set() with the mutex as an argument. Q.E.D. LEMMA 2: If an os_event_set() call is made after some thread has called -======= +====== the os_event_reset() and before it starts wait on that event, the call will not be lost to the second thread. This is true even if there is an intervening call to os_event_reset() by another thread. @@ -504,16 +504,16 @@ mutex_loop: spin_loop: HMT_low(); + os_rmb; while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } - os_rmb; // Ensure future reads sees new values i++; } HMT_medium(); - if (i == SYNC_SPIN_ROUNDS) { + if (i >= SYNC_SPIN_ROUNDS) { os_thread_yield(); } diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index fcf1c1cedf4..52830a77b12 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -952,7 +952,7 @@ trx_sys_print_mysql_binlog_offset_from_page( == TRX_SYS_MYSQL_LOG_MAGIC_N) { fprintf(stderr, - "ibbackup: Last MySQL binlog file position %lu %lu," + "mysqlbackup: Last MySQL binlog file position %lu %lu," " file name %s\n", (ulong) mach_read_from_4( sys_header + TRX_SYS_MYSQL_LOG_INFO @@ -1003,9 +1003,9 @@ trx_sys_read_file_format_id( ut_print_timestamp(stderr); fprintf(stderr, - " ibbackup: Error: trying to read system tablespace " - "file format,\n" - " ibbackup: but could not open the tablespace " + " mysqlbackup: Error: trying to read system " + "tablespace file format,\n" + " mysqlbackup: but could not open the tablespace " "file %s!\n", pathname); return(FALSE); } @@ -1022,9 +1022,9 @@ trx_sys_read_file_format_id( ut_print_timestamp(stderr); fprintf(stderr, - " ibbackup: Error: trying to read system tablespace " - "file format,\n" - " ibbackup: but failed to read the tablespace " + " mysqlbackup: Error: trying to read system " + "tablespace file format,\n" + " mysqlbackup: but failed to read the tablespace " "file %s!\n", pathname); os_file_close(file); @@ -1083,9 +1083,9 @@ trx_sys_read_pertable_file_format_id( ut_print_timestamp(stderr); fprintf(stderr, - " ibbackup: Error: trying to read per-table " + " mysqlbackup: Error: trying to read per-table " "tablespace format,\n" - " ibbackup: but could not open the tablespace " + " mysqlbackup: but could not open the tablespace " "file %s!\n", pathname); return(FALSE); @@ -1102,9 +1102,9 @@ trx_sys_read_pertable_file_format_id( ut_print_timestamp(stderr); fprintf(stderr, - " ibbackup: Error: trying to per-table data file " + " mysqlbackup: Error: trying to per-table data file " "format,\n" - " ibbackup: but failed to read the tablespace " + " mysqlbackup: but failed to read the tablespace " "file %s!\n", pathname); os_file_close(file);