diff options
Diffstat (limited to 'storage/xtradb')
61 files changed, 1072 insertions, 802 deletions
diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index 08e12643dec..75e994aa34b 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -217,6 +217,8 @@ IF(HAVE_IB_ATOMIC_PTHREAD_T_GCC) ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_GCC=1) ENDIF() +CHECK_C_SOURCE_COMPILES("struct t1{ int a; char *b; }; struct t1 c= { .a=1, .b=0 }; main() { }" HAVE_C99_INITIALIZERS) + ENDIF(NOT MSVC) CHECK_FUNCTION_EXISTS(asprintf HAVE_ASPRINTF) @@ -453,6 +455,14 @@ SET(INNOBASE_SOURCES ut/ut0vec.cc ut/ut0wqueue.cc) +# These files have unused result errors, so we skip Werror +CHECK_C_COMPILER_FLAG("-Werror" HAVE_WERROR) +IF(HAVE_WERROR) + INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/compile_flags.cmake) + ADD_COMPILE_FLAGS(page/page0zip.c COMPILE_FLAGS "-Wno-error") + ADD_COMPILE_FLAGS(ut/ut0ut.c COMPILE_FLAGS "-Wno-error") +ENDIF() + IF(WITH_INNODB) # Legacy option SET(WITH_INNOBASE_STORAGE_ENGINE TRUE) diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc index 3859fb84b81..8769fc47166 100644 --- a/storage/xtradb/api/api0api.cc +++ b/storage/xtradb/api/api0api.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2008, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2008, 2015, 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 @@ -318,35 +318,6 @@ ib_wake_master_thread(void) } } -/*********************************************************************//** -Calculate the max row size of the columns in a cluster index. -@return max row length */ -UNIV_INLINE -ulint -ib_get_max_row_len( -/*===============*/ - dict_index_t* cluster) /*!< in: cluster index */ -{ - ulint i; - ulint max_len = 0; - ulint n_fields = cluster->n_fields; - - /* Add the size of the ordering columns in the - clustered index. */ - for (i = 0; i < n_fields; ++i) { - const dict_col_t* col; - - col = dict_index_get_nth_col(cluster, i); - - /* Use the maximum output size of - mach_write_compressed(), although the encoded - length should always fit in 2 bytes. */ - max_len += dict_col_get_max_size(col); - } - - return(max_len); -} - /*****************************************************************//** Read the columns from a rec into a tuple. */ static @@ -710,120 +681,6 @@ ib_trx_rollback( return(err); } -/*****************************************************************//** -Find an index definition from the index vector using index name. -@return index def. if found else NULL */ -UNIV_INLINE -const ib_index_def_t* -ib_table_find_index( -/*================*/ - ib_vector_t* indexes, /*!< in: vector of indexes */ - const char* name) /*!< in: index name */ -{ - ulint i; - - for (i = 0; i < ib_vector_size(indexes); ++i) { - const ib_index_def_t* index_def; - - index_def = (ib_index_def_t*) ib_vector_get(indexes, i); - - if (innobase_strcasecmp(name, index_def->name) == 0) { - return(index_def); - } - } - - return(NULL); -} - -/*****************************************************************//** -Get the InnoDB internal precise type from the schema column definition. -@return precise type in api format */ -UNIV_INLINE -ulint -ib_col_get_prtype( -/*==============*/ - const ib_col_t* ib_col) /*!< in: column definition */ -{ - ulint prtype = 0; - - if (ib_col->ib_col_attr & IB_COL_UNSIGNED) { - prtype |= DATA_UNSIGNED; - - ut_a(ib_col->ib_col_type == IB_INT); - } - - if (ib_col->ib_col_attr & IB_COL_NOT_NULL) { - prtype |= DATA_NOT_NULL; - } - - return(prtype); -} - -/*****************************************************************//** -Get the InnoDB internal main type from the schema column definition. -@return column main type */ -UNIV_INLINE -ulint -ib_col_get_mtype( -/*==============*/ - const ib_col_t* ib_col) /*!< in: column definition */ -{ - /* Note: The api0api.h types should map directly to - the internal numeric codes. */ - return(ib_col->ib_col_type); -} - -/*****************************************************************//** -Find a column in the the column vector with the same name. -@return col. def. if found else NULL */ -UNIV_INLINE -const ib_col_t* -ib_table_find_col( -/*==============*/ - const ib_vector_t* cols, /*!< in: column list head */ - const char* name) /*!< in: column name to find */ -{ - ulint i; - - for (i = 0; i < ib_vector_size(cols); ++i) { - const ib_col_t* ib_col; - - ib_col = static_cast<const ib_col_t*>( - ib_vector_get((ib_vector_t*) cols, i)); - - if (innobase_strcasecmp(ib_col->name, name) == 0) { - return(ib_col); - } - } - - return(NULL); -} - -/*****************************************************************//** -Find a column in the the column list with the same name. -@return col. def. if found else NULL */ -UNIV_INLINE -const ib_key_col_t* -ib_index_find_col( -/*==============*/ - ib_vector_t* cols, /*!< in: column list head */ - const char* name) /*!< in: column name to find */ -{ - ulint i; - - for (i = 0; i < ib_vector_size(cols); ++i) { - const ib_key_col_t* ib_col; - - ib_col = static_cast<ib_key_col_t*>(ib_vector_get(cols, i)); - - if (innobase_strcasecmp(ib_col->name, name) == 0) { - return(ib_col); - } - } - - return(NULL); -} - #ifdef __WIN__ /*****************************************************************//** Convert a string to lower case. */ @@ -947,34 +804,6 @@ ib_table_name_check( /*****************************************************************//** -Get an index definition that is tagged as a clustered index. -@return cluster index schema */ -UNIV_INLINE -ib_index_def_t* -ib_find_clustered_index( -/*====================*/ - ib_vector_t* indexes) /*!< in: index defs. to search */ -{ - ulint i; - ulint n_indexes; - - n_indexes = ib_vector_size(indexes); - - for (i = 0; i < n_indexes; ++i) { - ib_index_def_t* ib_index_def; - - ib_index_def = static_cast<ib_index_def_t*>( - ib_vector_get(indexes, i)); - - if (ib_index_def->clustered) { - return(ib_index_def); - } - } - - return(NULL); -} - -/*****************************************************************//** Get a table id. The caller must have acquired the dictionary mutex. @return DB_SUCCESS if found */ static @@ -3564,41 +3393,6 @@ ib_cursor_set_cluster_access( prebuilt->need_to_access_clustered = TRUE; } -/*************************************************************//** -Convert and write an INT column value to an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INLINE -ib_err_t -ib_tuple_write_int( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - ulint col_no, /*!< in: column number */ - const void* value, /*!< in: integer value */ - ulint value_len) /*!< in: sizeof value type */ -{ - const dfield_t* dfield; - ulint data_len; - ulint type_len; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - ut_a(col_no < ib_tuple_get_n_cols(ib_tpl)); - - dfield = ib_col_get_dfield(tuple, col_no); - - data_len = dfield_get_len(dfield); - type_len = dtype_get_len(dfield_get_type(dfield)); - - if (dtype_get_mtype(dfield_get_type(dfield)) != DATA_INT - || value_len != data_len) { - - return(DB_DATA_MISMATCH); - } - - return(ib_col_set_value( - ib_tpl, static_cast<ib_ulint_t>(col_no), - value, static_cast<ib_ulint_t>(type_len), true)); -} - /*****************************************************************//** Write an integer value to a column. Integers are stored in big-endian format and will need to be converted from the host format. diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc index 323bb468527..4186c9ab33f 100644 --- a/storage/xtradb/btr/btr0cur.cc +++ b/storage/xtradb/btr/btr0cur.cc @@ -2522,15 +2522,15 @@ btr_cur_pess_upd_restore_supremum( Check if the total length of the modified blob for the row is within 10% of the total redo log size. This constraint on the blob length is to avoid overwriting the redo logs beyond the last checkpoint lsn. -@return DB_SUCCESS or DB_TOO_BIG_RECORD. */ +@return DB_SUCCESS or DB_TOO_BIG_FOR_REDO. */ static dberr_t btr_check_blob_limit(const big_rec_t* big_rec_vec) { const ib_uint64_t redo_size = srv_n_log_files * srv_log_file_size * UNIV_PAGE_SIZE; - const ulint redo_10p = redo_size / 10; - ulint total_blob_len = 0; + const ib_uint64_t redo_10p = redo_size / 10; + ib_uint64_t total_blob_len = 0; dberr_t err = DB_SUCCESS; /* Calculate the total number of bytes for blob data */ @@ -2540,11 +2540,11 @@ btr_check_blob_limit(const big_rec_t* big_rec_vec) if (total_blob_len > redo_10p) { ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data" - " length (" ULINTPF ") is greater than" + " length (" UINT64PF ") is greater than" " 10%% of the total redo log size (" UINT64PF "). Please increase total redo log size.", total_blob_len, redo_size); - err = DB_TOO_BIG_RECORD; + err = DB_TOO_BIG_FOR_REDO; } return(err); @@ -4659,7 +4659,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. The fields are stored on pages allocated from leaf node file segment of the index tree. -@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ +@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE or DB_TOO_BIG_FOR_REDO */ UNIV_INTERN dberr_t btr_store_big_rec_extern_fields( diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 6c6b67ad774..97781a12d20 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -295,7 +295,6 @@ UNIV_INTERN mysql_pfs_key_t buf_block_debug_latch_key; #ifdef UNIV_PFS_MUTEX UNIV_INTERN mysql_pfs_key_t buffer_block_mutex_key; -UNIV_INTERN mysql_pfs_key_t buf_pool_mutex_key; UNIV_INTERN mysql_pfs_key_t buf_pool_zip_mutex_key; UNIV_INTERN mysql_pfs_key_t buf_pool_flush_state_mutex_key; UNIV_INTERN mysql_pfs_key_t buf_pool_LRU_list_mutex_key; @@ -1783,16 +1782,12 @@ page_found: ut_ad(!bpage->in_page_hash); ut_ad(bpage->buf_fix_count == 0); - mutex_enter(&buf_pool->zip_mutex); - bpage->state = BUF_BLOCK_ZIP_PAGE; bpage->space = static_cast<ib_uint32_t>(space); bpage->offset = static_cast<ib_uint32_t>(offset); bpage->buf_fix_count = 1; bpage->buf_pool_index = buf_pool_index(buf_pool); - mutex_exit(&buf_pool->zip_mutex); - ut_d(bpage->in_page_hash = TRUE); HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, bpage); @@ -1844,7 +1839,6 @@ buf_pool_watch_remove( #endif /* UNIV_SYNC_DEBUG */ ut_ad(buf_page_get_state(watch) == BUF_BLOCK_ZIP_PAGE); - ut_ad(buf_own_zip_mutex_for_page(watch)); HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, watch); ut_d(watch->in_page_hash = FALSE); @@ -1887,9 +1881,7 @@ buf_pool_watch_unset( #endif /* PAGE_ATOMIC_REF_COUNT */ if (bpage->buf_fix_count == 0) { - mutex_enter(&buf_pool->zip_mutex); buf_pool_watch_remove(buf_pool, fold, bpage); - mutex_exit(&buf_pool->zip_mutex); } } @@ -4474,7 +4466,7 @@ corrupt: #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ buf_page_get_flush_type(bpage) == BUF_FLUSH_LRU)) { - have_LRU_mutex = TRUE; /* optimistic */ + have_LRU_mutex = true; /* optimistic */ } retry_mutex: if (have_LRU_mutex) { @@ -4494,6 +4486,7 @@ retry_mutex: && !have_LRU_mutex) { mutex_exit(block_mutex); + have_LRU_mutex = true; goto retry_mutex; } diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index 5dabf3b77e7..7c9e5e091c5 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -1107,8 +1107,8 @@ buf_flush_page( # if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG /********************************************************************//** Writes a flushable page asynchronously from the buffer pool to a file. -NOTE: block->mutex must be held upon entering this function, and it will be -released by this function after flushing. This is loosely based on +NOTE: block and LRU list mutexes must be held upon entering this function, and +they will be released by this function after flushing. This is loosely based on buf_flush_batch() and buf_flush_page(). @return TRUE if the page was flushed and the mutexes released */ UNIV_INTERN @@ -1659,6 +1659,8 @@ buf_do_LRU_batch( flush_counters_t* n) /*!< out: flushed/evicted page counts */ { + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); + if (buf_LRU_evict_from_unzip_LRU(buf_pool)) { n->unzip_LRU_evicted = buf_free_from_unzip_LRU_list_batch(buf_pool, max); diff --git a/storage/xtradb/buf/buf0lru.cc b/storage/xtradb/buf/buf0lru.cc index e9b6d8f3fb5..f2ce261c9df 100644 --- a/storage/xtradb/buf/buf0lru.cc +++ b/storage/xtradb/buf/buf0lru.cc @@ -526,7 +526,7 @@ buf_flush_or_remove_page( mutex_exit(block_mutex); - *must_restart = TRUE; + *must_restart = true; processed = false; } else if (!flush) { diff --git a/storage/xtradb/buf/buf0rea.cc b/storage/xtradb/buf/buf0rea.cc index 7a79958c136..63d2fdf7726 100644 --- a/storage/xtradb/buf/buf0rea.cc +++ b/storage/xtradb/buf/buf0rea.cc @@ -641,9 +641,9 @@ buf_read_ahead_linear( fail_count = 0; - for (i = low; i < high; i++) { + prio_rw_lock_t* hash_lock; - prio_rw_lock_t* hash_lock; + for (i = low; i < high; i++) { bpage = buf_page_hash_get_s_locked(buf_pool, space, i, &hash_lock); @@ -692,7 +692,7 @@ buf_read_ahead_linear( /* If we got this far, we know that enough pages in the area have been accessed in the right order: linear read-ahead can be sensible */ - bpage = buf_page_hash_get(buf_pool, space, offset); + bpage = buf_page_hash_get_s_locked(buf_pool, space, offset, &hash_lock); if (bpage == NULL) { @@ -720,6 +720,8 @@ buf_read_ahead_linear( pred_offset = fil_page_get_prev(frame); succ_offset = fil_page_get_next(frame); + rw_lock_s_unlock(hash_lock); + if ((offset == low) && (succ_offset == offset + 1)) { /* This is ok, we can continue */ diff --git a/storage/xtradb/dict/dict0boot.cc b/storage/xtradb/dict/dict0boot.cc index b57a8873bd5..94a3af2852b 100644 --- a/storage/xtradb/dict/dict0boot.cc +++ b/storage/xtradb/dict/dict0boot.cc @@ -302,8 +302,7 @@ dict_boot(void) /* Insert into the dictionary cache the descriptions of the basic system tables */ /*-------------------------*/ - table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0, - false); + table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0); @@ -357,8 +356,7 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0, - false); + table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); @@ -391,8 +389,7 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0, - false); + table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0); @@ -425,8 +422,7 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0, - false); + table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0); dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index cc4d93ebc99..a76121544b0 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. Copyright (c) 2013, SkySQL Ab. All Rights Reserved. @@ -649,7 +649,68 @@ dict_table_get_col_name( return(s); } +/**********************************************************************//** +Returns a column's name. +@return column name. NOTE: not guaranteed to stay valid if table is +modified in any way (columns added, etc.). */ +UNIV_INTERN +const char* +dict_table_get_col_name_for_mysql( +/*==============================*/ + const dict_table_t* table, /*!< in: table */ + const char* col_name)/*! in: MySQL table column name */ +{ + ulint i; + const char* s; + + ut_ad(table); + ut_ad(col_name); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + s = table->col_names; + if (s) { + /* If we have many virtual columns MySQL key_part->fieldnr + could be larger than number of columns in InnoDB table + when creating new indexes. */ + for (i = 0; i < table->n_def; i++) { + + if (!innobase_strcasecmp(s, col_name)) { + break; /* Found */ + } + s += strlen(s) + 1; + } + } + + return(s); +} #ifndef UNIV_HOTBACKUP +/** Allocate and init the autoinc latch of a given table. +This function must not be called concurrently on the same table object. +@param[in,out] table_void table whose autoinc latch to create */ +void +dict_table_autoinc_alloc( + void* table_void) +{ + dict_table_t* table = static_cast<dict_table_t*>(table_void); + table->autoinc_mutex = new (std::nothrow) ib_mutex_t(); + ut_a(table->autoinc_mutex != NULL); + mutex_create(autoinc_mutex_key, + table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); +} + +/** Allocate and init the zip_pad_mutex of a given index. +This function must not be called concurrently on the same index object. +@param[in,out] index_void index whose zip_pad_mutex to create */ +void +dict_index_zip_pad_alloc( + void* index_void) +{ + dict_index_t* index = static_cast<dict_index_t*>(index_void); + index->zip_pad.mutex = new (std::nothrow) os_fast_mutex_t; + ut_a(index->zip_pad.mutex != NULL); + os_fast_mutex_init(zip_pad_mutex_key, index->zip_pad.mutex); +} + /********************************************************************//** Acquire the autoinc lock. */ UNIV_INTERN @@ -658,7 +719,32 @@ dict_table_autoinc_lock( /*====================*/ dict_table_t* table) /*!< in/out: table */ { - mutex_enter(&table->autoinc_mutex); +#ifdef HAVE_ATOMIC_BUILTINS + os_once::do_or_wait_for_done( + &table->autoinc_mutex_created, + dict_table_autoinc_alloc, table); +#else /* HAVE_ATOMIC_BUILTINS */ + ut_ad(table->autoinc_mutex_created == os_once::DONE); +#endif /* HAVE_ATOMIC_BUILTINS */ + + mutex_enter(table->autoinc_mutex); +} + +/** Acquire the zip_pad_mutex latch. +@param[in,out] index the index whose zip_pad_mutex to acquire.*/ +void +dict_index_zip_pad_lock( + dict_index_t* index) +{ +#ifdef HAVE_ATOMIC_BUILTINS + os_once::do_or_wait_for_done( + &index->zip_pad.mutex_created, + dict_index_zip_pad_alloc, index); +#else /* HAVE_ATOMIC_BUILTINS */ + ut_ad(index->zip_pad.mutex_created == os_once::DONE); +#endif /* HAVE_ATOMIC_BUILTINS */ + + os_fast_mutex_lock(index->zip_pad.mutex); } /********************************************************************//** @@ -670,7 +756,7 @@ dict_table_autoinc_initialize( dict_table_t* table, /*!< in/out: table */ ib_uint64_t value) /*!< in: next value to assign to a row */ { - ut_ad(mutex_own(&table->autoinc_mutex)); + ut_ad(dict_table_autoinc_own(table)); table->autoinc = value; } @@ -712,7 +798,7 @@ dict_table_autoinc_read( /*====================*/ const dict_table_t* table) /*!< in: table */ { - ut_ad(mutex_own(&table->autoinc_mutex)); + ut_ad(dict_table_autoinc_own(table)); return(table->autoinc); } @@ -728,7 +814,7 @@ dict_table_autoinc_update_if_greater( dict_table_t* table, /*!< in/out: table */ ib_uint64_t value) /*!< in: value which was assigned to a row */ { - ut_ad(mutex_own(&table->autoinc_mutex)); + ut_ad(dict_table_autoinc_own(table)); if (value > table->autoinc) { @@ -744,7 +830,7 @@ dict_table_autoinc_unlock( /*======================*/ dict_table_t* table) /*!< in/out: table */ { - mutex_exit(&table->autoinc_mutex); + mutex_exit(table->autoinc_mutex); } #endif /* !UNIV_HOTBACKUP */ @@ -1583,15 +1669,18 @@ dict_table_rename_in_cache( } else if (table->space != TRX_SYS_SPACE) { char* new_path = NULL; - if (table->dir_path_of_temp_table != NULL) { + if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: trying to rename a" " TEMPORARY TABLE ", stderr); ut_print_name(stderr, NULL, TRUE, old_name); - fputs(" (", stderr); - ut_print_filename(stderr, - table->dir_path_of_temp_table); - fputs(" )\n", stderr); + if (table->dir_path_of_temp_table != NULL) { + fputs(" (", stderr); + ut_print_filename( + stderr, table->dir_path_of_temp_table); + fputs(" )\n", stderr); + } + return(DB_ERROR); } else if (DICT_TF_HAS_DATA_DIR(table->flags)) { @@ -2428,10 +2517,10 @@ too_big: dict_mem_index_free(new_index); dict_mem_index_free(index); return(DB_TOO_BIG_RECORD); - } else { - + } else if (current_thd != NULL) { + /* Avoid the warning to be printed + during recovery. */ ib_warn_row_too_big(table); - } } @@ -4115,16 +4204,25 @@ dict_table_get_highest_foreign_id( for (dict_foreign_set::iterator it = table->foreign_set.begin(); it != table->foreign_set.end(); ++it) { + char fkid[MAX_TABLE_NAME_LEN+20]; 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, + strcpy(fkid, foreign->id); + /* Convert foreign key identifier on dictionary memory + cache to filename charset. */ + innobase_convert_to_filename_charset( + strchr(fkid, '/') + 1, + strchr(foreign->id, '/') + 1, + MAX_TABLE_NAME_LEN); + + if (ut_strlen(fkid) > ((sizeof dict_ibfk) - 1) + len + && 0 == ut_memcmp(fkid, table->name, len) + && 0 == ut_memcmp(fkid + len, dict_ibfk, (sizeof dict_ibfk) - 1) - && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') { + && fkid[len + ((sizeof dict_ibfk) - 1)] != '0') { /* It is of the >= 4.0.18 format */ - id = strtoul(foreign->id + len + id = strtoul(fkid + len + ((sizeof dict_ibfk) - 1), &endp, 10); if (*endp == '\0') { @@ -5864,8 +5962,7 @@ dict_ind_init(void) dict_table_t* table; /* create dummy table and index for REDUNDANT infimum and supremum */ - table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0, - true); + table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0); dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR, DATA_ENGLISH | DATA_NOT_NULL, 8); @@ -5878,7 +5975,7 @@ dict_ind_init(void) /* create dummy table and index for COMPACT infimum and supremum */ table = dict_mem_table_create("SYS_DUMMY2", DICT_HDR_SPACE, 1, - DICT_TF_COMPACT, 0, true); + DICT_TF_COMPACT, 0); dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR, DATA_ENGLISH | DATA_NOT_NULL, 8); dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2", @@ -6714,10 +6811,10 @@ dict_index_zip_success( return; } - os_fast_mutex_lock(&index->zip_pad.mutex); + dict_index_zip_pad_lock(index); ++index->zip_pad.success; dict_index_zip_pad_update(&index->zip_pad, zip_threshold); - os_fast_mutex_unlock(&index->zip_pad.mutex); + dict_index_zip_pad_unlock(index); } /*********************************************************************//** @@ -6737,10 +6834,10 @@ dict_index_zip_failure( return; } - os_fast_mutex_lock(&index->zip_pad.mutex); + dict_index_zip_pad_lock(index); ++index->zip_pad.failure; dict_index_zip_pad_update(&index->zip_pad, zip_threshold); - os_fast_mutex_unlock(&index->zip_pad.mutex); + dict_index_zip_pad_unlock(index); } @@ -6772,9 +6869,9 @@ dict_index_zip_pad_optimal_page_size( #ifdef HAVE_ATOMIC_BUILTINS pad = os_atomic_increment_ulint(&index->zip_pad.pad, 0); #else /* HAVE_ATOMIC_BUILTINS */ - os_fast_mutex_lock(&index->zip_pad.mutex); + dict_index_zip_pad_lock(index); pad = index->zip_pad.pad; - os_fast_mutex_unlock(&index->zip_pad.mutex); + dict_index_zip_pad_unlock(index); #endif /* HAVE_ATOMIC_BUILTINS */ ut_ad(pad < UNIV_PAGE_SIZE); diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc index 874614bfb5c..ef8a2896b28 100644 --- a/storage/xtradb/dict/dict0load.cc +++ b/storage/xtradb/dict/dict0load.cc @@ -2176,8 +2176,7 @@ err_len: /* See if the tablespace is available. */ *table = dict_mem_table_create( - name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2, - false); + name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2); field = rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLES__ID, &len); ut_ad(len == 8); /* this was checked earlier */ diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc index 997e630dd15..c23a3637632 100644 --- a/storage/xtradb/dict/dict0mem.cc +++ b/storage/xtradb/dict/dict0mem.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -79,10 +79,7 @@ dict_mem_table_create( the table is placed */ ulint n_cols, /*!< in: number of columns */ ulint flags, /*!< in: table flags */ - ulint flags2, /*!< in: table flags2 */ - bool nonshared)/*!< in: whether the table object is a dummy - one that does not need the initialization of - locking-related fields. */ + ulint flags2) /*!< in: table flags2 */ { dict_table_t* table; mem_heap_t* heap; @@ -118,18 +115,10 @@ dict_mem_table_create( dict_table_stats_latch_create(table, true); #ifndef UNIV_HOTBACKUP + table->autoinc_lock = static_cast<ib_lock_t*>( + mem_heap_alloc(heap, lock_get_size())); - if (!nonshared) { - - table->autoinc_lock = static_cast<ib_lock_t*>( - mem_heap_alloc(heap, lock_get_size())); - - mutex_create(autoinc_mutex_key, - &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); - } else { - - table->autoinc_lock = NULL; - } + dict_table_autoinc_create_lazy(table); table->autoinc = 0; @@ -212,10 +201,7 @@ dict_mem_table_free( } } #ifndef UNIV_HOTBACKUP - if (table->autoinc_lock) { - - mutex_free(&(table->autoinc_mutex)); - } + dict_table_autoinc_destroy(table); #endif /* UNIV_HOTBACKUP */ dict_table_stats_latch_destroy(table); @@ -335,6 +321,9 @@ dict_mem_table_col_rename_low( ut_ad(from_len <= NAME_LEN); ut_ad(to_len <= NAME_LEN); + char from[NAME_LEN]; + strncpy(from, s, NAME_LEN); + if (from_len == to_len) { /* The easy case: simply replace the column name in table->col_names. */ @@ -402,14 +391,53 @@ dict_mem_table_col_rename_low( foreign = *it; - for (unsigned f = 0; f < foreign->n_fields; f++) { - /* These can point straight to - table->col_names, because the foreign key - constraints will be freed at the same time - when the table object is freed. */ - foreign->foreign_col_names[f] - = dict_index_get_nth_field( - foreign->foreign_index, f)->name; + if (foreign->foreign_index == NULL) { + /* We may go here when we set foreign_key_checks to 0, + and then try to rename a column and modify the + corresponding foreign key constraint. The index + would have been dropped, we have to find an equivalent + one */ + for (unsigned f = 0; f < foreign->n_fields; f++) { + if (strcmp(foreign->foreign_col_names[f], from) + == 0) { + + char** rc = const_cast<char**>( + foreign->foreign_col_names + + f); + + if (to_len <= strlen(*rc)) { + memcpy(*rc, to, to_len + 1); + } else { + *rc = static_cast<char*>( + mem_heap_dup( + foreign->heap, + to, + to_len + 1)); + } + } + } + + dict_index_t* new_index = dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, NULL, true, false); + /* There must be an equivalent index in this case. */ + ut_ad(new_index != NULL); + + foreign->foreign_index = new_index; + + } else { + + for (unsigned f = 0; f < foreign->n_fields; f++) { + /* These can point straight to + table->col_names, because the foreign key + constraints will be freed at the same time + when the table object is freed. */ + foreign->foreign_col_names[f] + = dict_index_get_nth_field( + foreign->foreign_index, + f)->name; + } } } @@ -419,6 +447,8 @@ dict_mem_table_col_rename_low( foreign = *it; + ut_ad(foreign->referenced_index != NULL); + for (unsigned f = 0; f < foreign->n_fields; f++) { /* foreign->referenced_col_names[] need to be copies, because the constraint may become @@ -536,8 +566,7 @@ dict_mem_index_create( dict_mem_fill_index_struct(index, heap, table_name, index_name, space, type, n_fields); - os_fast_mutex_init(zip_pad_mutex_key, &index->zip_pad.mutex); - + dict_index_zip_pad_mutex_create_lazy(index); return(index); } @@ -670,7 +699,7 @@ dict_mem_index_free( } #endif /* UNIV_BLOB_DEBUG */ - os_fast_mutex_free(&index->zip_pad.mutex); + dict_index_zip_pad_mutex_destroy(index); mem_heap_free(index->heap); } @@ -744,7 +773,7 @@ dict_foreign_set_validate( { dict_foreign_not_exists not_exists(fk_set); - dict_foreign_set::iterator it = std::find_if( + dict_foreign_set::const_iterator it = std::find_if( fk_set.begin(), fk_set.end(), not_exists); if (it == fk_set.end()) { diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 3343ae5555a..d1f35480ecf 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -5075,6 +5075,9 @@ retry: success = TRUE; } + DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", + success = FALSE; errno = 28;os_has_said_disk_full = TRUE;); + mutex_enter(&fil_system->mutex); if (success) { @@ -5117,6 +5120,10 @@ retry: offset, page_size * n_pages, node, NULL, space_id, NULL, 0, 0, 0); #endif /* UNIV_HOTBACKUP */ + + DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", + success = FALSE; errno = 28; os_has_said_disk_full = TRUE;); + if (success) { os_has_said_disk_full = FALSE; } else { diff --git a/storage/xtradb/fsp/fsp0fsp.cc b/storage/xtradb/fsp/fsp0fsp.cc index c06d4213d73..1f894d43031 100644 --- a/storage/xtradb/fsp/fsp0fsp.cc +++ b/storage/xtradb/fsp/fsp0fsp.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, 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 @@ -304,44 +304,6 @@ xdes_find_bit( } /**********************************************************************//** -Looks for a descriptor bit having the desired value. Scans the extent in -a direction opposite to xdes_find_bit. -@return bit index of the bit, ULINT_UNDEFINED if not found */ -UNIV_INLINE -ulint -xdes_find_bit_downward( -/*===================*/ - xdes_t* descr, /*!< in: descriptor */ - ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */ - ibool val, /*!< in: desired bit value */ - ulint hint, /*!< in: hint of which bit position would - be desirable */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - ulint i; - - ut_ad(descr && mtr); - ut_ad(val <= TRUE); - ut_ad(hint < FSP_EXTENT_SIZE); - ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX)); - for (i = hint + 1; i > 0; i--) { - if (val == xdes_mtr_get_bit(descr, bit, i - 1, mtr)) { - - return(i - 1); - } - } - - for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) { - if (val == xdes_mtr_get_bit(descr, bit, i, mtr)) { - - return(i); - } - } - - return(ULINT_UNDEFINED); -} - -/**********************************************************************//** Returns the number of used pages in a descriptor. @return number of pages used */ UNIV_INLINE diff --git a/storage/xtradb/fts/fts0ast.cc b/storage/xtradb/fts/fts0ast.cc index dd48ffee14d..030b972440f 100644 --- a/storage/xtradb/fts/fts0ast.cc +++ b/storage/xtradb/fts/fts0ast.cc @@ -694,3 +694,51 @@ fts_ast_string_print( printf("\n"); } + +#ifdef UNIV_DEBUG +const char* +fts_ast_oper_name_get(fts_ast_oper_t oper) +{ + switch(oper) { + case FTS_NONE: + return("FTS_NONE"); + case FTS_IGNORE: + return("FTS_IGNORE"); + case FTS_EXIST: + return("FTS_EXIST"); + case FTS_NEGATE: + return("FTS_NEGATE"); + case FTS_INCR_RATING: + return("FTS_INCR_RATING"); + case FTS_DECR_RATING: + return("FTS_DECR_RATING"); + case FTS_DISTANCE: + return("FTS_DISTANCE"); + case FTS_IGNORE_SKIP: + return("FTS_IGNORE_SKIP"); + case FTS_EXIST_SKIP: + return("FTS_EXIST_SKIP"); + } + ut_ad(0); +} + +const char* +fts_ast_node_type_get(fts_ast_type_t type) +{ + switch (type) { + case FTS_AST_OPER: + return("FTS_AST_OPER"); + case FTS_AST_NUMB: + return("FTS_AST_NUMB"); + case FTS_AST_TERM: + return("FTS_AST_TERM"); + case FTS_AST_TEXT: + return("FTS_AST_TEXT"); + case FTS_AST_LIST: + return("FTS_AST_LIST"); + case FTS_AST_SUBEXP_LIST: + return("FTS_AST_SUBEXP_LIST"); + } + ut_ad(0); +} +#endif /* UNIV_DEBUG */ diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 37e742bf938..5adda1fad6c 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2015, 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 @@ -81,11 +81,13 @@ ulint n_nodes = 0; /** Error condition reported by fts_utf8_decode() */ const ulint UTF8_ERROR = 0xFFFFFFFF; +#ifdef FTS_CACHE_SIZE_DEBUG /** The cache size permissible lower limit (1K) */ static const ulint FTS_CACHE_SIZE_LOWER_LIMIT_IN_MB = 1; /** The cache size permissible upper limit (1G) */ static const ulint FTS_CACHE_SIZE_UPPER_LIMIT_IN_MB = 1024; +#endif /* FTS_CACHE_SIZE_DEBUG */ /** Time to sleep after DEADLOCK error before retrying operation. */ static const ulint FTS_DEADLOCK_RETRY_WAIT = 100000; @@ -191,7 +193,7 @@ static const char* fts_create_common_tables_sql = { "" "CREATE TABLE \"%s_CONFIG\" (\n" " key CHAR(50),\n" - " value CHAR(50) NOT NULL\n" + " value CHAR(200) NOT NULL\n" ") COMPACT;\n" "CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_CONFIG\"(key);\n" }; @@ -329,27 +331,6 @@ fts_update_sync_doc_id( doc_id_t doc_id, /*!< in: last document id */ trx_t* trx) /*!< in: update trx, or NULL */ __attribute__((nonnull(1))); -/******************************************************************** -Check if we should stop. */ -UNIV_INLINE -ibool -fts_is_stop_signalled( -/*==================*/ - fts_t* fts) /*!< in: fts instance */ -{ - ibool stop_signalled = FALSE; - - mutex_enter(&fts->bg_threads_mutex); - - if (fts->fts_status & BG_THREAD_STOP) { - - stop_signalled = TRUE; - } - - mutex_exit(&fts->bg_threads_mutex); - - return(stop_signalled); -} /****************************************************************//** This function loads the default InnoDB stopword list */ @@ -1971,7 +1952,7 @@ fts_create_one_index_table( flags2 = DICT_TF2_USE_TABLESPACE; } - new_table = dict_mem_table_create(table_name, 0, 5, 1, flags2, false); + 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( @@ -3409,7 +3390,7 @@ fts_fetch_doc_from_rec( doc->charset = get_doc->index_cache->charset; /* Null Field */ - if (doc->text.f_len == UNIV_SQL_NULL) { + if (doc->text.f_len == UNIV_SQL_NULL || doc->text.f_len == 0) { continue; } @@ -5545,7 +5526,7 @@ fts_savepoint_lookup( /*********************************************************************//** Release the savepoint data identified by name. All savepoints created -after the named savepoint are also released. +after the named savepoint are kept. @return DB_SUCCESS or error code */ UNIV_INTERN void @@ -5554,81 +5535,37 @@ fts_savepoint_release( trx_t* trx, /*!< in: transaction */ const char* name) /*!< in: savepoint name */ { - ulint i; - ib_vector_t* savepoints; - ulint top_of_stack = 0; - ut_a(name != NULL); - savepoints = trx->fts_trx->savepoints; + ib_vector_t* savepoints = trx->fts_trx->savepoints; ut_a(ib_vector_size(savepoints) > 0); - /* Skip the implied savepoint (first element). */ - for (i = 1; i < ib_vector_size(savepoints); ++i) { - fts_savepoint_t* savepoint; + ulint i = fts_savepoint_lookup(savepoints, name); + if (i != ULINT_UNDEFINED) { + ut_a(i >= 1); + fts_savepoint_t* savepoint; savepoint = static_cast<fts_savepoint_t*>( ib_vector_get(savepoints, i)); - /* Even though we release the resources that are part - of the savepoint, we don't (always) actually delete the - entry. We simply set the savepoint name to NULL. Therefore - we have to skip deleted/released entries. */ - if (savepoint->name != NULL - && strcmp(name, savepoint->name) == 0) { - break; + if (i == ib_vector_size(savepoints) - 1) { + /* If the savepoint is the last, we save its + tables to the previous savepoint. */ + fts_savepoint_t* prev_savepoint; + prev_savepoint = static_cast<fts_savepoint_t*>( + ib_vector_get(savepoints, i - 1)); - /* Track the previous savepoint instance that will - be at the top of the stack after the release. */ - } else if (savepoint->name != NULL) { - /* We need to delete all entries - greater than this element. */ - top_of_stack = i; + ib_rbt_t* tables = savepoint->tables; + savepoint->tables = prev_savepoint->tables; + prev_savepoint->tables = tables; } - } - - /* Only if we found and element to release. */ - if (i < ib_vector_size(savepoints)) { - fts_savepoint_t* last_savepoint; - fts_savepoint_t* top_savepoint; - ib_rbt_t* tables; - - ut_a(top_of_stack < ib_vector_size(savepoints)); - /* Exchange tables between last savepoint and top savepoint */ - last_savepoint = static_cast<fts_savepoint_t*>( - ib_vector_last(trx->fts_trx->savepoints)); - top_savepoint = static_cast<fts_savepoint_t*>( - ib_vector_get(savepoints, top_of_stack)); - tables = top_savepoint->tables; - top_savepoint->tables = last_savepoint->tables; - last_savepoint->tables = tables; - - /* Skip the implied savepoint. */ - for (i = ib_vector_size(savepoints) - 1; - i > top_of_stack; - --i) { - - fts_savepoint_t* savepoint; - - savepoint = static_cast<fts_savepoint_t*>( - ib_vector_get(savepoints, i)); - - /* Skip savepoints that were released earlier. */ - if (savepoint->name != NULL) { - savepoint->name = NULL; - fts_savepoint_free(savepoint); - } - - ib_vector_pop(savepoints); - } + fts_savepoint_free(savepoint); + ib_vector_remove(savepoints, *(void**)savepoint); /* Make sure we don't delete the implied savepoint. */ ut_a(ib_vector_size(savepoints) > 0); - - /* This must hold. */ - ut_a(ib_vector_size(savepoints) == (top_of_stack + 1)); } } @@ -6330,7 +6267,7 @@ fts_fake_hex_to_dec( { ib_id_t dec_id = 0; char tmp_id[FTS_AUX_MIN_TABLE_ID_LENGTH]; - int ret; + int ret __attribute__((unused)); ret = sprintf(tmp_id, UINT64PFx, id); ut_ad(ret == 16); diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index 2e2bd061d07..e096b8bf6d6 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2015, 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 @@ -42,9 +42,6 @@ Completed 2011/7/10 Sunny and Jimmy Yang /** The FTS optimize thread's work queue. */ static ib_wqueue_t* fts_optimize_wq; -/** The number of document ids to delete in one statement. */ -static const ulint FTS_MAX_DELETE_DOC_IDS = 1000; - /** Time to wait for a message. */ static const ulint FTS_QUEUE_WAIT_IN_USECS = 5000000; @@ -1154,6 +1151,7 @@ fts_optimize_encode_node( } /* Calculate the space required to store the ilist. */ + ut_ad(doc_id > node->last_doc_id); doc_id_delta = doc_id - node->last_doc_id; enc_len = fts_get_encoded_len(static_cast<ulint>(doc_id_delta)); @@ -1396,7 +1394,8 @@ fts_optimize_word( src_node = (fts_node_t*) ib_vector_get(word->nodes, i); - if (!dst_node) { + if (dst_node == NULL + || dst_node->last_doc_id > src_node->first_doc_id) { dst_node = static_cast<fts_node_t*>( ib_vector_push(nodes, NULL)); @@ -2577,8 +2576,6 @@ fts_optimize_add_table( return; } - ut_ad(table->cached && table->fts != NULL); - /* Make sure table with FTS index cannot be evicted */ if (table->can_be_evicted) { dict_table_move_from_lru_to_non_lru(table); diff --git a/storage/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc index 1ca5f80b182..66060439215 100644 --- a/storage/xtradb/fts/fts0que.cc +++ b/storage/xtradb/fts/fts0que.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2015, 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 @@ -57,9 +57,6 @@ Completed 2011/7/10 Sunny and Jimmy Yang /*Initial byte length for 'words' in fts_ranking_t */ #define RANKING_WORDS_INIT_LEN 4 -/* Coeffecient to use for normalize relevance ranking. */ -static const double FTS_NORMALIZE_COEFF = 0.0115F; - // FIXME: Need to have a generic iterator that traverses the ilist. typedef std::vector<fts_string_t> word_vector_t; @@ -1534,7 +1531,8 @@ fts_merge_doc_ids( { const ib_rbt_node_t* node; - ut_a(!rbt_empty(doc_ids)); + DBUG_ENTER("fts_merge_doc_ids"); + ut_a(!query->intersection); /* To process FTS_EXIST operation (intersection), we need @@ -1559,7 +1557,7 @@ fts_merge_doc_ids( query, ranking->doc_id, ranking->rank); if (query->error != DB_SUCCESS) { - return(query->error); + DBUG_RETURN(query->error); } /* Merge words. Don't need to take operator into account. */ @@ -1578,7 +1576,7 @@ fts_merge_doc_ids( query->intersection = NULL; } - return(DB_SUCCESS); + DBUG_RETURN(DB_SUCCESS); } /*****************************************************************//** @@ -2839,11 +2837,11 @@ fts_query_visitor( fts_query_t* query = static_cast<fts_query_t*>(arg); ut_a(node); + DBUG_ENTER("fts_query_visitor"); + DBUG_PRINT("fts", ("nodetype: %s", fts_ast_node_type_get(node->type))); token.f_n_char = 0; - query->oper = oper; - query->cur_node = node; switch (node->type) { @@ -2905,7 +2903,7 @@ fts_query_visitor( query->multi_exist = true; } - return(query->error); + DBUG_RETURN(query->error); } /*****************************************************************//** @@ -2929,6 +2927,8 @@ fts_ast_visit_sub_exp( bool will_be_ignored = false; bool multi_exist; + DBUG_ENTER("fts_ast_visit_sub_exp"); + ut_a(node->type == FTS_AST_SUBEXP_LIST); cur_oper = query->oper; @@ -2957,14 +2957,14 @@ fts_ast_visit_sub_exp( /* Merge the sub-expression result with the parent result set. */ subexpr_doc_ids = query->doc_ids; query->doc_ids = parent_doc_ids; - if (error == DB_SUCCESS && !rbt_empty(subexpr_doc_ids)) { + if (error == DB_SUCCESS) { error = fts_merge_doc_ids(query, subexpr_doc_ids); } /* Free current result set. Result already merged into parent. */ fts_query_free_doc_ids(query, subexpr_doc_ids); - return(error); + DBUG_RETURN(error); } #if 0 @@ -3440,8 +3440,10 @@ fts_retrieve_ranking( ib_rbt_bound_t parent; fts_ranking_t new_ranking; + DBUG_ENTER("fts_retrieve_ranking"); + if (!result || !result->rankings_by_id) { - return(0); + DBUG_RETURN(0); } new_ranking.doc_id = doc_id; @@ -3452,10 +3454,10 @@ fts_retrieve_ranking( ranking = rbt_value(fts_ranking_t, parent.last); - return(ranking->rank); + DBUG_RETURN(ranking->rank); } - return(0); + DBUG_RETURN(0); } /*****************************************************************//** @@ -3472,6 +3474,8 @@ fts_query_prepare_result( const ib_rbt_node_t* node; bool result_is_null = false; + DBUG_ENTER("fts_query_prepare_result"); + if (result == NULL) { result = static_cast<fts_result_t*>(ut_malloc(sizeof(*result))); @@ -3520,7 +3524,7 @@ fts_query_prepare_result( if (query->total_size > fts_result_cache_limit) { query->error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT; fts_query_free_result(result); - return(NULL); + DBUG_RETURN(NULL); } } @@ -3543,7 +3547,7 @@ fts_query_prepare_result( ranking->rank * word_freq->idf * word_freq->idf); } - return(result); + DBUG_RETURN(result); } ut_a(rbt_size(query->doc_ids) > 0); @@ -3570,7 +3574,7 @@ fts_query_prepare_result( if (query->total_size > fts_result_cache_limit) { query->error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT; fts_query_free_result(result); - return(NULL); + DBUG_RETURN(NULL); } } } @@ -3582,7 +3586,7 @@ fts_query_prepare_result( query->doc_ids = NULL; } - return(result); + DBUG_RETURN(result); } /*****************************************************************//** @@ -3594,6 +3598,8 @@ fts_query_get_result( fts_query_t* query, /*!< in: query instance */ fts_result_t* result) /*!< in: result */ { + DBUG_ENTER("fts_query_get_result"); + if (rbt_size(query->doc_ids) > 0 || query->flags == FTS_OPT_RANKING) { /* Copy the doc ids to the result. */ result = fts_query_prepare_result(query, result); @@ -3603,7 +3609,7 @@ fts_query_get_result( memset(result, 0, sizeof(*result)); } - return(result); + DBUG_RETURN(result); } /*****************************************************************//** @@ -3681,6 +3687,7 @@ fts_query_parse( int error; fts_ast_state_t state; bool mode = query->boolean_mode; + DBUG_ENTER("fts_query_parse"); memset(&state, 0x0, sizeof(state)); @@ -3699,7 +3706,7 @@ fts_query_parse( query->root = state.root; } - return(state.root); + DBUG_RETURN(state.root); } /*******************************************************************//** diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 42a49e355e6..ef6aae7889e 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. @@ -355,7 +355,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { # ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK {&buffer_block_mutex_key, "buffer_block_mutex", 0}, # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */ - {&buf_pool_mutex_key, "buf_pool_mutex", 0}, {&buf_pool_zip_mutex_key, "buf_pool_zip_mutex", 0}, {&buf_pool_LRU_list_mutex_key, "buf_pool_LRU_list_mutex", 0}, {&buf_pool_free_list_mutex_key, "buf_pool_free_list_mutex", 0}, @@ -1890,6 +1889,15 @@ convert_error_code_to_mysql( return(HA_ERR_TO_BIG_ROW); } + + case DB_TOO_BIG_FOR_REDO: + my_printf_error(ER_TOO_BIG_ROWSIZE, "%s" , MYF(0), + "The size of BLOB/TEXT data inserted" + " in one transaction is greater than" + " 10% of redo log size. Increase the" + " redo log size using innodb_log_file_size."); + return(HA_ERR_TO_BIG_ROW); + case DB_TOO_BIG_INDEX_COL: my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0), DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags)); @@ -3203,19 +3211,6 @@ trx_is_strict( return(trx && trx->mysql_thd && THDVAR(trx->mysql_thd, strict_mode)); } -/**********************************************************************//** -Determines if the current MySQL thread is running in strict mode. -If thd==NULL, THDVAR returns the global value of innodb-strict-mode. -@return TRUE if strict */ -UNIV_INLINE -ibool -thd_is_strict( -/*==========*/ - THD* thd) /*!< in: MySQL thread descriptor */ -{ - return(THDVAR(thd, strict_mode)); -} - /**************************************************************//** Resets some fields of a prebuilt struct. The template is used in fast retrieval of just those column values MySQL needs in its processing. */ @@ -4809,7 +4804,10 @@ innobase_release_savepoint( DBUG_ASSERT(hton == innodb_hton_ptr); trx = check_trx_exists(thd); - trx_start_if_not_started(trx); + + if (trx->state == TRX_STATE_NOT_STARTED) { + trx_start_if_not_started(trx); + } /* TODO: use provided savepoint data area to store savepoint data */ @@ -5463,6 +5461,8 @@ innobase_match_index_columns( if (innodb_idx_fld >= innodb_idx_fld_end) { DBUG_RETURN(FALSE); } + + mtype = innodb_idx_fld->col->mtype; } if (col_type != mtype) { @@ -7468,12 +7468,15 @@ ha_innobase::innobase_lock_autoinc(void) break; case AUTOINC_NEW_STYLE_LOCKING: - /* For simple (single/multi) row INSERTs, we fallback to the - old style only if another transaction has already acquired - the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT - etc. type of statement. */ + /* For simple (single/multi) row INSERTs/REPLACEs and RBR + events, we fallback to the old style only if another + transaction has already acquired the AUTOINC lock on + behalf of a LOAD FILE or INSERT ... SELECT etc. type of + statement. */ if (thd_sql_command(user_thd) == SQLCOM_INSERT - || thd_sql_command(user_thd) == SQLCOM_REPLACE) { + || thd_sql_command(user_thd) == SQLCOM_REPLACE + || thd_sql_command(user_thd) == SQLCOM_END // RBR event + ) { dict_table_t* ib_table = prebuilt->table; /* Acquire the AUTOINC mutex. */ @@ -7482,9 +7485,11 @@ ha_innobase::innobase_lock_autoinc(void) /* We need to check that another transaction isn't already holding the AUTOINC lock on the table. */ if (ib_table->n_waiting_or_granted_auto_inc_locks) { - /* Release the mutex to avoid deadlocks. */ + /* Release the mutex to avoid deadlocks and + fall back to old style locking. */ dict_table_autoinc_unlock(ib_table); } else { + /* Do not fall back to old style locking. */ break; } } @@ -8026,7 +8031,8 @@ calc_row_difference( } } } - innodb_idx++; + if (field->stored_in_db) + innodb_idx++; } /* If the update changes a column with an FTS index on it, we @@ -8941,6 +8947,11 @@ ha_innobase::general_fetch( DBUG_ENTER("general_fetch"); + /* If transaction is not startted do not continue, instead return a error code. */ + if(!(prebuilt->sql_stat_start || (prebuilt->trx && prebuilt->trx->state == 1))) { + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share && share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); @@ -9720,18 +9731,18 @@ create_table_def( /* Adjust for the FTS hidden field */ if (!has_doc_id_col) { table = dict_mem_table_create(table_name, 0, s_cols + 1, - flags, flags2, false); + flags, flags2); /* Set the hidden doc_id column. */ table->fts->doc_col = s_cols; } else { table = dict_mem_table_create(table_name, 0, s_cols, - flags, flags2, false); + flags, flags2); table->fts->doc_col = doc_id_col; } } else { table = dict_mem_table_create(table_name, 0, s_cols, - flags, flags2, false); + flags, flags2); } if (flags2 & DICT_TF2_TEMPORARY) { @@ -10797,7 +10808,7 @@ ha_innobase::create( DBUG_ASSERT(thd != NULL); DBUG_ASSERT(create_info != NULL); - if (form->s->fields > REC_MAX_N_USER_FIELDS) { + if (form->s->stored_fields > REC_MAX_N_USER_FIELDS) { DBUG_RETURN(HA_ERR_TOO_MANY_FIELDS); } else if (srv_read_only_mode) { DBUG_RETURN(HA_ERR_TABLE_READONLY); @@ -12184,18 +12195,6 @@ ha_innobase::info_low( prebuilt->trx->op_info = "returning various info to MySQL"; } - - my_snprintf(path, sizeof(path), "%s/%s%s", - mysql_data_home, ib_table->name, reg_ext); - - unpack_filename(path,path); - - /* Note that we do not know the access time of the table, - nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ - - if (os_file_get_status(path, &stat_info, false) == DB_SUCCESS) { - stats.create_time = (ulong) stat_info.ctime; - } } if (flag & HA_STATUS_VARIABLE) { @@ -12481,6 +12480,20 @@ ha_innobase::info_low( if (!(flag & HA_STATUS_NO_LOCK)) { dict_table_stats_unlock(ib_table, RW_S_LATCH); } + + my_snprintf(path, sizeof(path), "%s/%s%s", + mysql_data_home, + table->s->normalized_path.str, + reg_ext); + + unpack_filename(path,path); + + /* Note that we do not know the access time of the table, + nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ + + if (os_file_get_status(path, &stat_info, false) == DB_SUCCESS) { + stats.create_time = (ulong) stat_info.ctime; + } } if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { @@ -14819,10 +14832,8 @@ ha_innobase::cmp_ref( len1 = innobase_read_from_2_little_endian(ref1); len2 = innobase_read_from_2_little_endian(ref2); - ref1 += 2; - ref2 += 2; result = ((Field_blob*) field)->cmp( - ref1, len1, ref2, len2); + ref1 + 2, len1, ref2 + 2, len2); } else { result = field->key_cmp(ref1, ref2); } @@ -19341,6 +19352,7 @@ innodb_compression_algorithm_validate( /********************************************************************** Issue a warning that the row is too big. */ +UNIV_INTERN void ib_warn_row_too_big(const dict_table_t* table) { @@ -19354,6 +19366,10 @@ ib_warn_row_too_big(const dict_table_t* table) THD* thd = current_thd; + if (thd == NULL) { + return; + } + push_warning_printf( thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_TO_BIG_ROW, "Row size too large (> %lu). Changing some columns to TEXT" diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index a6ec6e5465f..439c92b0638 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -129,6 +129,7 @@ my_error_innodb( break; case DB_OUT_OF_FILE_SPACE: my_error(ER_RECORD_FILE_FULL, MYF(0), table); + ut_error; break; case DB_TEMP_FILE_WRITE_FAILURE: my_error(ER_GET_ERRMSG, MYF(0), @@ -1458,8 +1459,9 @@ innobase_create_index_field_def( if a new clustered index is not being created */ const KEY_PART_INFO* key_part, /*!< in: MySQL key definition */ - index_field_t* index_field) /*!< out: index field + index_field_t* index_field, /*!< out: index field definition for key_part */ + const Field** fields) /*!< in: MySQL table fields */ { const Field* field; ibool is_unsigned; @@ -1476,6 +1478,7 @@ innobase_create_index_field_def( ut_a(field); index_field->col_no = key_part->fieldnr; + index_field->col_name = altered_table ? field->field_name : fields[key_part->fieldnr]->field_name; col_type = get_innobase_type_from_mysql_type(&is_unsigned, field); @@ -1510,8 +1513,9 @@ innobase_create_index_def( bool key_clustered, /*!< in: true if this is the new clustered index */ index_def_t* index, /*!< out: index definition */ - mem_heap_t* heap) /*!< in: heap where memory + mem_heap_t* heap, /*!< in: heap where memory is allocated */ + const Field** fields) /*!z in: MySQL table fields */ { const KEY* key = &keys[key_number]; ulint i; @@ -1525,6 +1529,8 @@ innobase_create_index_def( index->fields = static_cast<index_field_t*>( mem_heap_alloc(heap, n_fields * sizeof *index->fields)); + memset(index->fields, 0, n_fields * sizeof *index->fields); + index->ind_type = 0; index->key_number = key_number; index->n_fields = n_fields; @@ -1561,7 +1567,7 @@ innobase_create_index_def( for (i = 0; i < n_fields; i++) { innobase_create_index_field_def( - altered_table, &key->key_part[i], &index->fields[i]); + altered_table, &key->key_part[i], &index->fields[i], fields); } DBUG_VOID_RETURN; @@ -1892,7 +1898,7 @@ innobase_create_key_defs( /* Create the PRIMARY key index definition */ innobase_create_index_def( altered_table, key_info, primary_key_number, - TRUE, TRUE, indexdef++, heap); + TRUE, TRUE, indexdef++, heap, (const Field **)altered_table->field); created_clustered: n_add = 1; @@ -1904,7 +1910,7 @@ created_clustered: /* Copy the index definitions. */ innobase_create_index_def( altered_table, key_info, i, TRUE, FALSE, - indexdef, heap); + indexdef, heap, (const Field **)altered_table->field); if (indexdef->ind_type & DICT_FTS) { n_fts_add++; @@ -1949,7 +1955,7 @@ created_clustered: for (ulint i = 0; i < n_add; i++) { innobase_create_index_def( altered_table, key_info, add[i], FALSE, FALSE, - indexdef, heap); + indexdef, heap, (const Field **)altered_table->field); if (indexdef->ind_type & DICT_FTS) { n_fts_add++; @@ -1966,6 +1972,7 @@ created_clustered: index->fields = static_cast<index_field_t*>( mem_heap_alloc(heap, sizeof *index->fields)); + memset(index->fields, 0, sizeof *index->fields); index->n_fields = 1; index->fields->col_no = fts_doc_id_col; index->fields->prefix_len = 0; @@ -2821,7 +2828,7 @@ prepare_inplace_alter_table_dict( /* The initial space id 0 may be overridden later. */ ctx->new_table = dict_mem_table_create( - new_table_name, 0, n_cols, flags, flags2, false); + new_table_name, 0, n_cols, flags, flags2); /* The rebuilt indexed_table will use the renamed column names. */ ctx->col_names = NULL; @@ -4479,11 +4486,15 @@ err_exit: rename_foreign: trx->op_info = "renaming column in SYS_FOREIGN_COLS"; + std::list<dict_foreign_t*> fk_evict; + bool foreign_modified; + for (dict_foreign_set::const_iterator it = user_table->foreign_set.begin(); it != user_table->foreign_set.end(); ++it) { dict_foreign_t* foreign = *it; + foreign_modified = false; for (unsigned i = 0; i < foreign->n_fields; i++) { if (strcmp(foreign->foreign_col_names[i], from)) { @@ -4511,6 +4522,11 @@ rename_foreign: if (error != DB_SUCCESS) { goto err_exit; } + foreign_modified = true; + } + + if (foreign_modified) { + fk_evict.push_back(foreign); } } @@ -4519,7 +4535,9 @@ rename_foreign: it != user_table->referenced_set.end(); ++it) { + foreign_modified = false; dict_foreign_t* foreign = *it; + for (unsigned i = 0; i < foreign->n_fields; i++) { if (strcmp(foreign->referenced_col_names[i], from)) { continue; @@ -4546,7 +4564,17 @@ rename_foreign: if (error != DB_SUCCESS) { goto err_exit; } + foreign_modified = true; } + + if (foreign_modified) { + fk_evict.push_back(foreign); + } + } + + if (new_clustered) { + std::for_each(fk_evict.begin(), fk_evict.end(), + dict_foreign_remove_from_cache); } trx->op_info = ""; diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index 962718e7049..af5a7467c8e 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2015, 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 @@ -170,9 +170,12 @@ do { \ } \ } while (0) -#if !defined __STRICT_ANSI__ && defined __GNUC__ && (__GNUC__) > 2 && \ - !defined __INTEL_COMPILER && !defined __clang__ +#if !defined __STRICT_ANSI__ && defined __GNUC__ && (__GNUC__) > 2 && !defined __INTEL_COMPILER && !defined __clang__ +#ifdef HAVE_C99_INITIALIZERS +#define STRUCT_FLD(name, value) .name = value +#else #define STRUCT_FLD(name, value) name: value +#endif /* HAVE_C99_INITIALIZERS */ #else #define STRUCT_FLD(name, value) value #endif @@ -3254,8 +3257,6 @@ i_s_fts_index_cache_fill_one_index( for (rbt_node = rbt_first(index_cache->words); rbt_node; rbt_node = rbt_next(index_cache->words, rbt_node)) { - doc_id_t doc_id = 0; - fts_tokenizer_word_t* word; word = rbt_value(fts_tokenizer_word_t, rbt_node); @@ -3281,6 +3282,7 @@ i_s_fts_index_cache_fill_one_index( fts_node_t* node; byte* ptr; ulint decoded = 0; + doc_id_t doc_id = 0; node = static_cast<fts_node_t*> (ib_vector_get( word->nodes, i)); @@ -3952,10 +3954,14 @@ i_s_fts_config_fill( if (!user_table) { DBUG_RETURN(0); + } else if (!dict_table_has_fts_index(user_table)) { + dict_table_close(user_table, FALSE, FALSE); + + DBUG_RETURN(0); } trx = trx_allocate_for_background(); - trx->op_info = "Select for FTS DELETE TABLE"; + trx->op_info = "Select for FTS CONFIG TABLE"; FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE, user_table); @@ -5188,11 +5194,6 @@ i_s_innodb_fill_buffer_pool( info_buffer = (buf_page_info_t*) mem_heap_zalloc( heap, mem_size); - /* Obtain appropriate mutexes. Since this is diagnostic - buffer pool info printout, we are not required to - preserve the overall consistency, so we can - release mutex periodically */ - /* GO through each block in the chunk */ for (n_blocks = num_to_process; n_blocks--; block++) { i_s_innodb_buffer_page_get_info( diff --git a/storage/xtradb/ibuf/ibuf0ibuf.cc b/storage/xtradb/ibuf/ibuf0ibuf.cc index ef6c9c74558..972208c51bd 100644 --- a/storage/xtradb/ibuf/ibuf0ibuf.cc +++ b/storage/xtradb/ibuf/ibuf0ibuf.cc @@ -611,8 +611,7 @@ ibuf_init_at_db_start(void) heap = mem_heap_create(450); /* Use old-style record format for the insert buffer. */ - table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0, 0, - false); + table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0, 0); dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0); @@ -1573,7 +1572,7 @@ ibuf_dummy_index_create( table = dict_mem_table_create("IBUF_DUMMY", DICT_HDR_SPACE, n, - comp ? DICT_TF_COMPACT : 0, 0, true); + comp ? DICT_TF_COMPACT : 0, 0); index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY", DICT_HDR_SPACE, 0, n); @@ -2879,6 +2878,12 @@ ibuf_contract_in_background( mutex_exit(&ibuf_mutex); } +#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG + if (ibuf_debug) { + return(0); + } +#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ + while (sum_pages < n_pages) { ulint n_bytes; @@ -3931,7 +3936,7 @@ check_watch: { buf_page_t* bpage; buf_pool_t* buf_pool = buf_pool_get(space, page_no); - bpage = buf_page_hash_get(buf_pool, space, page_no); + bpage = buf_page_get_also_watch(buf_pool, space, page_no); if (UNIV_LIKELY_NULL(bpage)) { /* A buffer pool watch has been set or the diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index 15f36e4343c..d8a3e77d820 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -1283,7 +1283,7 @@ page_hash lock is acquired in the specified lock mode. Otherwise, mode value is ignored. It is up to the caller to release the lock. If the block is found and the lock is NULL then the page_hash lock is released by this function. -@return block, NULL if not found */ +@return block, NULL if not found, or watch sentinel (if watch is true) */ UNIV_INLINE buf_page_t* buf_page_hash_get_locked( @@ -1299,9 +1299,11 @@ buf_page_hash_get_locked( found. NULL otherwise. If NULL is passed then the hash_lock is released by this function */ - ulint lock_mode); /*!< in: RW_LOCK_EX or + ulint lock_mode, /*!< in: RW_LOCK_EX or RW_LOCK_SHARED. Ignored if lock == NULL */ + bool watch = false); /*!< in: if true, return watch + sentinel also. */ /******************************************************************//** Returns the control block of a file page, NULL if not found. If the block is found and lock is not NULL then the appropriate @@ -1341,6 +1343,8 @@ buf_page_hash_get_low() function. buf_page_hash_get_locked(b, s, o, l, RW_LOCK_EX) #define buf_page_hash_get(b, s, o) \ buf_page_hash_get_locked(b, s, o, NULL, 0) +#define buf_page_get_also_watch(b, s, o) \ + buf_page_hash_get_locked(b, s, o, NULL, 0, true) #define buf_block_hash_get_s_locked(b, s, o, l) \ buf_block_hash_get_locked(b, s, o, l, RW_LOCK_SHARED) diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic index 10f0e02cb8f..b40285ae3f0 100644 --- a/storage/xtradb/include/buf0buf.ic +++ b/storage/xtradb/include/buf0buf.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -1193,7 +1193,7 @@ page_hash lock is acquired in the specified lock mode. Otherwise, mode value is ignored. It is up to the caller to release the lock. If the block is found and the lock is NULL then the page_hash lock is released by this function. -@return block, NULL if not found */ +@return block, NULL if not found, or watch sentinel (if watch is true) */ UNIV_INLINE buf_page_t* buf_page_hash_get_locked( @@ -1209,9 +1209,11 @@ buf_page_hash_get_locked( found. NULL otherwise. If NULL is passed then the hash_lock is released by this function */ - ulint lock_mode) /*!< in: RW_LOCK_EX or + ulint lock_mode, /*!< in: RW_LOCK_EX or RW_LOCK_SHARED. Ignored if lock == NULL */ + bool watch) /*!< in: if true, return watch + sentinel also. */ { buf_page_t* bpage = NULL; ulint fold; @@ -1242,7 +1244,9 @@ buf_page_hash_get_locked( bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); if (!bpage || buf_pool_watch_is_sentinel(buf_pool, bpage)) { - bpage = NULL; + if (!watch) { + bpage = NULL; + } goto unlock_and_exit; } diff --git a/storage/xtradb/include/buf0flu.h b/storage/xtradb/include/buf0flu.h index ab5349901e9..5cc0eb9d4cf 100644 --- a/storage/xtradb/include/buf0flu.h +++ b/storage/xtradb/include/buf0flu.h @@ -85,8 +85,8 @@ buf_flush_init_for_writing( # if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG /********************************************************************//** Writes a flushable page asynchronously from the buffer pool to a file. -NOTE: block->mutex must be held upon entering this function, and they will be -released by this function after flushing. This is loosely based on +NOTE: block and LRU list mutexes must be held upon entering this function, and +they will be released by this function after flushing. This is loosely based on buf_flush_batch() and buf_flush_page(). @return TRUE if the page was flushed and the mutexes released */ UNIV_INTERN diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h index 744b80ecd05..dab917e18db 100644 --- a/storage/xtradb/include/db0err.h +++ b/storage/xtradb/include/db0err.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 @@ -130,7 +130,8 @@ enum dberr_t { DB_TEMP_FILE_WRITE_FAILURE, /*!< Temp file write failure */ DB_FTS_TOO_MANY_WORDS_IN_PHRASE, /*< Too many words in a phrase */ - + DB_TOO_BIG_FOR_REDO, /* Record length greater than 10% + of redo log */ /* The following are partial failure codes */ DB_FAIL = 1000, DB_OVERFLOW, diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h index c2bf55a1a16..43fa613e756 100644 --- a/storage/xtradb/include/dict0dict.h +++ b/storage/xtradb/include/dict0dict.h @@ -600,6 +600,17 @@ dict_table_get_col_name( ulint col_nr) /*!< in: column number */ __attribute__((nonnull, warn_unused_result)); /**********************************************************************//** +Returns a column's name. +@return column name. NOTE: not guaranteed to stay valid if table is +modified in any way (columns added, etc.). */ +UNIV_INTERN +const char* +dict_table_get_col_name_for_mysql( +/*==============================*/ + const dict_table_t* table, /*!< in: table */ + const char* col_name)/*!< in: MySQL table column name */ + __attribute__((nonnull, warn_unused_result)); +/**********************************************************************//** Prints a table data. */ UNIV_INTERN void diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h index 7bec1499fd2..473aefec418 100644 --- a/storage/xtradb/include/dict0mem.h +++ b/storage/xtradb/include/dict0mem.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. Copyright (c) 2013, SkySQL Ab. All Rights Reserved. @@ -54,6 +54,7 @@ Created 1/8/1996 Heikki Tuuri #include <set> #include <algorithm> #include <iterator> +#include <ostream> /* Forward declaration. */ struct ib_rbt_t; @@ -313,10 +314,7 @@ dict_mem_table_create( of the table is placed */ ulint n_cols, /*!< in: number of columns */ ulint flags, /*!< in: table flags */ - ulint flags2, /*!< in: table flags2 */ - bool nonshared);/*!< in: whether the table object is a dummy - one that does not need the initialization of - locking-related fields. */ + ulint flags2); /*!< in: table flags2 */ /**********************************************************************//** Determines if a table belongs to a system database @return true if table belong to a system database */ @@ -608,11 +606,12 @@ extern ulong zip_failure_threshold_pct; compression failures */ extern ulong zip_pad_max; -/** Data structure to hold information about about how much space in +/** Data structure to hold information about how much space in an uncompressed page should be left as padding to avoid compression failures. This estimate is based on a self-adapting heuristic. */ struct zip_pad_info_t { - os_fast_mutex_t mutex; /*!< mutex protecting the info */ + os_fast_mutex_t* + mutex; /*!< mutex protecting the info */ ulint pad; /*!< number of bytes used as pad */ ulint success;/*!< successful compression ops during current round */ @@ -620,6 +619,9 @@ struct zip_pad_info_t { current round */ ulint n_rounds;/*!< number of currently successful rounds */ + volatile os_once::state_t + mutex_created; + /*!< Creation state of mutex member */ }; /** Data structure for an index. Most fields will be @@ -1098,8 +1100,7 @@ struct dict_table_t{ dict_table_t::indexes*::stat_index_size dict_table_t::indexes*::stat_n_leaf_pages (*) those are not always protected for - performance reasons. NULL for dumy table - objects. */ + performance reasons. */ unsigned stat_initialized:1; /*!< TRUE if statistics have been calculated the first time after database startup or table creation */ @@ -1224,12 +1225,15 @@ struct dict_table_t{ and release it without a need to allocate space from the lock heap of the trx: otherwise the lock heap would grow rapidly - if we do a large insert from a select. NULL - for dummy table objects. */ - ib_mutex_t autoinc_mutex; + if we do a large insert from a select */ + ib_mutex_t* autoinc_mutex; /*!< mutex protecting the autoincrement - counter. Not initialized for dummy table - objects */ + counter */ + + /** Creation state of autoinc_mutex member */ + volatile os_once::state_t + autoinc_mutex_created; + ib_uint64_t autoinc;/*!< autoinc counter value to give to the next inserted row */ ulong n_waiting_or_granted_auto_inc_locks; @@ -1293,6 +1297,111 @@ struct dict_foreign_add_to_referenced_table { } }; +/** Destroy the autoinc latch of the given table. +This function is only called from either single threaded environment +or from a thread that has not shared the table object with other threads. +@param[in,out] table table whose stats latch to destroy */ +inline +void +dict_table_autoinc_destroy( + dict_table_t* table) +{ + if (table->autoinc_mutex_created == os_once::DONE + && table->autoinc_mutex != NULL) { + mutex_free(table->autoinc_mutex); + delete table->autoinc_mutex; + } +} + +/** Allocate and init the autoinc latch of a given table. +This function must not be called concurrently on the same table object. +@param[in,out] table_void table whose autoinc latch to create */ +void +dict_table_autoinc_alloc( + void* table_void); + +/** Allocate and init the zip_pad_mutex of a given index. +This function must not be called concurrently on the same index object. +@param[in,out] index_void index whose zip_pad_mutex to create */ +void +dict_index_zip_pad_alloc( + void* index_void); + +/** Request for lazy creation of the autoinc latch of a given table. +This function is only called from either single threaded environment +or from a thread that has not shared the table object with other threads. +@param[in,out] table table whose autoinc latch is to be created. */ +inline +void +dict_table_autoinc_create_lazy( + dict_table_t* table) +{ +#ifdef HAVE_ATOMIC_BUILTINS + table->autoinc_mutex = NULL; + table->autoinc_mutex_created = os_once::NEVER_DONE; +#else /* HAVE_ATOMIC_BUILTINS */ + dict_table_autoinc_alloc(table); + table->autoinc_mutex_created = os_once::DONE; +#endif /* HAVE_ATOMIC_BUILTINS */ +} + +/** Request a lazy creation of dict_index_t::zip_pad::mutex. +This function is only called from either single threaded environment +or from a thread that has not shared the table object with other threads. +@param[in,out] index index whose zip_pad mutex is to be created */ +inline +void +dict_index_zip_pad_mutex_create_lazy( + dict_index_t* index) +{ +#ifdef HAVE_ATOMIC_BUILTINS + index->zip_pad.mutex = NULL; + index->zip_pad.mutex_created = os_once::NEVER_DONE; +#else /* HAVE_ATOMIC_BUILTINS */ + dict_index_zip_pad_alloc(index); + index->zip_pad.mutex_created = os_once::DONE; +#endif /* HAVE_ATOMIC_BUILTINS */ +} + +/** Destroy the zip_pad_mutex of the given index. +This function is only called from either single threaded environment +or from a thread that has not shared the table object with other threads. +@param[in,out] table table whose stats latch to destroy */ +inline +void +dict_index_zip_pad_mutex_destroy( + dict_index_t* index) +{ + if (index->zip_pad.mutex_created == os_once::DONE + && index->zip_pad.mutex != NULL) { + os_fast_mutex_free(index->zip_pad.mutex); + delete index->zip_pad.mutex; + } +} + +/** Release the zip_pad_mutex of a given index. +@param[in,out] index index whose zip_pad_mutex is to be released */ +inline +void +dict_index_zip_pad_unlock( + dict_index_t* index) +{ + os_fast_mutex_unlock(index->zip_pad.mutex); +} + +#ifdef UNIV_DEBUG +/** Check if the current thread owns the autoinc_mutex of a given table. +@param[in] table the autoinc_mutex belongs to this table +@return true, if the current thread owns the autoinc_mutex, false otherwise.*/ +inline +bool +dict_table_autoinc_own( + const dict_table_t* table) +{ + return(mutex_own(table->autoinc_mutex)); +} +#endif /* UNIV_DEBUG */ + #ifndef UNIV_NONINL #include "dict0mem.ic" #endif diff --git a/storage/xtradb/include/fts0ast.h b/storage/xtradb/include/fts0ast.h index 50ee587e282..b2380f78b39 100644 --- a/storage/xtradb/include/fts0ast.h +++ b/storage/xtradb/include/fts0ast.h @@ -329,4 +329,11 @@ struct fts_ast_state_t { tokenization */ }; +#ifdef UNIV_DEBUG +const char* +fts_ast_oper_name_get(fts_ast_oper_t oper); +const char* +fts_ast_node_type_get(fts_ast_type_t type); +#endif /* UNIV_DEBUG */ + #endif /* INNOBASE_FSTS0AST_H */ diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 66a96282b69..3c14828989b 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2006, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2006, 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 diff --git a/storage/xtradb/include/lock0priv.h b/storage/xtradb/include/lock0priv.h index e564387ec53..90d5dc994a4 100644 --- a/storage/xtradb/include/lock0priv.h +++ b/storage/xtradb/include/lock0priv.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2015, MariaDB Corporation 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 @@ -72,6 +73,12 @@ struct lock_t { hash_node_t hash; /*!< hash chain node for a record lock */ dict_index_t* index; /*!< index for a record lock */ + + /* Statistics for how long lock has been held and time + how long this lock had to be waited before it was granted */ + time_t requested_time; /*!< Lock request time */ + ulint wait_time; /*!< Time waited this lock or 0 */ + union { lock_table_t tab_lock;/*!< table lock */ lock_rec_t rec_lock;/*!< record lock */ diff --git a/storage/xtradb/include/os0file.h b/storage/xtradb/include/os0file.h index 89a1d8c0fe4..78af907c006 100644 --- a/storage/xtradb/include/os0file.h +++ b/storage/xtradb/include/os0file.h @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Copyright (c) 2013, SkySQL Ab. All Rights Reserved. diff --git a/storage/xtradb/include/os0sync.h b/storage/xtradb/include/os0sync.h index f968de7c6dd..3a7707ee130 100644 --- a/storage/xtradb/include/os0sync.h +++ b/storage/xtradb/include/os0sync.h @@ -452,7 +452,7 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ # define os_atomic_test_and_set_ulint(ptr, new_val) \ __sync_lock_test_and_set(ptr, new_val) -#ifdef __powerpc__ +#if defined(__powerpc__) || defined(__aarch64__) /* os_atomic_test_and_set_byte_release() should imply a release barrier before setting, and a full barrier after. But __sync_lock_test_and_set() is only @@ -531,7 +531,7 @@ amount of increment. */ os_atomic_increment_ulint((ulong_t*) ptr, amount) # define os_atomic_increment_uint64(ptr, amount) \ - atomic_add_64_nv(ptr, amount) + atomic_add_64_nv((uint64_t *) ptr, amount) /* Returns the resulting value, ptr is pointer to target, amount is the amount to decrement. */ diff --git a/storage/xtradb/include/row0merge.h b/storage/xtradb/include/row0merge.h index 390c0ce038b..de353d46202 100644 --- a/storage/xtradb/include/row0merge.h +++ b/storage/xtradb/include/row0merge.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 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 @@ -95,6 +95,7 @@ struct index_field_t { ulint col_no; /*!< column offset */ ulint prefix_len; /*!< column prefix length, or 0 if indexing the whole column */ + const char* col_name; /*!< column name or NULL */ }; /** Definition of an index being created */ diff --git a/storage/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic index 8aadc406132..d481d14009b 100644 --- a/storage/xtradb/include/sync0rw.ic +++ b/storage/xtradb/include/sync0rw.ic @@ -511,6 +511,7 @@ rw_lock_x_lock_func_nowait( ulint line) /*!< in: line where requested */ { ibool success; + ibool local_recursive= lock->recursive; #ifdef INNODB_RW_LOCKS_USE_ATOMICS success = os_compare_and_swap_lint(&lock->lock_word, X_LOCK_DECR, 0); @@ -525,10 +526,14 @@ rw_lock_x_lock_func_nowait( mutex_exit(&(lock->mutex)); #endif + /* Note: recursive must be loaded before writer_thread see + comment for rw_lock_set_writer_id_and_recursion_flag(). + To achieve this we load it before os_compare_and_swap_lint(), + which implies full memory barrier in current implementation. */ if (success) { rw_lock_set_writer_id_and_recursion_flag(lock, TRUE); - } else if (lock->recursive + } else if (local_recursive && os_thread_eq(lock->writer_thread, os_thread_get_curr_id())) { /* Relock: this lock_word modification is safe since no other diff --git a/storage/xtradb/include/sync0sync.h b/storage/xtradb/include/sync0sync.h index 788f765f919..ffe2d635fbd 100644 --- a/storage/xtradb/include/sync0sync.h +++ b/storage/xtradb/include/sync0sync.h @@ -69,7 +69,6 @@ instrumentation due to their large number of instances. */ /* Key defines to register InnoDB mutexes with performance schema */ extern mysql_pfs_key_t autoinc_mutex_key; extern mysql_pfs_key_t buffer_block_mutex_key; -extern mysql_pfs_key_t buf_pool_mutex_key; extern mysql_pfs_key_t buf_pool_zip_mutex_key; extern mysql_pfs_key_t buf_pool_LRU_list_mutex_key; extern mysql_pfs_key_t buf_pool_free_list_mutex_key; diff --git a/storage/xtradb/include/trx0roll.h b/storage/xtradb/include/trx0roll.h index aa3dbb1f6cd..629b41569f6 100644 --- a/storage/xtradb/include/trx0roll.h +++ b/storage/xtradb/include/trx0roll.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 @@ -33,6 +33,8 @@ Created 3/26/1996 Heikki Tuuri #include "mtr0mtr.h" #include "trx0sys.h" +extern bool trx_rollback_or_clean_is_active; + /*******************************************************************//** Determines if this transaction is rolling back an incomplete transaction in crash recovery. diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index c97be0e4f03..fc1871d438e 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2015, MariaDB Corporation 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 @@ -1058,6 +1059,20 @@ struct trx_t{ #define DPAH_SIZE 8192 byte* distinct_page_access_hash; ibool take_stats; + + /* Lock wait statistics */ + ulint n_rec_lock_waits; + /*!< Number of record lock waits, + might not be exactly correct. */ + ulint n_table_lock_waits; + /*!< Number of table lock waits, + might not be exactly correct. */ + ulint total_rec_lock_wait_time; + /*!< Total rec lock wait time up + to this moment. */ + ulint total_table_lock_wait_time; + /*!< Total table lock wait time + up to this moment. */ }; /* Transaction isolation levels (trx->isolation_level) */ diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 24145d1cbb7..6b0c33df44c 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -45,10 +45,10 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 22 +#define INNODB_VERSION_BUGFIX 24 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 71.0 +#define PERCONA_INNODB_VERSION 72.2 #endif /* Enable UNIV_LOG_ARCHIVE in XtraDB */ diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index f8fc351aa92..e76bb0e2c62 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2014, 2015, MariaDB Corporation 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 @@ -374,7 +375,7 @@ struct lock_stack_t { ulint heap_no; /*!< heap number if rec lock */ }; -extern "C" void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd); +extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd); extern "C" int thd_need_wait_for(const MYSQL_THD thd); extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); @@ -384,8 +385,10 @@ because there is no parallel deadlock check. This stack is protected by the lock_sys_t::mutex. */ static lock_stack_t* lock_stack; +#ifdef UNIV_DEBUG /** The count of the types of locks. */ static const ulint lock_types = UT_ARR_SIZE(lock_compatibility_matrix); +#endif /* UNIV_DEBUG */ #ifdef UNIV_PFS_MUTEX /* Key to register mutex with performance schema */ @@ -1897,6 +1900,9 @@ lock_rec_create( /* Set the bit corresponding to rec */ lock_rec_set_nth_bit(lock, heap_no); + lock->requested_time = ut_time(); + lock->wait_time = 0; + index->table->n_rec_locks++; ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); @@ -2055,6 +2061,8 @@ lock_rec_enqueue_waiting( MONITOR_INC(MONITOR_LOCKREC_WAIT); + trx->n_rec_lock_waits++; + return(DB_LOCK_WAIT); } @@ -2087,7 +2095,8 @@ lock_rec_add_to_queue( ut_ad(lock_mutex_own()); ut_ad(caller_owns_trx_mutex == trx_mutex_own(trx)); - ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index)); + ut_ad(dict_index_is_clust(index) + || dict_index_get_online_status(index) != ONLINE_INDEX_CREATION); #ifdef UNIV_DEBUG switch (type_mode & LOCK_MODE_MASK) { case LOCK_X: @@ -2474,6 +2483,17 @@ lock_grant( } } + /* Cumulate total lock wait time for statistics */ + if (lock_get_type_low(lock) & LOCK_TABLE) { + lock->trx->total_table_lock_wait_time += + (ulint)difftime(ut_time(), lock->trx->lock.wait_started); + } else { + lock->trx->total_rec_lock_wait_time += + (ulint)difftime(ut_time(), lock->trx->lock.wait_started); + } + + lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time); + trx_mutex_exit(lock->trx); } @@ -4239,6 +4259,8 @@ lock_table_create( lock->type_mode = type_mode | LOCK_TABLE; lock->trx = trx; + lock->requested_time = ut_time(); + lock->wait_time = 0; lock->un_member.tab_lock.table = table; @@ -4484,6 +4506,7 @@ lock_table_enqueue_waiting( trx->lock.wait_started = ut_time(); trx->lock.was_chosen_as_deadlock_victim = FALSE; + trx->n_table_lock_waits++; if (UNIV_UNLIKELY(trx->take_stats)) { ut_usectime(&sec, &ms); @@ -5168,6 +5191,10 @@ lock_table_print( fputs(" waiting", file); } + fprintf(file, " lock hold time %lu wait time before grant %lu ", + (ulint)difftime(ut_time(), lock->requested_time), + lock->wait_time); + putc('\n', file); } @@ -5199,7 +5226,14 @@ lock_rec_print( fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu ", (ulong) space, (ulong) page_no, (ulong) lock_rec_get_n_bits(lock)); + dict_index_name_print(file, lock->trx, lock->index); + + /* Print number of table locks */ + fprintf(file, " trx table locks %lu total table locks %lu ", + ib_vector_size(lock->trx->lock.table_locks), + UT_LIST_GET_LEN(lock->index->table->locks)); + fprintf(file, " trx id " TRX_ID_FMT, lock->trx->id); if (lock_get_mode(lock) == LOCK_S) { @@ -5228,6 +5262,10 @@ lock_rec_print( mtr_start(&mtr); + fprintf(file, " lock hold time %lu wait time before grant %lu ", + (ulint)difftime(ut_time(), lock->requested_time), + lock->wait_time); + putc('\n', file); if ( srv_show_verbose_locks ) { @@ -5488,6 +5526,14 @@ loop: trx->read_view->up_limit_id); } + /* Total trx lock waits and times */ + fprintf(file, "Trx #rec lock waits %lu #table lock waits %lu\n", + trx->n_rec_lock_waits, trx->n_table_lock_waits); + fprintf(file, "Trx total rec lock wait time %lu SEC\n", + trx->total_rec_lock_wait_time); + fprintf(file, "Trx total table lock wait time %lu SEC\n", + trx->total_table_lock_wait_time); + if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) { fprintf(file, @@ -5506,7 +5552,7 @@ loop: } } - if (!srv_print_innodb_lock_monitor && !srv_show_locks_held) { + if (!srv_print_innodb_lock_monitor || !srv_show_locks_held) { nth_trx++; goto loop; } diff --git a/storage/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc index 031926fd91f..903bdab02ce 100644 --- a/storage/xtradb/log/log0log.cc +++ b/storage/xtradb/log/log0log.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -55,6 +55,7 @@ Created 12/9/1995 Heikki Tuuri #include "srv0start.h" #include "trx0sys.h" #include "trx0trx.h" +#include "trx0roll.h" #include "srv0mon.h" /* @@ -3514,6 +3515,12 @@ logs_empty_and_mark_files_at_shutdown(void) if (log_disable_checkpoint_active) log_enable_checkpoint(); + while (srv_fast_shutdown == 0 && trx_rollback_or_clean_is_active) { + /* we should wait until rollback after recovery end + for slow shutdown */ + os_thread_sleep(100000); + } + /* Wait until the master thread and all other operations are idle: our algorithm only works if the server is idle at shutdown */ diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc index 7bda744704b..42c238810e8 100644 --- a/storage/xtradb/log/log0recv.cc +++ b/storage/xtradb/log/log0recv.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. Copyright (c) 2013, SkySQL Ab. All Rights Reserved. @@ -1934,7 +1934,7 @@ loop: goto loop; } - ut_ad(!allow_ibuf == mutex_own(&log_sys->mutex)); + ut_ad((!allow_ibuf) == mutex_own(&log_sys->mutex)); if (!allow_ibuf) { recv_no_ibuf_operations = TRUE; @@ -3581,6 +3581,7 @@ recv_recovery_rollback_active(void) /* Rollback the uncommitted transactions which have no user session */ + trx_rollback_or_clean_is_active = true; os_thread_create(trx_rollback_or_clean_all_recovered, 0, 0); } } diff --git a/storage/xtradb/mtr/mtr0log.cc b/storage/xtradb/mtr/mtr0log.cc index 0660c819240..5335cb4c9ef 100644 --- a/storage/xtradb/mtr/mtr0log.cc +++ b/storage/xtradb/mtr/mtr0log.cc @@ -560,7 +560,7 @@ mlog_parse_index( n = n_uniq = 1; } table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n, - comp ? DICT_TF_COMPACT : 0, 0, true); + comp ? DICT_TF_COMPACT : 0, 0); ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY", DICT_HDR_SPACE, 0, n); ind->table = table; diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index be6f328aaac..28f1b156224 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Copyright (c) 2013, 2015, MariaDB Corporation. @@ -870,6 +870,7 @@ os_file_handle_error_cond_exit( fflush(stderr); + ut_error; return(FALSE); case OS_FILE_AIO_RESOURCES_RESERVED: @@ -3126,7 +3127,6 @@ try_again: ret = os_file_pread(file, buf, n, offset, trx); if ((ulint) ret == n) { - /* Note that InnoDB writes files that are not formated as file spaces and they do not have FIL_PAGE_TYPE field, thus we must use here information is the actual @@ -3136,11 +3136,17 @@ try_again: } return(TRUE); + } else if (ret == -1) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Error in system call pread(). The operating" + " system error number is %lu.",(ulint) errno); + } else { + /* Partial read occured */ + ib_logf(IB_LOG_LEVEL_ERROR, + "Tried to read " ULINTPF " bytes at offset " + UINT64PF ". Was only able to read %ld.", + n, offset, (lint) ret); } - - ib_logf(IB_LOG_LEVEL_ERROR, - "Tried to read " ULINTPF " bytes at offset " UINT64PF ". " - "Was only able to read %ld.", n, offset, (lint) ret); #endif /* __WIN__ */ retry = os_file_handle_error(NULL, "read", __FILE__, __LINE__); @@ -3244,7 +3250,6 @@ try_again: ret = os_file_pread(file, buf, n, offset, NULL); if ((ulint) ret == n) { - /* Note that InnoDB writes files that are not formated as file spaces and they do not have FIL_PAGE_TYPE field, thus we must use here information is the actual @@ -3254,6 +3259,16 @@ try_again: } return(TRUE); + } else if (ret == -1) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Error in system call pread(). The operating" + " system error number is %lu.",(ulint) errno); + } else { + /* Partial read occured */ + ib_logf(IB_LOG_LEVEL_ERROR, + "Tried to read " ULINTPF " bytes at offset " + UINT64PF ". Was only able to read %ld.", + n, offset, (lint) ret); } #endif /* __WIN__ */ retry = os_file_handle_error_no_exit(NULL, "read", FALSE, __FILE__, __LINE__); @@ -3434,18 +3449,26 @@ retry: ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: Write to file %s failed" - " at offset " UINT64PF ".\n" - "InnoDB: %lu bytes should have been written," - " only %ld were written.\n" - "InnoDB: Operating system error number %lu.\n" - "InnoDB: Check that your OS and file system" - " support files of this size.\n" - "InnoDB: Check also that the disk is not full" - " or a disk quota exceeded.\n", - name, offset, n, (lint) ret, - (ulint) errno); + if(ret == -1) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Failure of system call pwrite(). Operating" + " system error number is %lu.", + (ulint) errno); + } else { + fprintf(stderr, + " InnoDB: Error: Write to file %s failed" + " at offset " UINT64PF ".\n" + "InnoDB: %lu bytes should have been written," + " only %ld were written.\n" + "InnoDB: Operating system error number %lu.\n" + "InnoDB: Check that your OS and file system" + " support files of this size.\n" + "InnoDB: Check also that the disk is not full" + " or a disk quota exceeded.\n", + name, offset, n, (lint) ret, + (ulint) errno); + } + if (strerror(errno) != NULL) { fprintf(stderr, "InnoDB: Error number %d means '%s'.\n", @@ -5088,7 +5111,7 @@ os_aio_func( mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER); DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", - mode = OS_AIO_SYNC;); + mode = OS_AIO_SYNC; os_has_said_disk_full = FALSE;); if (mode == OS_AIO_SYNC) { ibool ret; @@ -5096,10 +5119,9 @@ os_aio_func( no need to use an i/o-handler thread */ if (type == OS_FILE_READ) { - ret = os_file_read_func(file, buf, offset, n, trx, - page_compression); - } - else { + ret = os_file_read_func(file, buf, offset, n, trx, page_compression); + + } else { ut_ad(!srv_read_only_mode); ut_a(type == OS_FILE_WRITE); @@ -5108,6 +5130,9 @@ os_aio_func( DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", os_has_said_disk_full = FALSE; ret = 0; errno = 28;); + if (!ret) { + os_file_handle_error_cond_exit(name, "os_file_write_func", TRUE, FALSE, __FILE__, __LINE__); + } } return ret; @@ -5996,6 +6021,14 @@ consecutive_loop: ret = os_file_write( aio_slot->name, aio_slot->file, combined_buf, aio_slot->offset, total_len); + + DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28", + os_has_said_disk_full = FALSE; ret = 0; errno = 28;); + + if (!ret) { + os_file_handle_error_cond_exit(aio_slot->name, "os_file_write_func", TRUE, FALSE, __FILE__, __LINE__); + } + } else { ret = os_file_read( aio_slot->file, combined_buf, @@ -6003,11 +6036,6 @@ consecutive_loop: aio_slot->page_compression); } - if (aio_slot->type == OS_FILE_WRITE) { - DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28_2", - os_has_said_disk_full = FALSE; ret = 0; errno = 28;); - } - srv_set_io_thread_op_info(global_segment, "file i/o done"); if (aio_slot->type == OS_FILE_READ && n_consecutive > 1) { diff --git a/storage/xtradb/os/os0sync.cc b/storage/xtradb/os/os0sync.cc index 451ba5285e3..03c53848832 100644 --- a/storage/xtradb/os/os0sync.cc +++ b/storage/xtradb/os/os0sync.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, 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 @@ -234,24 +234,6 @@ os_cond_broadcast( } /*********************************************************//** -Wakes one thread waiting for condition variable */ -UNIV_INLINE -void -os_cond_signal( -/*==========*/ - os_cond_t* cond) /*!< in: condition variable. */ -{ - ut_a(cond); - -#ifdef __WIN__ - ut_a(wake_condition_variable != NULL); - wake_condition_variable(cond); -#else - ut_a(pthread_cond_signal(cond) == 0); -#endif -} - -/*********************************************************//** Destroys condition variable */ UNIV_INLINE void diff --git a/storage/xtradb/page/page0zip.cc b/storage/xtradb/page/page0zip.cc index 535497480b7..d3ac5b261a4 100644 --- a/storage/xtradb/page/page0zip.cc +++ b/storage/xtradb/page/page0zip.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. Copyright (c) 2014, SkySQL Ab. All Rights Reserved. @@ -1601,7 +1601,7 @@ page_zip_fields_free( { if (index) { dict_table_t* table = index->table; - os_fast_mutex_free(&index->zip_pad.mutex); + dict_index_zip_pad_mutex_destroy(index); mem_heap_free(index->heap); dict_mem_table_free(table); @@ -1652,7 +1652,7 @@ page_zip_fields_decode( } table = dict_mem_table_create("ZIP_DUMMY", DICT_HDR_SPACE, n, - DICT_TF_COMPACT, 0, true); + DICT_TF_COMPACT, 0); index = dict_mem_index_create("ZIP_DUMMY", "ZIP_DUMMY", DICT_HDR_SPACE, 0, n); index->table = table; diff --git a/storage/xtradb/pars/pars0pars.cc b/storage/xtradb/pars/pars0pars.cc index f051481184b..655e5ba1324 100644 --- a/storage/xtradb/pars/pars0pars.cc +++ b/storage/xtradb/pars/pars0pars.cc @@ -1997,7 +1997,7 @@ pars_create_table( n_cols = que_node_list_get_len(column_defs); table = dict_mem_table_create( - table_sym->name, 0, n_cols, flags, flags2, false); + table_sym->name, 0, n_cols, flags, flags2); #ifdef UNIV_DEBUG if (not_fit_in_memory != NULL) { diff --git a/storage/xtradb/que/que0que.cc b/storage/xtradb/que/que0que.cc index 8d9b8fac776..e2dc0239e13 100644 --- a/storage/xtradb/que/que0que.cc +++ b/storage/xtradb/que/que0que.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, 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 @@ -390,32 +390,6 @@ que_fork_start_command( return(thr); } -/****************************************************************//** -Tests if all the query threads in the same fork have a given state. -@return TRUE if all the query threads in the same fork were in the -given state */ -UNIV_INLINE -ibool -que_fork_all_thrs_in_state( -/*=======================*/ - que_fork_t* fork, /*!< in: query fork */ - ulint state) /*!< in: state */ -{ - que_thr_t* thr_node; - - for (thr_node = UT_LIST_GET_FIRST(fork->thrs); - thr_node != NULL; - thr_node = UT_LIST_GET_NEXT(thrs, thr_node)) { - - if (thr_node->state != state) { - - return(FALSE); - } - } - - return(TRUE); -} - /**********************************************************************//** Calls que_graph_free_recursive for statements in a statement list. */ static diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc index 0d7b7c16785..c5cc9f02f04 100644 --- a/storage/xtradb/rem/rem0rec.cc +++ b/storage/xtradb/rem/rem0rec.cc @@ -842,7 +842,7 @@ rec_get_converted_size_comp_prefix_low( } ut_ad(len <= col->len || col->mtype == DATA_BLOB - || (col->len == 0 && col->mtype == DATA_VARCHAR)); + || (col->len == 0 && col->mtype == DATA_VARCHAR)); fixed_len = field->fixed_len; if (temp && fixed_len diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index e27c4c2805a..e38d9ef6276 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2010, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2010, 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 diff --git a/storage/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc index 42c0ae928d5..bba8c32b752 100644 --- a/storage/xtradb/row/row0log.cc +++ b/storage/xtradb/row/row0log.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2015, 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 @@ -1382,6 +1382,27 @@ blob_done: dfield_set_data(dfield, data, len); } + if (len != UNIV_SQL_NULL && col->mtype == DATA_MYSQL + && col->len != len && !dict_table_is_comp(log->table)) { + + ut_ad(col->len >= len); + if (dict_table_is_comp(index->table)) { + byte* buf = (byte*) mem_heap_alloc(heap, + col->len); + memcpy(buf, dfield->data, len); + memset(buf + len, 0x20, col->len - len); + + dfield_set_data(dfield, buf, col->len); + } else { + /* field length mismatch should not happen + when rebuilding the redundant row format + table. */ + ut_ad(0); + *error = DB_CORRUPTION; + return(NULL); + } + } + /* See if any columns were changed to NULL or NOT NULL. */ const dict_col_t* new_col = dict_table_get_nth_col(log->table, col_no); diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index ae9ea0c4979..58c700f08e5 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 2015, 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 @@ -235,22 +235,88 @@ row_merge_buf_free( mem_heap_free(buf->heap); } -/******************************************************//** -Insert a data tuple into a sort buffer. -@return number of rows added, 0 if out of space */ +/** Convert the field data from compact to redundant format. +@param[in] row_field field to copy from +@param[out] field field to copy to +@param[in] len length of the field data +@param[in] zip_size compressed BLOB page size, + zero for uncompressed BLOBs +@param[in,out] heap memory heap where to allocate data when + converting to ROW_FORMAT=REDUNDANT, or NULL + when not to invoke + row_merge_buf_redundant_convert(). */ +static +void +row_merge_buf_redundant_convert( + const dfield_t* row_field, + dfield_t* field, + ulint len, + ulint zip_size, + mem_heap_t* heap, + trx_t* trx) +{ + ut_ad(DATA_MBMINLEN(field->type.mbminmaxlen) == 1); + ut_ad(DATA_MBMAXLEN(field->type.mbminmaxlen) > 1); + + byte* buf = (byte*) mem_heap_alloc(heap, len); + ulint field_len = row_field->len; + ut_ad(field_len <= len); + + if (row_field->ext) { + const byte* field_data = static_cast<byte*>( + dfield_get_data(row_field)); + ulint ext_len; + + ut_a(field_len >= BTR_EXTERN_FIELD_REF_SIZE); + ut_a(memcmp(field_data + field_len - BTR_EXTERN_FIELD_REF_SIZE, + field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE)); + + byte* data = btr_copy_externally_stored_field( + &ext_len, field_data, zip_size, field_len, heap, trx); + + ut_ad(ext_len < len); + + memcpy(buf, data, ext_len); + field_len = ext_len; + } else { + memcpy(buf, row_field->data, field_len); + } + + memset(buf + field_len, 0x20, len - field_len); + + dfield_set_data(field, buf, len); +} + +/** Insert a data tuple into a sort buffer. +@param[in,out] buf sort buffer +@param[in] fts_index fts index to be created +@param[in] old_table original table +@param[in,out] psort_info parallel sort info +@param[in] row table row +@param[in] ext cache of externally stored + column prefixes, or NULL +@param[in,out] doc_id Doc ID if we are creating + FTS index +@param[in,out] conv_heap memory heap where to allocate data when + converting to ROW_FORMAT=REDUNDANT, or NULL + when not to invoke + row_merge_buf_redundant_convert() +@param[in,out] exceed_page set if the record size exceeds the page size + when converting to ROW_FORMAT=REDUNDANT +@return number of rows added, 0 if out of space */ static ulint row_merge_buf_add( -/*==============*/ - row_merge_buf_t* buf, /*!< in/out: sort buffer */ - dict_index_t* fts_index,/*!< in: fts index to be created */ - const dict_table_t* old_table,/*!< in: original table */ - fts_psort_t* psort_info, /*!< in: parallel sort info */ - const dtuple_t* row, /*!< in: table row */ - const row_ext_t* ext, /*!< in: cache of externally stored - column prefixes, or NULL */ - doc_id_t* doc_id) /*!< in/out: Doc ID if we are - creating FTS index */ + row_merge_buf_t* buf, + dict_index_t* fts_index, + const dict_table_t* old_table, + fts_psort_t* psort_info, + const dtuple_t* row, + const row_ext_t* ext, + doc_id_t* doc_id, + mem_heap_t* conv_heap, + bool* exceed_page, + trx_t* trx) { ulint i; const dict_index_t* index; @@ -400,6 +466,23 @@ row_merge_buf_add( n_row_added = 1; continue; } + + if (field->len != UNIV_SQL_NULL + && col->mtype == DATA_MYSQL + && col->len != field->len) { + + if (conv_heap != NULL) { + row_merge_buf_redundant_convert( + row_field, field, col->len, + dict_table_zip_size(old_table), + conv_heap, trx); + } else { + /* Field length mismatch should not + happen when rebuilding redundant row + format table. */ + ut_ad(dict_table_is_comp(index->table)); + } + } } len = dfield_get_len(field); @@ -508,6 +591,14 @@ row_merge_buf_add( of extra_size. */ data_size += (extra_size + 1) + ((extra_size + 1) >= 0x80); + /* Record size can exceed page size while converting to + redundant row format. But there is assert + ut_ad(size < UNIV_PAGE_SIZE) in rec_offs_data_size(). + It may hit the assert before attempting to insert the row. */ + if (conv_heap != NULL && data_size > UNIV_PAGE_SIZE) { + *exceed_page = true; + } + ut_ad(data_size < srv_sort_buf_size); /* Reserve one byte for the end marker of row_merge_block_t. */ @@ -527,6 +618,10 @@ row_merge_buf_add( dfield_dup(field++, buf->heap); } while (--n_fields); + if (conv_heap != NULL) { + mem_heap_empty(conv_heap); + } + DBUG_RETURN(n_row_added); } @@ -1209,6 +1304,7 @@ row_merge_read_clustered_index( os_event_t fts_parallel_sort_event = NULL; ibool fts_pll_sort = FALSE; ib_int64_t sig_count = 0; + mem_heap_t* conv_heap = NULL; DBUG_ENTER("row_merge_read_clustered_index"); ut_ad((old_table == new_table) == !col_map); @@ -1304,6 +1400,11 @@ row_merge_read_clustered_index( row_heap = mem_heap_create(sizeof(mrec_buf_t)); + if (dict_table_is_comp(old_table) + && !dict_table_is_comp(new_table)) { + conv_heap = mem_heap_create(sizeof(mrec_buf_t)); + } + /* Scan the clustered index. */ for (;;) { const rec_t* rec; @@ -1588,16 +1689,24 @@ write_buffers: row_merge_buf_t* buf = merge_buf[i]; merge_file_t* file = &files[i]; ulint rows_added = 0; + bool exceed_page = false; if (UNIV_LIKELY (row && (rows_added = row_merge_buf_add( buf, fts_index, old_table, - psort_info, row, ext, &doc_id)))) { + psort_info, row, ext, &doc_id, + conv_heap, &exceed_page, trx)))) { /* If we are creating FTS index, a single row can generate more records for tokenized word */ file->n_rec += rows_added; + + if (exceed_page) { + err = DB_TOO_BIG_RECORD; + break; + } + if (doc_id > max_doc_id) { max_doc_id = doc_id; } @@ -1698,12 +1807,18 @@ write_buffers: (!(rows_added = row_merge_buf_add( buf, fts_index, old_table, psort_info, row, ext, - &doc_id)))) { + &doc_id, conv_heap, + &exceed_page, trx)))) { /* An empty buffer should have enough room for at least one record. */ ut_error; } + if (exceed_page) { + err = DB_TOO_BIG_RECORD; + break; + } + file->n_rec += rows_added; } } @@ -1728,6 +1843,10 @@ func_exit: } all_done: + if (conv_heap != NULL) { + mem_heap_free(conv_heap); + } + #ifdef FTS_INTERNAL_DIAG_PRINT DEBUG_FTS_SORT_PRINT("FTS_SORT: Complete Scan Table\n"); #endif @@ -2106,6 +2225,7 @@ row_merge( /* Copy the last blocks, if there are any. */ while (foffs0 < ihalf) { + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { return(DB_INTERRUPTED); } @@ -2122,6 +2242,7 @@ row_merge( ut_ad(foffs0 == ihalf); while (foffs1 < file->offset) { + if (trx_is_interrupted(trx)) { return(DB_INTERRUPTED); } @@ -2181,6 +2302,7 @@ row_merge_sort( { const ulint half = file->offset / 2; ulint num_runs; + ulint cur_run = 0; ulint* run_offset; dberr_t error = DB_SUCCESS; DBUG_ENTER("row_merge_sort"); @@ -2204,11 +2326,19 @@ row_merge_sort( of file marker). Thus, it must be at least one block. */ ut_ad(file->offset > 0); + thd_progress_init(trx->mysql_thd, num_runs); + /* Merge the runs until we have one big run */ do { + cur_run++; + error = row_merge(trx, dup, file, block, tmpfd, &num_runs, run_offset); + /* Report progress of merge sort to MySQL for + show processlist progress field */ + thd_progress_report(trx->mysql_thd, cur_run, num_runs); + if (error != DB_SUCCESS) { break; } @@ -2218,6 +2348,8 @@ row_merge_sort( mem_free(run_offset); + thd_progress_end(trx->mysql_thd); + DBUG_RETURN(error); } @@ -3343,9 +3475,13 @@ row_merge_create_index( for (i = 0; i < n_fields; i++) { index_field_t* ifield = &index_def->fields[i]; + const char * col_name = ifield->col_name ? + dict_table_get_col_name_for_mysql(table, ifield->col_name) : + dict_table_get_col_name(table, ifield->col_no); dict_mem_index_add_field( - index, dict_table_get_col_name(table, ifield->col_no), + index, + col_name, ifield->prefix_len); } diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index 854ebd6f8cc..8dd84f15bea 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2015, 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 @@ -609,6 +609,7 @@ handle_new_error: case DB_DUPLICATE_KEY: case DB_FOREIGN_DUPLICATE_KEY: case DB_TOO_BIG_RECORD: + case DB_TOO_BIG_FOR_REDO: case DB_UNDO_RECORD_TOO_BIG: case DB_ROW_IS_REFERENCED: case DB_NO_REFERENCED_ROW: @@ -1455,6 +1456,11 @@ error_exit: srv_stats.n_rows_inserted.add((size_t)trx->id, 1); } + if (prebuilt->clust_index_was_generated) { + /* set row id to prebuilt */ + ut_memcpy(prebuilt->row_id, node->row_id_buf, DATA_ROW_ID_LEN); + } + /* Not protected by dict_table_stats_lock() for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code @@ -3451,13 +3457,11 @@ row_truncate_table_for_mysql( goto funct_exit; } - if (table->space && !table->dir_path_of_temp_table) { + if (table->space && !DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) { /* Discard and create the single-table tablespace. */ ulint space = table->space; ulint flags = fil_space_get_flags(space); - ut_a(!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)); - dict_get_and_save_data_dir_path(table, true); if (flags != ULINT_UNDEFINED @@ -4257,8 +4261,9 @@ row_drop_table_for_mysql( is_temp = DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY); /* If there is a temp path then the temp flag is set. - However, during recovery, we might have a temp flag but - not know the temp path */ + However, during recovery or reloading the table object + after eviction from data dictionary cache, we might + have a temp flag but not know the temp path */ ut_a(table->dir_path_of_temp_table == NULL || is_temp); if (dict_table_is_discarded(table) || table->ibd_file_missing) { @@ -4387,6 +4392,7 @@ row_drop_table_for_mysql( case DB_OUT_OF_FILE_SPACE: err = DB_MUST_GET_MORE_FILE_SPACE; + trx->error_state = err; row_mysql_handle_errors(&err, trx, NULL, NULL); /* raise error */ @@ -4826,6 +4832,7 @@ row_rename_table_for_mysql( ibool old_is_tmp, new_is_tmp; pars_info_t* info = NULL; int retry; + bool aux_fts_rename = false; ut_a(old_name != NULL); ut_a(new_name != NULL); @@ -5112,34 +5119,8 @@ row_rename_table_for_mysql( if (dict_table_has_fts_index(table) && !dict_tables_have_same_db(old_name, new_name)) { err = fts_rename_aux_tables(table, new_name, trx); - - if (err != DB_SUCCESS && (table->space != 0)) { - char* orig_name = table->name; - trx_t* trx_bg = trx_allocate_for_background(); - - /* If the first fts_rename fails, the trx would - be rolled back and committed, we can't use it any more, - so we have to start a new background trx here. */ - ut_a(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); - trx_bg->op_info = "Revert the failing rename " - "for fts aux tables"; - trx_bg->dict_operation_lock_mode = RW_X_LATCH; - trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); - - /* If rename fails and table has its own tablespace, - we need to call fts_rename_aux_tables again to - revert the ibd file rename, which is not under the - control of trx. Also notice the parent table name - in cache is not changed yet. If the reverting fails, - the ibd data may be left in the new database, which - can be fixed only manually. */ - table->name = const_cast<char*>(new_name); - fts_rename_aux_tables(table, old_name, trx_bg); - table->name = orig_name; - - trx_bg->dict_operation_lock_mode = 0; - trx_commit_for_mysql(trx_bg); - trx_free_for_background(trx_bg); + if (err != DB_TABLE_NOT_FOUND) { + aux_fts_rename = true; } } @@ -5240,6 +5221,37 @@ end: } funct_exit: + if (aux_fts_rename && err != DB_SUCCESS + && table != NULL && (table->space != 0)) { + + char* orig_name = table->name; + trx_t* trx_bg = trx_allocate_for_background(); + + /* If the first fts_rename fails, the trx would + be rolled back and committed, we can't use it any more, + so we have to start a new background trx here. */ + ut_a(trx_state_eq(trx_bg, TRX_STATE_NOT_STARTED)); + trx_bg->op_info = "Revert the failing rename " + "for fts aux tables"; + trx_bg->dict_operation_lock_mode = RW_X_LATCH; + trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); + + /* If rename fails and table has its own tablespace, + we need to call fts_rename_aux_tables again to + revert the ibd file rename, which is not under the + control of trx. Also notice the parent table name + in cache is not changed yet. If the reverting fails, + the ibd data may be left in the new database, which + can be fixed only manually. */ + table->name = const_cast<char*>(new_name); + fts_rename_aux_tables(table, old_name, trx_bg); + table->name = orig_name; + + trx_bg->dict_operation_lock_mode = 0; + trx_commit_for_mysql(trx_bg); + trx_free_for_background(trx_bg); + } + if (table != NULL) { dict_table_close(table, dict_locked, FALSE); } diff --git a/storage/xtradb/row/row0quiesce.cc b/storage/xtradb/row/row0quiesce.cc index 1d67d5a9717..ecd6f47947b 100644 --- a/storage/xtradb/row/row0quiesce.cc +++ b/storage/xtradb/row/row0quiesce.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2012, 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 @@ -680,7 +680,6 @@ row_quiesce_set_state( switch (state) { case QUIESCE_START: - ut_a(table->quiesce == QUIESCE_NONE); break; case QUIESCE_COMPLETE: diff --git a/storage/xtradb/srv/srv0mon.cc b/storage/xtradb/srv/srv0mon.cc index 57409243f5e..5e15dd15db2 100644 --- a/storage/xtradb/srv/srv0mon.cc +++ b/storage/xtradb/srv/srv0mon.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2010, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. Copyright (c) 2013, 2014, MariaDB Corporation @@ -1003,7 +1003,8 @@ static monitor_info_t innodb_counter_info[] = {"adaptive_hash_searches_btree", "adaptive_hash_index", "Number of searches using B-tree on an index search", - MONITOR_NONE, + static_cast<monitor_type_t>( + MONITOR_EXISTING | MONITOR_DEFAULT_ON), MONITOR_DEFAULT_START, MONITOR_OVLD_ADAPTIVE_HASH_SEARCH_BTREE}, {"adaptive_hash_pages_added", "adaptive_hash_index", diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 961182fb9bf..92238cee405 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved. @@ -3319,7 +3319,9 @@ srv_do_purge( *n_total_purged += n_pages_purged; - } while (!srv_purge_should_exit(n_pages_purged) && n_pages_purged > 0); + } while (!srv_purge_should_exit(n_pages_purged) + && n_pages_purged > 0 + && purge_sys->state == PURGE_STATE_RUN); return(rseg_history_len); } diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index fd6ccfe75b1..248f1e4db89 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -133,23 +133,32 @@ UNIV_INTERN enum srv_shutdown_state srv_shutdown_state = SRV_SHUTDOWN_NONE; static os_file_t files[1000]; /** io_handler_thread parameters for thread identification */ -static ulint n[SRV_MAX_N_IO_THREADS + 6]; -/** io_handler_thread identifiers, 32 is the maximum number of purge threads */ -/** 6 is the ? */ -#define START_OLD_THREAD_CNT (SRV_MAX_N_IO_THREADS + 6 + SRV_MAX_N_PURGE_THREADS) -static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 6 + SRV_MAX_N_PURGE_THREADS + MTFLUSH_MAX_WORKER]; +static ulint n[SRV_MAX_N_IO_THREADS]; +/** io_handler_thread identifiers, 32 is the maximum number of purge threads. +The extra elements at the end are allocated as follows: +SRV_MAX_N_IO_THREADS + 1: srv_master_thread +SRV_MAX_N_IO_THREADS + 2: lock_wait_timeout_thread +SRV_MAX_N_IO_THREADS + 3: srv_error_monitor_thread +SRV_MAX_N_IO_THREADS + 4: srv_monitor_thread +SRV_MAX_N_IO_THREADS + 5: srv_redo_log_follow_thread +SRV_MAX_N_IO_THREADS + 6: srv_purge_coordinator_thread +SRV_MAX_N_IO_THREADS + 7: srv_worker_thread +... +SRV_MAX_N_IO_THREADS + 7 + srv_n_purge_threads - 1: srv_worker_thread */ +static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 7 + SRV_MAX_N_PURGE_THREADS + MTFLUSH_MAX_WORKER]; + +/** Thead handles */ +static os_thread_t thread_handles[SRV_MAX_N_IO_THREADS + 7 + SRV_MAX_N_PURGE_THREADS+ MTFLUSH_MAX_WORKER]; /* Thread contex data for multi-threaded flush */ void *mtflush_ctx=NULL; -/** Thead handles */ -static os_thread_t thread_handles[SRV_MAX_N_IO_THREADS + 6 + SRV_MAX_N_PURGE_THREADS]; static os_thread_t buf_flush_page_cleaner_thread_handle; static os_thread_t buf_dump_thread_handle; static os_thread_t dict_stats_thread_handle; static os_thread_t buf_flush_lru_manager_thread_handle; static os_thread_t srv_redo_log_follow_thread_handle; /** Status variables, is thread started ?*/ -static bool thread_started[SRV_MAX_N_IO_THREADS + 6 + SRV_MAX_N_PURGE_THREADS] = {false}; +static bool thread_started[SRV_MAX_N_IO_THREADS + 7 + SRV_MAX_N_PURGE_THREADS] = {false}; static bool buf_flush_page_cleaner_thread_started = false; static bool buf_dump_thread_started = false; static bool dict_stats_thread_started = false; @@ -1891,6 +1900,7 @@ innobase_start_or_create_for_mysql(void) + 1 /* srv_error_monitor_thread */ + 1 /* srv_monitor_thread */ + 1 /* srv_master_thread */ + + 1 /* srv_redo_log_follow_thread */ + 1 /* srv_purge_coordinator_thread */ + 1 /* buf_dump_thread */ + 1 /* dict_stats_thread */ @@ -2798,21 +2808,21 @@ files_checked: if (!srv_read_only_mode && srv_force_recovery < SRV_FORCE_NO_BACKGROUND) { - thread_handles[5 + SRV_MAX_N_IO_THREADS] = os_thread_create( + thread_handles[6 + SRV_MAX_N_IO_THREADS] = os_thread_create( srv_purge_coordinator_thread, - NULL, thread_ids + 5 + SRV_MAX_N_IO_THREADS); + NULL, thread_ids + 6 + SRV_MAX_N_IO_THREADS); - thread_started[5 + SRV_MAX_N_IO_THREADS] = true; + thread_started[6 + SRV_MAX_N_IO_THREADS] = true; ut_a(UT_ARR_SIZE(thread_ids) - > 5 + srv_n_purge_threads + SRV_MAX_N_IO_THREADS); + > 6 + srv_n_purge_threads + SRV_MAX_N_IO_THREADS); /* We've already created the purge coordinator thread above. */ for (i = 1; i < srv_n_purge_threads; ++i) { - thread_handles[5 + i + SRV_MAX_N_IO_THREADS] = os_thread_create( + thread_handles[6 + i + SRV_MAX_N_IO_THREADS] = os_thread_create( srv_worker_thread, NULL, - thread_ids + 5 + i + SRV_MAX_N_IO_THREADS); - thread_started[5 + i + SRV_MAX_N_IO_THREADS] = true; + thread_ids + 6 + i + SRV_MAX_N_IO_THREADS); + thread_started[6 + i + SRV_MAX_N_IO_THREADS] = true; } srv_start_wait_for_purge_to_start(); @@ -3219,9 +3229,9 @@ innobase_shutdown_for_mysql(void) ibuf_close(); log_shutdown(); - lock_sys_close(); trx_sys_file_format_close(); trx_sys_close(); + lock_sys_close(); /* We don't create these mutexes in RO mode because we don't create the temp files that the cover. */ diff --git a/storage/xtradb/sync/sync0rw.cc b/storage/xtradb/sync/sync0rw.cc index 3296e2e74a7..51bfba9950b 100644 --- a/storage/xtradb/sync/sync0rw.cc +++ b/storage/xtradb/sync/sync0rw.cc @@ -694,6 +694,8 @@ rw_lock_x_lock_low( const char* file_name,/*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { + ibool local_recursive= lock->recursive; + if (rw_lock_lock_word_decr(lock, X_LOCK_DECR)) { /* lock->recursive also tells us if the writer_thread @@ -715,12 +717,12 @@ 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 + /* Decrement failed: relock or failed lock + Note: recursive must be loaded before writer_thread see + comment for rw_lock_set_writer_id_and_recursion_flag(). + To achieve this we load it before rw_lock_lock_word_decr(), + which implies full memory barrier in current implementation. */ + if (!pass && local_recursive && os_thread_eq(lock->writer_thread, thread_id)) { /* Relock */ if (lock->lock_word == 0) { diff --git a/storage/xtradb/sync/sync0sync.cc b/storage/xtradb/sync/sync0sync.cc index d02a0df70ca..cfd8f27c389 100644 --- a/storage/xtradb/sync/sync0sync.cc +++ b/storage/xtradb/sync/sync0sync.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -48,6 +48,8 @@ Created 9/5/1995 Heikki Tuuri #include "ha_prototypes.h" #include "my_cpu.h" +#include <vector> + /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX ============================================ @@ -228,14 +230,8 @@ UNIV_INTERN ibool sync_order_checks_on = FALSE; static const ulint SYNC_THREAD_N_LEVELS = 10000; /** Array for tracking sync levels per thread. */ -struct sync_arr_t { - ulint in_use; /*!< Number of active cells */ - ulint n_elems; /*!< Number of elements in the array */ - ulint max_elems; /*!< Maximum elements */ - ulint next_free; /*!< ULINT_UNDEFINED or index of next - free slot */ - sync_level_t* elems; /*!< Array elements */ -}; +typedef std::vector<sync_level_t> sync_arr_t; + /** Mutexes or rw-locks held by a thread */ struct sync_thread_t{ @@ -952,10 +948,10 @@ sync_thread_levels_g( { ulint i; - for (i = 0; i < arr->n_elems; i++) { + for (i = 0; i < arr->size(); i++) { const sync_level_t* slot; - slot = &arr->elems[i]; + slot = (const sync_level_t*)&(arr->at(i)); if (slot->latch != NULL && slot->level <= limit) { if (warn) { @@ -987,10 +983,10 @@ sync_thread_levels_contain( { ulint i; - for (i = 0; i < arr->n_elems; i++) { + for (i = 0; i < arr->size(); i++) { const sync_level_t* slot; - slot = &arr->elems[i]; + slot = (const sync_level_t*)&(arr->at(i)); if (slot->latch != NULL && slot->level == level) { @@ -1034,10 +1030,10 @@ sync_thread_levels_contains( arr = thread_slot->levels; - for (i = 0; i < arr->n_elems; i++) { + for (i = 0; i < arr->size(); i++) { sync_level_t* slot; - slot = &arr->elems[i]; + slot = (sync_level_t*)&(arr->at(i)); if (slot->latch != NULL && slot->level == level) { @@ -1083,10 +1079,10 @@ sync_thread_levels_nonempty_gen( arr = thread_slot->levels; - for (i = 0; i < arr->n_elems; ++i) { + for (i = 0; i < arr->size(); ++i) { const sync_level_t* slot; - slot = &arr->elems[i]; + slot = (const sync_level_t*)&(arr->at(i)); if (slot->latch != NULL && (!dict_mutex_allowed @@ -1143,10 +1139,10 @@ sync_thread_levels_nonempty_trx( arr = thread_slot->levels; - for (i = 0; i < arr->n_elems; ++i) { + for (i = 0; i < arr->size(); ++i) { const sync_level_t* slot; - slot = &arr->elems[i]; + slot = (const sync_level_t*)&(arr->at(i)); if (slot->latch != NULL && (!has_search_latch @@ -1177,10 +1173,9 @@ sync_thread_add_level( SYNC_LEVEL_VARYING, nothing is done */ ibool relock) /*!< in: TRUE if re-entering an x-lock */ { - ulint i; - sync_level_t* slot; sync_arr_t* array; sync_thread_t* thread_slot; + sync_level_t sync_level; if (!sync_order_checks_on) { @@ -1205,21 +1200,11 @@ sync_thread_add_level( thread_slot = sync_thread_level_arrays_find_slot(); if (thread_slot == NULL) { - ulint sz; - - sz = sizeof(*array) - + (sizeof(*array->elems) * SYNC_THREAD_N_LEVELS); /* We have to allocate the level array for a new thread */ - array = static_cast<sync_arr_t*>(calloc(sz, sizeof(char))); + array = new sync_arr_t(); ut_a(array != NULL); - - array->next_free = ULINT_UNDEFINED; - array->max_elems = SYNC_THREAD_N_LEVELS; - array->elems = (sync_level_t*) &array[1]; - thread_slot = sync_thread_level_arrays_find_free(); - thread_slot->levels = array; thread_slot->id = os_thread_get_curr_id(); } @@ -1446,26 +1431,10 @@ sync_thread_add_level( } levels_ok: - if (array->next_free == ULINT_UNDEFINED) { - ut_a(array->n_elems < array->max_elems); - - i = array->n_elems++; - } else { - i = array->next_free; - array->next_free = array->elems[i].level; - } - - ut_a(i < array->n_elems); - ut_a(i != ULINT_UNDEFINED); - - ++array->in_use; - slot = &array->elems[i]; - - ut_a(slot->latch == NULL); - - slot->latch = latch; - slot->level = level; + sync_level.latch = latch; + sync_level.level = level; + array->push_back(sync_level); mutex_exit(&sync_thread_mutex); } @@ -1483,7 +1452,6 @@ sync_thread_reset_level( { sync_arr_t* array; sync_thread_t* thread_slot; - ulint i; if (!sync_order_checks_on) { @@ -1512,36 +1480,15 @@ sync_thread_reset_level( array = thread_slot->levels; - for (i = 0; i < array->n_elems; i++) { - sync_level_t* slot; - - slot = &array->elems[i]; + for (std::vector<sync_level_t>::iterator it = array->begin(); it != array->end(); ++it) { + sync_level_t level = *it; - if (slot->latch != latch) { + if (level.latch != latch) { continue; } - slot->latch = NULL; - - /* Update the free slot list. See comment in sync_level_t - for the level field. */ - slot->level = array->next_free; - array->next_free = i; - - ut_a(array->in_use >= 1); - --array->in_use; - - /* If all cells are idle then reset the free - list. The assumption is that this will save - time when we need to scan up to n_elems. */ - - if (array->in_use == 0) { - array->n_elems = 0; - array->next_free = ULINT_UNDEFINED; - } - + array->erase(it); mutex_exit(&sync_thread_mutex); - return(TRUE); } @@ -1628,8 +1575,7 @@ sync_thread_level_arrays_free(void) /* If this slot was allocated then free the slot memory too. */ if (slot->levels != NULL) { - free(slot->levels); - slot->levels = NULL; + delete slot->levels; } } diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc index a64367c4ba7..e2c3c0b949c 100644 --- a/storage/xtradb/trx/trx0roll.cc +++ b/storage/xtradb/trx/trx0roll.cc @@ -50,6 +50,9 @@ Created 3/26/1996 Heikki Tuuri rollback */ #define TRX_ROLL_TRUNC_THRESHOLD 1 +/** true if trx_rollback_or_clean_all_recovered() thread is active */ +bool trx_rollback_or_clean_is_active; + /** In crash recovery, the current trx to be rolled back; NULL otherwise */ static const trx_t* trx_roll_crash_recv_trx = NULL; @@ -492,7 +495,7 @@ trx_release_savepoint_for_mysql( { trx_named_savept_t* savep; - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); + ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || trx_state_eq(trx, TRX_STATE_PREPARED)); ut_ad(trx->in_mysql_trx_list); savep = trx_savepoint_find(trx, savepoint_name); @@ -805,6 +808,8 @@ DECLARE_THREAD(trx_rollback_or_clean_all_recovered)( trx_rollback_or_clean_recovered(TRUE); + trx_rollback_or_clean_is_active = false; + /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index 5ea63295792..4986ee201f8 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -473,11 +473,12 @@ trx_free_prepared( /*==============*/ trx_t* trx) /*!< in, own: trx object */ { - ut_ad(mutex_own(&trx_sys->mutex)); - ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)); ut_a(trx->magic_n == TRX_MAGIC_N); + mutex_exit(&trx_sys->mutex); + lock_trx_release_locks(trx); + mutex_enter(&trx_sys->mutex); trx_undo_free_prepared(trx); assert_trx_in_rw_list(trx); diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc index 15c7bb503cb..121cbdb7bc0 100644 --- a/storage/xtradb/ut/ut0ut.cc +++ b/storage/xtradb/ut/ut0ut.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 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 @@ -825,6 +825,8 @@ ut_strerr( return("Temp file write failure"); case DB_FTS_TOO_MANY_WORDS_IN_PHRASE: return("Too many words in a FTS phrase or proximity search"); + case DB_TOO_BIG_FOR_REDO: + return("BLOB record length is greater than 10%% of redo log"); /* do not add default: in order to produce a warning if new code is added to the enum but not added here */ |