From 993395bfa090266eb0ded41173130268a3ff01e7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 11 Sep 2014 10:13:35 +0200 Subject: [PATCH] 5.6.20 --- CMakeLists.txt | 56 ++++++- api/api0api.cc | 23 ++- btr/btr0cur.cc | 43 +++++ buf/buf0buf.cc | 8 +- buf/buf0lru.cc | 27 --- dict/dict0crea.cc | 44 +++-- dict/dict0dict.cc | 351 +++++++++++++++++++-------------------- dict/dict0mem.cc | 27 ++- fil/fil0fil.cc | 51 +++--- fts/fts0ast.cc | 136 +++++++++++---- fts/fts0blex.cc | 8 +- fts/fts0blex.l | 8 +- fts/fts0fts.cc | 46 ++++- fts/fts0pars.cc | 51 ++++-- fts/fts0pars.y | 22 +-- fts/fts0que.cc | 57 ++++--- fts/fts0tlex.cc | 6 +- fts/fts0tlex.l | 6 +- handler/ha_innodb.cc | 30 ++-- handler/handler0alter.cc | 70 ++++---- handler/i_s.cc | 12 +- include/buf0buf.h | 2 +- include/buf0buf.ic | 6 - include/dict0crea.h | 34 ++-- include/dict0mem.h | 134 +++++++++++++-- include/fil0fil.h | 12 +- include/fts0ast.h | 69 +++++++- include/fts0fts.h | 1 + include/fts0pars.h | 6 +- include/log0log.h | 6 +- include/os0file.h | 2 +- include/os0sync.h | 51 ++++++ include/sync0rw.ic | 7 +- include/sync0sync.h | 2 + include/sync0sync.ic | 9 + log/log0log.cc | 4 +- log/log0recv.cc | 20 +-- os/os0file.cc | 8 +- page/page0zip.cc | 16 -- row/row0ins.cc | 26 +-- row/row0mysql.cc | 152 +++++++++-------- row/row0upd.cc | 34 ++-- srv/srv0start.cc | 20 ++- sync/sync0arr.cc | 4 + sync/sync0rw.cc | 12 +- sync/sync0sync.cc | 5 +- trx/trx0sys.cc | 22 +-- 47 files changed, 1102 insertions(+), 644 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7daf2fa3c2..eeb53f96c9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,6 @@ IF(NOT CMAKE_CROSSCOMPILING) long x; long y; long res; - char c; x = 10; y = 123; @@ -87,6 +86,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); @@ -95,7 +104,7 @@ IF(NOT CMAKE_CROSSCOMPILING) } return(0); }" - HAVE_IB_GCC_ATOMIC_BUILTINS + HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE ) CHECK_C_SOURCE_RUNS( "#include @@ -117,16 +126,47 @@ IF(NOT CMAKE_CROSSCOMPILING) }" HAVE_IB_GCC_ATOMIC_BUILTINS_64 ) + CHECK_C_SOURCE_RUNS( + "#include + int main() + { + __sync_synchronize(); + return(0); + }" + HAVE_IB_GCC_SYNC_SYNCHRONISE + ) + CHECK_C_SOURCE_RUNS( + "#include + int main() + { + __atomic_thread_fence(__ATOMIC_ACQUIRE); + __atomic_thread_fence(__ATOMIC_RELEASE); + return(0); + }" + HAVE_IB_GCC_ATOMIC_THREAD_FENCE + ) ENDIF() 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() +IF(HAVE_IB_GCC_SYNC_SYNCHRONISE) + ADD_DEFINITIONS(-DHAVE_IB_GCC_SYNC_SYNCHRONISE=1) +ENDIF() + +IF(HAVE_IB_GCC_ATOMIC_THREAD_FENCE) + ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_THREAD_FENCE=1) +ENDIF() + # either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not IF(NOT CMAKE_CROSSCOMPILING) CHECK_C_SOURCE_RUNS( @@ -208,10 +248,21 @@ IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS") return(0); } " HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS) + CHECK_C_SOURCE_COMPILES( + "#include + int main() { + __machine_r_barrier(); + __machine_w_barrier(); + return(0); + }" + HAVE_IB_MACHINE_BARRIER_SOLARIS) ENDIF() IF(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS) ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_SOLARIS=1) ENDIF() + IF(HAVE_IB_MACHINE_BARRIER_SOLARIS) + ADD_DEFINITIONS(-DHAVE_IB_MACHINE_BARRIER_SOLARIS=1) + ENDIF() ENDIF() @@ -229,6 +280,7 @@ ENDIF() IF(MSVC) ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS) + ADD_DEFINITIONS(-DHAVE_WINDOWS_MM_FENCE) ENDIF() diff --git a/api/api0api.cc b/api/api0api.cc index bb65dd82216..a060cbc7270 100644 --- a/api/api0api.cc +++ b/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/btr/btr0cur.cc b/btr/btr0cur.cc index d1a0c64d2bf..29cf95f555c 100644 --- a/btr/btr0cur.cc +++ b/btr/btr0cur.cc @@ -2556,6 +2556,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 @@ -4377,6 +4402,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)); @@ -4396,6 +4422,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/buf/buf0buf.cc b/buf/buf0buf.cc index 4bae962e7d3..6f00d2e43b5 100644 --- a/buf/buf0buf.cc +++ b/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/buf/buf0lru.cc b/buf/buf0lru.cc index ec30c063a72..a1618020bca 100644 --- a/buf/buf0lru.cc +++ b/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/dict/dict0crea.cc b/dict/dict0crea.cc index ff892749d4f..30523ff2af4 100644 --- a/dict/dict0crea.cc +++ b/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/dict/dict0dict.cc b/dict/dict0dict.cc index 90f7d7be871..9eeea9c3842 100644 --- a/dict/dict0dict.cc +++ b/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" @@ -1246,8 +1247,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; @@ -1463,6 +1464,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 */ @@ -1637,27 +1654,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); } @@ -1666,9 +1681,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; @@ -1818,12 +1843,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)) { @@ -1893,27 +1924,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; } @@ -3129,7 +3150,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()); } /*********************************************************************//** @@ -3149,9 +3170,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) { @@ -3180,9 +3203,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) { @@ -3193,17 +3218,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 @@ -3215,16 +3229,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); @@ -3238,33 +3248,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); @@ -3402,11 +3400,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) { @@ -3443,9 +3441,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; } @@ -3474,10 +3475,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); @@ -3488,9 +3492,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 @@ -4068,9 +4074,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, @@ -4089,8 +4098,6 @@ dict_table_get_highest_foreign_id( } } } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); } return(biggest_id); @@ -4151,6 +4158,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; @@ -4169,6 +4177,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))); @@ -4233,6 +4243,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 */ @@ -4277,7 +4288,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); } @@ -4287,7 +4298,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); } @@ -4419,6 +4440,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); @@ -4444,8 +4483,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" @@ -4459,7 +4496,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); @@ -4474,7 +4510,6 @@ col_loop2: i++; if (!success) { - dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); @@ -4495,7 +4530,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); @@ -4521,7 +4555,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); @@ -4559,7 +4592,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); @@ -4578,7 +4610,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); @@ -4587,7 +4618,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); @@ -4600,8 +4630,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" @@ -4627,8 +4655,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" @@ -4650,7 +4676,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" @@ -4694,16 +4719,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; } /************************************************************************** @@ -4789,7 +4804,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; @@ -4855,25 +4869,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; @@ -5200,7 +5199,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))); @@ -5239,19 +5237,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); } /**********************************************************************//** @@ -5459,15 +5451,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); @@ -5524,8 +5513,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)); @@ -5857,10 +5844,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); @@ -5880,10 +5868,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); @@ -6175,24 +6164,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/dict/dict0mem.cc b/dict/dict0mem.cc index 6310b2fd225..885627a61bc 100644 --- a/dict/dict0mem.cc +++ b/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/fil/fil0fil.cc b/fil/fil0fil.cc index 2c7d8bcc6b0..55e54cb9568 100644 --- a/fil/fil0fil.cc +++ b/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); @@ -5176,9 +5179,9 @@ retry: #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) @@ -5675,7 +5678,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/fts/fts0ast.cc b/fts/fts0ast.cc index d6c19c0050a..dd48ffee14d 100644 --- a/fts/fts0ast.cc +++ b/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/fts/fts0blex.cc b/fts/fts0blex.cc index f83523825d2..7d0acb00a3b 100644 --- a/fts/fts0blex.cc +++ b/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/fts/fts0blex.l b/fts/fts0blex.l index 6193f0df187..ae6e8ffaa48 100644 --- a/fts/fts0blex.l +++ b/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/fts/fts0fts.cc b/fts/fts0fts.cc index 31b32eb565a..abb5515e7fd 100644 --- a/fts/fts0fts.cc +++ b/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/fts/fts0pars.cc b/fts/fts0pars.cc index 83d465b0988..7f0ba4e0c1b 100644 --- a/fts/fts0pars.cc +++ b/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/fts/fts0pars.y b/fts/fts0pars.y index ff22e9a9873..e48036e82fe 100644 --- a/fts/fts0pars.y +++ b/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/fts/fts0que.cc b/fts/fts0que.cc index 87c7951d947..816b52c1a67 100644 --- a/fts/fts0que.cc +++ b/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); } @@ -3898,6 +3913,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); @@ -3954,7 +3970,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/fts/fts0tlex.cc b/fts/fts0tlex.cc index ef17ab1acf2..b744fbf0763 100644 --- a/fts/fts0tlex.cc +++ b/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/fts/fts0tlex.l b/fts/fts0tlex.l index a18c2a55081..4f55a83afe5 100644 --- a/fts/fts0tlex.l +++ b/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/handler/ha_innodb.cc b/handler/ha_innodb.cc index 629617d8b8d..8a20600171e 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -3497,7 +3497,7 @@ innobase_commit( /* We were instructed to commit the whole transaction, or this is an SQL statement end and autocommit is on */ - /* We need current binlog position for ibbackup to work. */ + /* We need current binlog position for mysqlbackup to work. */ retry: if (innobase_commit_concurrency > 0) { mysql_mutex_lock(&commit_cond_m); @@ -3822,7 +3822,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)); @@ -11746,9 +11746,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); @@ -11784,9 +11788,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); @@ -11819,8 +11827,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 = ""; @@ -13598,7 +13606,7 @@ innobase_xa_prepare( || !thd_test_options( thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - /* For ibbackup to work the order of transactions in binlog + /* For mysqlbackup to work the order of transactions in binlog and InnoDB must be the same. Consider the situation thread1> prepare; write to binlog; ... diff --git a/handler/handler0alter.cc b/handler/handler0alter.cc index 9b5d8649175..c23dba234f3 100644 --- a/handler/handler0alter.cc +++ b/handler/handler0alter.cc @@ -558,15 +558,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); } } @@ -2188,14 +2182,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))) { @@ -2227,10 +2225,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; } @@ -3532,11 +3533,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); @@ -4369,10 +4371,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; @@ -4402,10 +4406,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; @@ -4729,8 +4735,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/handler/i_s.cc b/handler/i_s.cc index d87ffb86b97..cfe69274e8e 100644 --- a/handler/i_s.cc +++ b/handler/i_s.cc @@ -2913,7 +2913,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_ft_default_stopword = /* pointer to type-specific plugin descriptor */ /* void* */ - STRUCT_FLD(info, &i_s_stopword_fields_info), + STRUCT_FLD(info, &i_s_info), /* plugin name */ /* const char* */ @@ -3085,7 +3085,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_ft_deleted = /* pointer to type-specific plugin descriptor */ /* void* */ - STRUCT_FLD(info, &i_s_fts_doc_fields_info), + STRUCT_FLD(info, &i_s_info), /* plugin name */ /* const char* */ @@ -3172,7 +3172,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_ft_being_deleted = /* pointer to type-specific plugin descriptor */ /* void* */ - STRUCT_FLD(info, &i_s_fts_doc_fields_info), + STRUCT_FLD(info, &i_s_info), /* plugin name */ /* const char* */ @@ -3466,7 +3466,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_ft_index_cache = /* pointer to type-specific plugin descriptor */ /* void* */ - STRUCT_FLD(info, &i_s_fts_index_fields_info), + STRUCT_FLD(info, &i_s_info), /* plugin name */ /* const char* */ @@ -3905,7 +3905,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_ft_index_table = /* pointer to type-specific plugin descriptor */ /* void* */ - STRUCT_FLD(info, &i_s_fts_index_fields_info), + STRUCT_FLD(info, &i_s_info), /* plugin name */ /* const char* */ @@ -4103,7 +4103,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_ft_config = /* pointer to type-specific plugin descriptor */ /* void* */ - STRUCT_FLD(info, &i_s_fts_config_fields_info), + STRUCT_FLD(info, &i_s_info), /* plugin name */ /* const char* */ diff --git a/include/buf0buf.h b/include/buf0buf.h index 289de8f42ae..3f2ac4980cf 100644 --- a/include/buf0buf.h +++ b/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/include/buf0buf.ic b/include/buf0buf.ic index b15a7fb11b6..6e419674f98 100644 --- a/include/buf0buf.ic +++ b/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/include/dict0crea.h b/include/dict0crea.h index 6ec1079957b..67eab9058da 100644 --- a/include/dict0crea.h +++ b/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/include/dict0mem.h b/include/dict0mem.h index 49c69512194..63bc4ff777a 100644 --- a/include/dict0mem.h +++ b/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; @@ -703,12 +705,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 @@ -730,6 +826,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 */ @@ -784,13 +882,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; @@ -1029,6 +1130,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/include/fil0fil.h b/include/fil0fil.h index 72b4cfd3bfb..b607ca36d70 100644 --- a/include/fil0fil.h +++ b/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/include/fts0ast.h b/include/fts0ast.h index c0aac6d8e4c..50ee587e282 100644 --- a/include/fts0ast.h +++ b/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/include/fts0fts.h b/include/fts0fts.h index 5bea5bc0e97..a2996ecacc8 100644 --- a/include/fts0fts.h +++ b/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/include/fts0pars.h b/include/fts0pars.h index 50f636944e5..8108e811599 100644 --- a/include/fts0pars.h +++ b/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/include/log0log.h b/include/log0log.h index c88e49eb586..1318b62c242 100644 --- a/include/log0log.h +++ b/include/log0log.h @@ -642,13 +642,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 @@ -677,7 +677,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/include/os0file.h b/include/os0file.h index 9d0fc1135da..9b688ff048b 100644 --- a/include/os0file.h +++ b/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/include/os0sync.h b/include/os0sync.h index fb48bf78339..57b29fff663 100644 --- a/include/os0sync.h +++ b/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 @@ -437,6 +441,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 @@ -518,6 +523,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 @@ -685,6 +691,51 @@ for synchronization */ os_decrement_counter_by_amount(mutex, counter, 1);\ } while (0); +/** barrier definitions for memory ordering */ +#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 +# define os_wmb +# 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) +# define IB_MEMORY_BARRIER_STARTUP_MSG \ + "GCC builtin __atomic_thread_fence() is used for memory barrier" + +#elif defined(HAVE_IB_GCC_SYNC_SYNCHRONISE) +# define HAVE_MEMORY_BARRIER +# define os_rmb __sync_synchronize() +# define os_wmb __sync_synchronize() +# define IB_MEMORY_BARRIER_STARTUP_MSG \ + "GCC builtin __sync_synchronize() is used for memory barrier" + +#elif defined(HAVE_IB_MACHINE_BARRIER_SOLARIS) +# define HAVE_MEMORY_BARRIER +# include +# define os_rmb __machine_r_barrier() +# define os_wmb __machine_w_barrier() +# define IB_MEMORY_BARRIER_STARTUP_MSG \ + "Solaris memory ordering functions are used for memory barrier" + +#elif defined(HAVE_WINDOWS_MM_FENCE) && defined(_WIN64) +# define HAVE_MEMORY_BARRIER +# include +# define os_rmb _mm_lfence() +# define os_wmb _mm_sfence() +# define IB_MEMORY_BARRIER_STARTUP_MSG \ + "_mm_lfence() and _mm_sfence() are used for memory barrier" + +#else +# define os_rmb +# define os_wmb +# define IB_MEMORY_BARRIER_STARTUP_MSG \ + "Memory barrier is not used" +#endif + #ifndef UNIV_NONINL #include "os0sync.ic" #endif diff --git a/include/sync0rw.ic b/include/sync0rw.ic index 467a8b4eb44..bb05ae7daf1 100644 --- a/include/sync0rw.ic +++ b/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 */ } @@ -199,7 +201,10 @@ rw_lock_lock_word_decr( ulint amount) /*!< in: amount to decrement */ { #ifdef INNODB_RW_LOCKS_USE_ATOMICS - lint local_lock_word = lock->lock_word; + lint local_lock_word; + + 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, diff --git a/include/sync0sync.h b/include/sync0sync.h index 7b00e16476b..82fb353a41b 100644 --- a/include/sync0sync.h +++ b/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/include/sync0sync.ic b/include/sync0sync.ic index cb375cb4a4f..616e53d4aac 100644 --- a/include/sync0sync.ic +++ b/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,6 +96,7 @@ ib_mutex_test_and_set( ut_a(mutex->lock_word == 0); mutex->lock_word = 1; + os_wmb; } return((byte) ret); @@ -111,7 +116,11 @@ mutex_reset_lock_word( /* In theory __sync_lock_release should be used to release the lock. Unfortunately, it does not work properly alone. The workaround is that more conservative __sync_lock_test_and_set is used instead. */ +# if defined(HAVE_ATOMIC_BUILTINS_BYTE) os_atomic_test_and_set_byte(&mutex->lock_word, 0); +# else + os_atomic_test_and_set_ulint(&mutex->lock_word, 0); +# endif #else mutex->lock_word = 0; diff --git a/log/log0log.cc b/log/log0log.cc index 83e391b822a..8b4149539d7 100644 --- a/log/log0log.cc +++ b/log/log0log.cc @@ -1248,7 +1248,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; @@ -1988,7 +1988,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/log/log0recv.cc b/log/log0recv.cc index a521e098598..4fe9620ccaa 100644 --- a/log/log0recv.cc +++ b/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/os/os0file.cc b/os/os0file.cc index 483a9bfeef8..68f0ed10144 100644 --- a/os/os0file.cc +++ b/os/os0file.cc @@ -1817,7 +1817,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); @@ -1842,7 +1842,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) { @@ -1879,7 +1879,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); @@ -1902,7 +1902,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/page/page0zip.cc b/page/page0zip.cc index ab7a19795a3..194dc3a1d0e 100644 --- a/page/page0zip.cc +++ b/page/page0zip.cc @@ -3254,24 +3254,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/row/row0ins.cc b/row/row0ins.cc index 834dfe6f8eb..49bb5980548 100644 --- a/row/row0ins.cc +++ b/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/row/row0mysql.cc b/row/row0mysql.cc index aae18ba3eae..c6a2126df39 100644 --- a/row/row0mysql.cc +++ b/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/row/row0upd.cc b/row/row0upd.cc index daecfc9ef8f..fcd54332a47 100644 --- a/row/row0upd.cc +++ b/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/srv/srv0start.cc b/srv/srv0start.cc index 1c2bfcbd920..fde0d1552be 100644 --- a/srv/srv0start.cc +++ b/srv/srv0start.cc @@ -1646,6 +1646,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 @@ -2621,13 +2634,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/sync/sync0arr.cc b/sync/sync0arr.cc index 2cfb693f8ba..d56d328d8c3 100644 --- a/sync/sync0arr.cc +++ b/sync/sync0arr.cc @@ -740,6 +740,7 @@ sync_arr_cell_can_wake_up( mutex = static_cast(cell->wait_object); + os_rmb; if (mutex_get_lock_word(mutex) == 0) { return(TRUE); @@ -749,6 +750,7 @@ sync_arr_cell_can_wake_up( lock = static_cast(cell->wait_object); + os_rmb; if (lock->lock_word > 0) { /* Either unlocked or only read locked. */ @@ -760,6 +762,7 @@ sync_arr_cell_can_wake_up( lock = static_cast(cell->wait_object); /* lock_word == 0 means all readers have left */ + os_rmb; if (lock->lock_word == 0) { return(TRUE); @@ -768,6 +771,7 @@ sync_arr_cell_can_wake_up( lock = static_cast(cell->wait_object); /* lock_word > 0 means no writer or reserved writer */ + os_rmb; if (lock->lock_word > 0) { return(TRUE); diff --git a/sync/sync0rw.cc b/sync/sync0rw.cc index ebf73917702..9da6e3e7746 100644 --- a/sync/sync0rw.cc +++ b/sync/sync0rw.cc @@ -381,6 +381,7 @@ rw_lock_s_lock_spin( lock_loop: /* Spin waiting for the writer field to become free */ + os_rmb; while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); @@ -389,7 +390,7 @@ lock_loop: i++; } - if (i == SYNC_SPIN_ROUNDS) { + if (i >= SYNC_SPIN_ROUNDS) { os_thread_yield(); } @@ -476,6 +477,7 @@ rw_lock_x_lock_wait( counter_index = (size_t) os_thread_get_curr_id(); + os_rmb; ut_ad(lock->lock_word <= 0); while (lock->lock_word < 0) { @@ -484,6 +486,7 @@ rw_lock_x_lock_wait( } if(i < SYNC_SPIN_ROUNDS) { i++; + os_rmb; continue; } @@ -560,6 +563,10 @@ rw_lock_x_lock_low( } else { os_thread_id_t thread_id = os_thread_get_curr_id(); + if (!pass) { + os_rmb; + } + /* Decrement failed: relock or failed lock */ if (!pass && lock->recursive && os_thread_eq(lock->writer_thread, thread_id)) { @@ -638,6 +645,7 @@ lock_loop: } /* Spin waiting for the lock_word to become free */ + os_rmb; while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) { if (srv_spin_wait_delay) { @@ -647,7 +655,7 @@ lock_loop: i++; } - if (i == SYNC_SPIN_ROUNDS) { + if (i >= SYNC_SPIN_ROUNDS) { os_thread_yield(); } else { goto lock_loop; diff --git a/sync/sync0sync.cc b/sync/sync0sync.cc index a0673411c81..60b1798fb0d 100644 --- a/sync/sync0sync.cc +++ b/sync/sync0sync.cc @@ -458,6 +458,7 @@ mutex_set_waiters( *ptr = n; /* Here we assume that the write of a single word in memory is atomic */ + os_wmb; } /******************************************************************//** @@ -499,7 +500,7 @@ mutex_loop: a memory word. */ spin_loop: - + 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)); @@ -508,7 +509,7 @@ spin_loop: i++; } - if (i == SYNC_SPIN_ROUNDS) { + if (i >= SYNC_SPIN_ROUNDS) { os_thread_yield(); } diff --git a/trx/trx0sys.cc b/trx/trx0sys.cc index fcf1c1cedf4..52830a77b12 100644 --- a/trx/trx0sys.cc +++ b/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);