diff options
Diffstat (limited to 'storage/xtradb')
24 files changed, 712 insertions, 282 deletions
diff --git a/storage/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc index 067cd4e5e1c..caa35d31109 100644 --- a/storage/xtradb/btr/btr0btr.cc +++ b/storage/xtradb/btr/btr0btr.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. Copyright (c) 2014, 2015, MariaDB Corporation @@ -2285,7 +2285,7 @@ the tuple. It is assumed that mtr contains an x-latch on the tree. NOTE that the operation of this function must always succeed, we cannot reverse it: therefore enough free disk space must be guaranteed to be available before this function is called. -@return inserted record */ +@return inserted record or NULL if run out of space */ UNIV_INTERN rec_t* btr_root_raise_and_insert( @@ -2346,6 +2346,11 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); + + if (new_block == NULL && os_has_said_disk_full) { + return(NULL); + } + new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -3130,7 +3135,7 @@ this function is called. NOTE: jonaso added support for calling function with tuple == NULL which cause it to only split a page. -@return inserted record */ +@return inserted record or NULL if run out of space */ UNIV_INTERN rec_t* btr_page_split_and_insert( @@ -3244,9 +3249,18 @@ func_start: } } + DBUG_EXECUTE_IF("disk_is_full", + os_has_said_disk_full = true; + return(NULL);); + /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, btr_page_get_level(page, mtr), mtr, mtr); + + if (new_block == NULL && os_has_said_disk_full) { + return(NULL); + } + new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc index c949bcae476..5bb94dfce2a 100644 --- a/storage/xtradb/btr/btr0cur.cc +++ b/storage/xtradb/btr/btr0cur.cc @@ -1785,6 +1785,10 @@ btr_cur_pessimistic_insert( flags, cursor, offsets, heap, entry, n_ext, mtr); } + if (*rec == NULL && os_has_said_disk_full) { + return(DB_OUT_OF_FILE_SPACE); + } + ut_ad(page_rec_get_next(btr_cur_get_rec(cursor)) == *rec); if (!(flags & BTR_NO_LOCKING_FLAG)) { diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index 037d94dd514..5d64b75784a 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -2251,7 +2251,7 @@ Clears up tail of the LRU lists: * Flush dirty pages at the tail of LRU to the disk The depth to which we scan each buffer pool is controlled by dynamic config parameter innodb_LRU_scan_depth. -@return total pages flushed */ +@return number of pages flushed */ UNIV_INTERN ulint buf_flush_LRU_tail(void) @@ -2671,19 +2671,24 @@ static void page_cleaner_adapt_lru_sleep_time( /*==============================*/ - ulint* lru_sleep_time) /*!< in/out: desired page cleaner thread sleep + ulint* lru_sleep_time, /*!< in/out: desired page cleaner thread sleep time for LRU flushes */ + ulint lru_n_flushed) /*!< in: number of flushed in previous batch */ + { ulint free_len = buf_get_total_free_list_length(); ulint max_free_len = srv_LRU_scan_depth * srv_buf_pool_instances; - if (free_len < max_free_len / 100) { + if (free_len < max_free_len / 100 && lru_n_flushed) { - /* Free lists filled less than 1%, no sleep */ + /* Free lists filled less than 1% + and iteration was able to flush, no sleep */ *lru_sleep_time = 0; - } else if (free_len > max_free_len / 5) { + } else if (free_len > max_free_len / 5 + || (free_len < max_free_len / 100 && lru_n_flushed == 0)) { - /* Free lists filled more than 20%, sleep a bit more */ + /* Free lists filled more than 20% + or no pages flushed in previous batch, sleep a bit more */ *lru_sleep_time += 50; if (*lru_sleep_time > srv_cleaner_max_lru_time) *lru_sleep_time = srv_cleaner_max_lru_time; @@ -2885,6 +2890,7 @@ DECLARE_THREAD(buf_flush_lru_manager_thread)( { ulint next_loop_time = ut_time_ms() + 1000; ulint lru_sleep_time = srv_cleaner_max_lru_time; + ulint lru_n_flushed = 1; #ifdef UNIV_PFS_THREAD pfs_register_thread(buf_lru_manager_thread_key); @@ -2911,11 +2917,11 @@ DECLARE_THREAD(buf_flush_lru_manager_thread)( page_cleaner_sleep_if_needed(next_loop_time); - page_cleaner_adapt_lru_sleep_time(&lru_sleep_time); + page_cleaner_adapt_lru_sleep_time(&lru_sleep_time, lru_n_flushed); next_loop_time = ut_time_ms() + lru_sleep_time; - buf_flush_LRU_tail(); + lru_n_flushed = buf_flush_LRU_tail(); } buf_lru_manager_is_active = false; diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index f6621473077..206038d36c9 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -1659,10 +1659,13 @@ dict_table_rename_in_cache( to preserve the original table name in constraints which reference it */ { + dberr_t err; dict_foreign_t* foreign; dict_index_t* index; ulint fold; char old_name[MAX_FULL_NAME_LEN + 1]; + os_file_type_t ftype; + ibool exists; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1700,8 +1703,6 @@ dict_table_rename_in_cache( .ibd file and rebuild the .isl file if needed. */ if (dict_table_is_discarded(table)) { - os_file_type_t type; - ibool exists; char* filepath; ut_ad(table->space != TRX_SYS_SPACE); @@ -1720,7 +1721,7 @@ dict_table_rename_in_cache( fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE); /* Delete any temp file hanging around. */ - if (os_file_status(filepath, &exists, &type) + if (os_file_status(filepath, &exists, &ftype) && exists && !os_file_delete_if_exists(innodb_file_temp_key, filepath)) { @@ -1732,8 +1733,6 @@ dict_table_rename_in_cache( mem_free(filepath); } else if (table->space != TRX_SYS_SPACE) { - char* new_path = NULL; - if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: trying to rename a" @@ -1747,34 +1746,43 @@ dict_table_rename_in_cache( } return(DB_ERROR); + } - } else if (DICT_TF_HAS_DATA_DIR(table->flags)) { - char* old_path; - - old_path = fil_space_get_first_path(table->space); + char* new_path = NULL; + char* old_path = fil_space_get_first_path(table->space); + if (DICT_TF_HAS_DATA_DIR(table->flags)) { new_path = os_file_make_new_pathname( old_path, new_name); - mem_free(old_path); - - dberr_t err = fil_create_link_file( - new_name, new_path); - + err = fil_create_link_file(new_name, new_path); if (err != DB_SUCCESS) { mem_free(new_path); + mem_free(old_path); return(DB_TABLESPACE_EXISTS); } + } else { + new_path = fil_make_ibd_name(new_name, false); + } + + /* New filepath must not exist. */ + err = fil_rename_tablespace_check( + table->space, old_path, new_path, false); + if (err != DB_SUCCESS) { + mem_free(old_path); + mem_free(new_path); + return(err); } ibool success = fil_rename_tablespace( old_name, table->space, new_name, new_path); + mem_free(old_path); + mem_free(new_path); + /* If the tablespace is remote, a new .isl file was created If success, delete the old one. If not, delete the new one. */ - if (new_path) { - - mem_free(new_path); + if (DICT_TF_HAS_DATA_DIR(table->flags)) { fil_delete_link_file(success ? old_name : new_name); } diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 65827717230..5f0c52b5cc8 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -2994,6 +2994,48 @@ fil_make_isl_name( return(filename); } +/** Test if a tablespace file can be renamed to a new filepath by checking +if that the old filepath exists and the new filepath does not exist. +@param[in] space_id tablespace id +@param[in] old_path old filepath +@param[in] new_path new filepath +@param[in] is_discarded whether the tablespace is discarded +@return innodb error code */ +dberr_t +fil_rename_tablespace_check( + ulint space_id, + const char* old_path, + const char* new_path, + bool is_discarded) +{ + ulint exists = false; + os_file_type_t ftype; + + if (!is_discarded + && os_file_status(old_path, &exists, &ftype) + && !exists) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot rename '%s' to '%s' for space ID %lu" + " because the source file does not exist.", + old_path, new_path, space_id); + + return(DB_TABLESPACE_NOT_FOUND); + } + + exists = false; + if (!os_file_status(new_path, &exists, &ftype) || exists) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot rename '%s' to '%s' for space ID %lu" + " because the target file exists." + " Remove the target file and try again.", + old_path, new_path, space_id); + + return(DB_TABLESPACE_EXISTS); + } + + return(DB_SUCCESS); +} + /*******************************************************************//** Renames a single-table tablespace. The tablespace must be cached in the tablespace memory cache. @@ -6918,31 +6960,110 @@ fil_get_space_names( return(err); } -/****************************************************************//** -Generate redo logs for swapping two .ibd files */ +/** Generate redo log for swapping two .ibd files +@param[in] old_table old table +@param[in] new_table new table +@param[in] tmp_name temporary table name +@param[in,out] mtr mini-transaction +@return innodb error code */ UNIV_INTERN -void +dberr_t fil_mtr_rename_log( -/*===============*/ - ulint old_space_id, /*!< in: tablespace id of the old - table. */ - const char* old_name, /*!< in: old table name */ - ulint new_space_id, /*!< in: tablespace id of the new - table */ - const char* new_name, /*!< in: new table name */ - const char* tmp_name, /*!< in: temp table name used while - swapping */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + const dict_table_t* old_table, + const dict_table_t* new_table, + const char* tmp_name, + mtr_t* mtr) { - if (old_space_id != TRX_SYS_SPACE) { - fil_op_write_log(MLOG_FILE_RENAME, old_space_id, - 0, 0, old_name, tmp_name, mtr); + dberr_t err = DB_SUCCESS; + char* old_path; + + /* If neither table is file-per-table, + there will be no renaming of files. */ + if (old_table->space == TRX_SYS_SPACE + && new_table->space == TRX_SYS_SPACE) { + return(DB_SUCCESS); + } + + if (DICT_TF_HAS_DATA_DIR(old_table->flags)) { + old_path = os_file_make_remote_pathname( + old_table->data_dir_path, old_table->name, "ibd"); + } else { + old_path = fil_make_ibd_name(old_table->name, false); + } + if (old_path == NULL) { + return(DB_OUT_OF_MEMORY); + } + + if (old_table->space != TRX_SYS_SPACE) { + char* tmp_path; + + if (DICT_TF_HAS_DATA_DIR(old_table->flags)) { + tmp_path = os_file_make_remote_pathname( + old_table->data_dir_path, tmp_name, "ibd"); + } + else { + tmp_path = fil_make_ibd_name(tmp_name, false); + } + + if (tmp_path == NULL) { + mem_free(old_path); + return(DB_OUT_OF_MEMORY); + } + + /* Temp filepath must not exist. */ + err = fil_rename_tablespace_check( + old_table->space, old_path, tmp_path, + dict_table_is_discarded(old_table)); + mem_free(tmp_path); + if (err != DB_SUCCESS) { + mem_free(old_path); + return(err); + } + + fil_op_write_log(MLOG_FILE_RENAME, old_table->space, + 0, 0, old_table->name, tmp_name, mtr); } - if (new_space_id != TRX_SYS_SPACE) { - fil_op_write_log(MLOG_FILE_RENAME, new_space_id, - 0, 0, new_name, old_name, mtr); + if (new_table->space != TRX_SYS_SPACE) { + + /* Destination filepath must not exist unless this ALTER + TABLE starts and ends with a file_per-table tablespace. */ + if (old_table->space == TRX_SYS_SPACE) { + char* new_path = NULL; + + if (DICT_TF_HAS_DATA_DIR(new_table->flags)) { + new_path = os_file_make_remote_pathname( + new_table->data_dir_path, + new_table->name, "ibd"); + } + else { + new_path = fil_make_ibd_name( + new_table->name, false); + } + + if (new_path == NULL) { + mem_free(old_path); + return(DB_OUT_OF_MEMORY); + } + + err = fil_rename_tablespace_check( + new_table->space, new_path, old_path, + dict_table_is_discarded(new_table)); + mem_free(new_path); + if (err != DB_SUCCESS) { + mem_free(old_path); + return(err); + } + } + + fil_op_write_log(MLOG_FILE_RENAME, new_table->space, + 0, 0, new_table->name, old_table->name, mtr); + } + + mem_free(old_path); + + return(err); } /************************************************************************* diff --git a/storage/xtradb/fsp/fsp0fsp.cc b/storage/xtradb/fsp/fsp0fsp.cc index 9af25b53a90..790232edb66 100644 --- a/storage/xtradb/fsp/fsp0fsp.cc +++ b/storage/xtradb/fsp/fsp0fsp.cc @@ -961,10 +961,20 @@ fsp_try_extend_data_file( } } else { /* We extend single-table tablespaces first one extent - at a time, but for bigger tablespaces more. It is not - enough to extend always by one extent, because some - extents are frag page extents. */ + at a time, but 4 at a time for bigger tablespaces. It is + not enough to extend always by one extent, because we need + to add at least one extent to FSP_FREE. + A single extent descriptor page will track many extents. + And the extent that uses its extent descriptor page is + put onto the FSP_FREE_FRAG list. Extents that do not + use their extent descriptor page are added to FSP_FREE. + The physical page size is used to determine how many + extents are tracked on one extent descriptor page. */ ulint extent_size; /*!< one megabyte, in pages */ + ulint threshold; /*!< The size of the tablespace + (in number of pages) where we + start allocating more than one + extent at a time. */ if (!zip_size) { extent_size = FSP_EXTENT_SIZE; @@ -973,6 +983,14 @@ fsp_try_extend_data_file( * UNIV_PAGE_SIZE / zip_size; } + /* Threshold is set at 32mb except when the page + size is small enough that it must be done sooner. + For page size less than 4k, we may reach the + extent contains extent descriptor page before + 32 mb. */ + threshold = ut_min((32 * extent_size), + (zip_size ? zip_size : UNIV_PAGE_SIZE)); + if (size < extent_size) { /* Let us first extend the file to extent_size */ success = fsp_try_extend_data_file_with_pages( @@ -989,7 +1007,7 @@ fsp_try_extend_data_file( size = extent_size; } - if (size < 32 * extent_size) { + if (size < threshold) { size_increase = extent_size; } else { /* Below in fsp_fill_free_list() we assume diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 2f989a47d86..89d31619ae2 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -5,7 +5,7 @@ Copyright (c) 2013, 2015, MariaDB Corporation. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. +Copyright (c) 2013, 2014 SkySQL Ab. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -944,12 +944,6 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG}, {"os_log_written", (char*) &export_vars.innodb_os_log_written, SHOW_LONGLONG}, - {"os_merge_buffers_written", - (char*) &export_vars.innodb_merge_buffers_written, SHOW_LONGLONG}, - {"os_merge_buffers_read", - (char*) &export_vars.innodb_merge_buffers_read, SHOW_LONGLONG}, - {"os_merge_buffers_merged", - (char*) &export_vars.innodb_merge_buffers_merged, SHOW_LONGLONG}, {"page_size", (char*) &export_vars.innodb_page_size, SHOW_LONG}, {"pages_created", @@ -1490,7 +1484,6 @@ Normalizes a table name string. A normalized name consists of the database name catenated to '/' and table name. An example: test/mytable. On Windows normalization puts both the database name and the table name always to lower case if "set_lower_case" is set to TRUE. */ -static void normalize_table_name_low( /*=====================*/ @@ -5386,7 +5379,6 @@ Normalizes a table name string. A normalized name consists of the database name catenated to '/' and table name. Example: test/mytable. On Windows normalization puts both the database name and the table name always to lower case if "set_lower_case" is set to TRUE. */ -static void normalize_table_name_low( /*=====================*/ @@ -8323,7 +8315,13 @@ ha_innobase::write_row( ha_statistic_increment(&SSV::ha_write_count); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -8670,7 +8668,13 @@ wsrep_error: func_exit: innobase_active_small(); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -9084,7 +9088,13 @@ ha_innobase::update_row( ha_statistic_increment(&SSV::ha_update_count); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -9199,7 +9209,13 @@ func_exit: wsrep_error: #endif /* WITH_WSREP */ - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -12721,7 +12737,13 @@ ha_innobase::truncate() update_thd(ha_thd()); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -12736,7 +12758,13 @@ ha_innobase::truncate() err = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -14126,7 +14154,13 @@ ha_innobase::analyze( { int ret; - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { return(HA_ADMIN_CORRUPT); } @@ -14136,7 +14170,13 @@ ha_innobase::analyze( HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE, true /* this is ANALYZE */); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { return(HA_ADMIN_CORRUPT); } @@ -15345,7 +15385,13 @@ ha_innobase::transactional_table_lock( update_thd(thd); - if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) { + if (share->ib_table != prebuilt->table) { + fprintf(stderr, + "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %d.", + share->ib_table, prebuilt->table, prebuilt->table->name, prebuilt->table->is_corrupt); + } + + if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt)) { DBUG_RETURN(HA_ERR_CRASHED); } @@ -18445,7 +18491,6 @@ innodb_sched_priority_purge_update( return; } - ut_ad(purge_sys->state == PURGE_STATE_RUN); for (ulint i = 0; i < srv_n_purge_threads; i++) { ulint nice = os_thread_get_priority(srv_purge_tids[i]); ulint actual_priority diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 076c4b6c3b6..ea02463010c 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -167,10 +167,13 @@ my_error_innodb( /* TODO: report the row, as we do for DB_DUPLICATE_KEY */ my_error(ER_INVALID_USE_OF_NULL, MYF(0)); break; + case DB_TABLESPACE_EXISTS: + my_error(ER_TABLESPACE_EXISTS, MYF(0), table); + break; + #ifdef UNIV_DEBUG case DB_SUCCESS: case DB_DUPLICATE_KEY: - case DB_TABLESPACE_EXISTS: case DB_ONLINE_LOG_TOO_BIG: /* These codes should not be passed here. */ ut_error; @@ -202,12 +205,14 @@ innobase_fulltext_exist( /*******************************************************************//** Determine if ALTER TABLE needs to rebuild the table. @param ha_alter_info the DDL operation +@param altered_table MySQL original table @return whether it is necessary to rebuild the table */ static __attribute__((nonnull, warn_unused_result)) bool innobase_need_rebuild( /*==================*/ - const Alter_inplace_info* ha_alter_info) + const Alter_inplace_info* ha_alter_info, + const TABLE* altered_table) { if (ha_alter_info->handler_flags == Alter_inplace_info::CHANGE_CREATE_OPTION @@ -219,6 +224,34 @@ innobase_need_rebuild( return(false); } + /* If alter table changes column name and adds a new + index, we need to check is this new index created + to new column name. This is because column name + changes are done normally after creating indexes. */ + if ((ha_alter_info->handler_flags + & Alter_inplace_info::ALTER_COLUMN_NAME) && + ((ha_alter_info->handler_flags + & Alter_inplace_info::ADD_INDEX) || + (ha_alter_info->handler_flags + & Alter_inplace_info::ADD_FOREIGN_KEY))) { + for (ulint i = 0; i < ha_alter_info->key_count; i++) { + const KEY* key = &ha_alter_info->key_info_buffer[ + ha_alter_info->index_add_buffer[i]]; + + for (ulint j = 0; j < key->user_defined_key_parts; j++) { + const KEY_PART_INFO* key_part = &(key->key_part[j]); + const Field* field = altered_table->field[key_part->fieldnr]; + + /* Field used on added index is renamed on + this same alter table. We need table + rebuild. */ + if (field->flags & FIELD_IS_RENAMED) { + return (true); + } + } + } + } + return(!!(ha_alter_info->handler_flags & INNOBASE_ALTER_REBUILD)); } @@ -557,7 +590,7 @@ ha_innobase::check_if_supported_inplace_alter( operation is possible. */ } else if (((ha_alter_info->handler_flags & Alter_inplace_info::ADD_PK_INDEX) - || innobase_need_rebuild(ha_alter_info)) + || innobase_need_rebuild(ha_alter_info, table)) && (innobase_fulltext_exist(altered_table))) { /* Refuse to rebuild the table online, if fulltext indexes are to survive the rebuild. */ @@ -1558,7 +1591,8 @@ innobase_create_index_def( index_def_t* index, /*!< out: index definition */ mem_heap_t* heap, /*!< in: heap where memory is allocated */ - const Field** fields) /*!z in: MySQL table fields */ + const Field** fields) /*!< in: MySQL table fields + */ { const KEY* key = &keys[key_number]; ulint i; @@ -1854,9 +1888,11 @@ innobase_create_key_defs( bool& add_fts_doc_id, /*!< in: whether we need to add new DOC ID column for FTS index */ - bool& add_fts_doc_idx) + bool& add_fts_doc_idx, /*!< in: whether we need to add new DOC ID index for FTS index */ + const TABLE* table) + /*!< in: MySQL table that is being altered */ { index_def_t* indexdef; index_def_t* indexdefs; @@ -1906,7 +1942,8 @@ innobase_create_key_defs( } const bool rebuild = new_primary || add_fts_doc_id - || innobase_need_rebuild(ha_alter_info); + || innobase_need_rebuild(ha_alter_info, table); + /* Reserve one more space if new_primary is true, and we might need to add the FTS_DOC_ID_INDEX */ indexdef = indexdefs = static_cast<index_def_t*>( @@ -2744,7 +2781,8 @@ prepare_inplace_alter_table_dict( ctx->heap, ha_alter_info, altered_table, ctx->num_to_add_index, num_fts_index, row_table_got_default_clust_index(ctx->new_table), - fts_doc_id_col, add_fts_doc_id, add_fts_doc_id_idx); + fts_doc_id_col, add_fts_doc_id, add_fts_doc_id_idx, + old_table); new_clustered = DICT_CLUSTERED & index_defs[0].ind_type; @@ -2757,7 +2795,7 @@ prepare_inplace_alter_table_dict( /* This is not an online operation (LOCK=NONE). */ } else if (ctx->add_autoinc == ULINT_UNDEFINED && num_fts_index == 0 - && (!innobase_need_rebuild(ha_alter_info) + && (!innobase_need_rebuild(ha_alter_info, old_table) || !innobase_fulltext_exist(altered_table))) { /* InnoDB can perform an online operation (LOCK=NONE). */ } else { @@ -2774,7 +2812,7 @@ prepare_inplace_alter_table_dict( is just copied from old table and stored in indexdefs[0] */ DBUG_ASSERT(!add_fts_doc_id || new_clustered); DBUG_ASSERT(!!new_clustered == - (innobase_need_rebuild(ha_alter_info) + (innobase_need_rebuild(ha_alter_info, old_table) || add_fts_doc_id)); /* Allocate memory for dictionary index definitions */ @@ -3034,7 +3072,7 @@ prepare_inplace_alter_table_dict( add_cols, ctx->heap); ctx->add_cols = add_cols; } else { - DBUG_ASSERT(!innobase_need_rebuild(ha_alter_info)); + DBUG_ASSERT(!innobase_need_rebuild(ha_alter_info, old_table)); if (!ctx->new_table->fts && innobase_fulltext_exist(altered_table)) { @@ -3055,7 +3093,7 @@ prepare_inplace_alter_table_dict( ctx->add_index[a] = row_merge_create_index( ctx->trx, ctx->new_table, - &index_defs[a]); + &index_defs[a], ctx->col_names); add_key_nums[a] = index_defs[a].key_number; @@ -3925,7 +3963,7 @@ err_exit: if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA) || (ha_alter_info->handler_flags == Alter_inplace_info::CHANGE_CREATE_OPTION - && !innobase_need_rebuild(ha_alter_info))) { + && !innobase_need_rebuild(ha_alter_info, table))) { if (heap) { ha_alter_info->handler_ctx @@ -4099,7 +4137,7 @@ ok_exit: if (ha_alter_info->handler_flags == Alter_inplace_info::CHANGE_CREATE_OPTION - && !innobase_need_rebuild(ha_alter_info)) { + && !innobase_need_rebuild(ha_alter_info, table)) { goto ok_exit; } @@ -4811,9 +4849,11 @@ commit_get_autoinc( Field* autoinc_field = old_table->found_next_number_field; + KEY* autoinc_key = + old_table->key_info + old_table->s->next_number_index; - dict_index_t* index = dict_table_get_index_on_first_col( - ctx->old_table, autoinc_field->field_index); + dict_index_t* index = dict_table_get_index_on_name( + ctx->old_table, autoinc_key->name); max_autoinc = ha_alter_info->create_info->auto_increment_value; @@ -5221,6 +5261,61 @@ commit_cache_rebuild( DBUG_VOID_RETURN; } +/** Store the column number of the columns in a list belonging +to indexes which are not being dropped. +@param[in] ctx In-place ALTER TABLE context +@param[out] drop_col_list list which will be set, containing columns + which is part of index being dropped */ +static +void +get_col_list_to_be_dropped( + ha_innobase_inplace_ctx* ctx, + std::set<ulint>& drop_col_list) +{ + for (ulint index_count = 0; index_count < ctx->num_to_drop_index; + index_count++) { + dict_index_t* index = ctx->drop_index[index_count]; + + for (ulint col = 0; col < index->n_user_defined_cols; col++) { + ulint col_no = dict_index_get_nth_col_no(index, col); + drop_col_list.insert(col_no); + } + } +} + +/** For each column, which is part of an index which is not going to be +dropped, it checks if the column number of the column is same as col_no +argument passed. +@param[in] table table object +@param[in] col_no column number of the column which is to be checked +@retval true column exists +@retval false column does not exist. */ +static +bool +check_col_exists_in_indexes( + const dict_table_t* table, + ulint col_no) +{ + for (dict_index_t* index = dict_table_get_first_index(table); index; + index = dict_table_get_next_index(index)) { + + if (index->to_be_dropped) { + continue; + } + + for (ulint col = 0; col < index->n_user_defined_cols; col++) { + + ulint index_col_no = dict_index_get_nth_col_no( + index, col); + if (col_no == index_col_no) { + return(true); + } + } + } + + return(false); +} + /** Commit the changes made during prepare_inplace_alter_table() and inplace_alter_table() inside the data dictionary tables, when not rebuilding the table. @@ -5356,6 +5451,20 @@ commit_cache_norebuild( DBUG_ASSERT(!ctx->need_rebuild()); + std::set<ulint> drop_list; + std::set<ulint>::const_iterator col_it; + + /* Check if the column, part of an index to be dropped is part of any + other index which is not being dropped. If it so, then set the ord_part + of the column to 0. */ + get_col_list_to_be_dropped(ctx, drop_list); + + for(col_it = drop_list.begin(); col_it != drop_list.end(); ++col_it) { + if (!check_col_exists_in_indexes(ctx->new_table, *col_it)) { + ctx->new_table->cols[*col_it].ord_part = 0; + } + } + for (ulint i = 0; i < ctx->num_to_add_index; i++) { dict_index_t* index = ctx->add_index[i]; DBUG_ASSERT(dict_index_get_online_status(index) @@ -5556,6 +5665,7 @@ ha_innobase::commit_inplace_alter_table( Alter_inplace_info* ha_alter_info, bool commit) { + dberr_t error; ha_innobase_inplace_ctx* ctx0 = static_cast<ha_innobase_inplace_ctx*> (ha_alter_info->handler_ctx); @@ -5637,7 +5747,7 @@ ha_innobase::commit_inplace_alter_table( transactions collected during crash recovery could be holding InnoDB locks only, not MySQL locks. */ - dberr_t error = row_merge_lock_table( + error = row_merge_lock_table( prebuilt->trx, ctx->old_table, LOCK_X); if (error != DB_SUCCESS) { @@ -5772,14 +5882,20 @@ ha_innobase::commit_inplace_alter_table( = static_cast<ha_innobase_inplace_ctx*>(*pctx); DBUG_ASSERT(ctx->need_rebuild()); - /* Generate the redo log for the file - operations that will be performed in - commit_cache_rebuild(). */ - fil_mtr_rename_log(ctx->old_table->space, - ctx->old_table->name, - ctx->new_table->space, - ctx->new_table->name, - ctx->tmp_name, &mtr); + /* Check for any possible problems for any + file operations that will be performed in + commit_cache_rebuild(), and if none, generate + the redo log for these operations. */ + error = fil_mtr_rename_log(ctx->old_table, + ctx->new_table, + ctx->tmp_name, &mtr); + if (error != DB_SUCCESS) { + /* Out of memory or a problem will occur + when renaming files. */ + fail = true; + my_error_innodb(error, ctx->old_table->name, + ctx->old_table->flags); + } DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); } @@ -5792,18 +5908,25 @@ ha_innobase::commit_inplace_alter_table( DBUG_EXECUTE_IF("innodb_alter_commit_crash_before_commit", log_buffer_flush_to_disk(); DBUG_SUICIDE();); - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); ut_ad(!trx->fts_trx); - ut_ad(trx->insert_undo || trx->update_undo); - /* The following call commits the - mini-transaction, making the data dictionary - transaction committed at mtr.end_lsn. The - transaction becomes 'durable' by the time when - log_buffer_flush_to_disk() returns. In the - logical sense the commit in the file-based - data structures happens here. */ - trx_commit_low(trx, &mtr); + if (fail) { + mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); + mtr_commit(&mtr); + trx_rollback_for_mysql(trx); + } else { + /* The following call commits the + mini-transaction, making the data dictionary + transaction committed at mtr.end_lsn. The + transaction becomes 'durable' by the time when + log_buffer_flush_to_disk() returns. In the + logical sense the commit in the file-based + data structures happens here. */ + ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); + ut_ad(trx->insert_undo || trx->update_undo); + + trx_commit_low(trx, &mtr); + } /* If server crashes here, the dictionary in InnoDB and MySQL will differ. The .ibd files @@ -5825,7 +5948,6 @@ ha_innobase::commit_inplace_alter_table( update the in-memory structures, close some handles, release temporary files, and (unless we rolled back) update persistent statistics. */ - dberr_t error = DB_SUCCESS; for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { diff --git a/storage/xtradb/include/buf0flu.h b/storage/xtradb/include/buf0flu.h index c51010e33bc..87ce7d88bdf 100644 --- a/storage/xtradb/include/buf0flu.h +++ b/storage/xtradb/include/buf0flu.h @@ -211,7 +211,7 @@ Clears up tail of the LRU lists: * Flush dirty pages at the tail of LRU to the disk The depth to which we scan each buffer pool is controlled by dynamic config parameter innodb_LRU_scan_depth. -@return total pages flushed */ +@return number of pages flushed */ UNIV_INTERN ulint buf_flush_LRU_tail(void); diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 2a3995519a7..973882a50b4 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2015, MariaDB Corporation. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2013, 2016, 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 @@ -699,6 +699,21 @@ fil_discard_tablespace( ulint id) /*!< in: space id */ __attribute__((warn_unused_result)); #endif /* !UNIV_HOTBACKUP */ + +/** Test if a tablespace file can be renamed to a new filepath by checking +if that the old filepath exists and the new filepath does not exist. +@param[in] space_id tablespace id +@param[in] old_path old filepath +@param[in] new_path new filepath +@param[in] is_discarded whether the tablespace is discarded +@return innodb error code */ +dberr_t +fil_rename_tablespace_check( + ulint space_id, + const char* old_path, + const char* new_path, + bool is_discarded); + /*******************************************************************//** Renames a single-table tablespace. The tablespace must be cached in the tablespace memory cache. @@ -1223,21 +1238,19 @@ fil_get_space_names( /*!< in/out: Vector for collecting the names. */ __attribute__((warn_unused_result)); -/****************************************************************//** -Generate redo logs for swapping two .ibd files */ +/** Generate redo log for swapping two .ibd files +@param[in] old_table old table +@param[in] new_table new table +@param[in] tmp_name temporary table name +@param[in,out] mtr mini-transaction +@return innodb error code */ UNIV_INTERN -void +dberr_t fil_mtr_rename_log( -/*===============*/ - ulint old_space_id, /*!< in: tablespace id of the old - table. */ - const char* old_name, /*!< in: old table name */ - ulint new_space_id, /*!< in: tablespace id of the new - table */ - const char* new_name, /*!< in: new table name */ - const char* tmp_name, /*!< in: temp table name used while - swapping */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + const dict_table_t* old_table, + const dict_table_t* new_table, + const char* tmp_name, + mtr_t* mtr) __attribute__((nonnull)); /*******************************************************************//** diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 9ec6a7ff4b4..a9c003d5bb1 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -655,4 +655,18 @@ ib_push_warning( ulint error, /*!< in: error code to push as warning */ const char *format,/*!< in: warning message */ ...); + +/*****************************************************************//** +Normalizes a table name string. A normalized name consists of the +database name catenated to '/' and table name. An example: +test/mytable. On Windows normalization puts both the database name and the +table name always to lower case if "set_lower_case" is set to TRUE. */ +void +normalize_table_name_low( +/*=====================*/ + char* norm_name, /*!< out: normalized name as a + null-terminated string */ + const char* name, /*!< in: table name string */ + ibool set_lower_case); /*!< in: TRUE if we want to set + name to lower case */ #endif /* HA_INNODB_PROTOTYPES_H */ diff --git a/storage/xtradb/include/row0merge.h b/storage/xtradb/include/row0merge.h index 196543f25e1..3e3459b8703 100644 --- a/storage/xtradb/include/row0merge.h +++ b/storage/xtradb/include/row0merge.h @@ -268,8 +268,11 @@ row_merge_create_index( /*===================*/ trx_t* trx, /*!< in/out: trx (sets error_state) */ dict_table_t* table, /*!< in: the index is on this table */ - const index_def_t* index_def); + const index_def_t* index_def, /*!< in: the index definition */ + const char** col_names); + /*! in: column names if columns are + renamed or NULL */ /*********************************************************************//** Check if a transaction can use an index. @return TRUE if index can be used by the transaction else FALSE */ diff --git a/storage/xtradb/include/srv0mon.h b/storage/xtradb/include/srv0mon.h index 658cd94d1ec..33ae7749ca5 100644 --- a/storage/xtradb/include/srv0mon.h +++ b/storage/xtradb/include/srv0mon.h @@ -2,7 +2,7 @@ Copyright (c) 2010, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. +Copyright (c) 2013, 2016, 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 @@ -263,9 +263,6 @@ enum monitor_id_t { MONITOR_OVLD_OS_LOG_FSYNC, MONITOR_OVLD_OS_LOG_PENDING_FSYNC, MONITOR_OVLD_OS_LOG_PENDING_WRITES, - MONITOR_MERGE_BLOCKS_WRITTEN, - MONITOR_MERGE_BLOCKS_READ, - MONITOR_MERGE_BLOCKS_MERGED, /* Transaction related counters */ MONITOR_MODULE_TRX, diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 9a3bf4e74ae..a2d300957ba 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -3,7 +3,7 @@ Copyright (c) 1995, 2015, Oracle and/or its affiliates. Copyright (c) 2008, 2009, Google Inc. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. +Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -186,13 +186,6 @@ struct srv_stats_t { /** Number of lock waits that have been up to max time (i.e.) lock wait timeout */ ulint_ctr_1_t n_lock_max_wait_time; - - /** Number of merge buffers written */ - ulint_ctr_64_t merge_buffers_written; - /** Number of merge buffers read */ - ulint_ctr_64_t merge_buffers_read; - /** Number of merge buffers merged */ - ulint_ctr_64_t merge_buffers_merged; }; extern const char* srv_main_thread_op_info; @@ -1214,9 +1207,6 @@ struct export_var_t{ ulint innodb_purge_view_trx_id_age; /*!< rw_max_trx_id - purged view's min trx_id */ #endif /* UNIV_DEBUG */ - ib_int64_t innodb_merge_buffers_written; - ib_int64_t innodb_merge_buffers_read; - ib_int64_t innodb_merge_buffers_merged; ib_int64_t innodb_page_compression_saved;/*!< Number of bytes saved by page compression */ diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index dabaee4110c..f4a0da12476 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 26 +#define INNODB_VERSION_BUGFIX 28 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 76.0 +#define PERCONA_INNODB_VERSION 76.1 #endif /* Enable UNIV_LOG_ARCHIVE in XtraDB */ diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc index b0e69107723..c9bf5cf3f9e 100644 --- a/storage/xtradb/log/log0recv.cc +++ b/storage/xtradb/log/log0recv.cc @@ -849,6 +849,10 @@ not_consistent: fprintf(stderr, "InnoDB: No valid checkpoint found.\n" + "InnoDB: If you are attempting downgrade" + " from MySQL 5.7.9 or later,\n" + "InnoDB: please refer to " REFMAN + "upgrading-downgrading.html\n" "InnoDB: If this error appears when you are" " creating an InnoDB database,\n" "InnoDB: the problem may be that during" diff --git a/storage/xtradb/row/row0import.cc b/storage/xtradb/row/row0import.cc index ac6380e5a27..893ffcab3da 100644 --- a/storage/xtradb/row/row0import.cc +++ b/storage/xtradb/row/row0import.cc @@ -2070,8 +2070,20 @@ PageConverter::validate( return(IMPORT_PAGE_STATUS_CORRUPTED); } else if (offset > 0 && page_get_page_no(page) == 0) { - const byte* b = page; - const byte* e = b + m_page_size; + ulint checksum; + + checksum = mach_read_from_4(page + FIL_PAGE_SPACE_OR_CHKSUM); + if (checksum != 0) { + /* Checksum check passed in buf_page_is_corrupted(). */ + ib_logf(IB_LOG_LEVEL_WARN, + "%s: Page %lu checksum %lu should be zero.", + m_filepath, (ulong) (offset / m_page_size), + checksum); + } + + const byte* b = page + FIL_PAGE_OFFSET; + const byte* e = page + m_page_size + - FIL_PAGE_END_LSN_OLD_CHKSUM; /* If the page number is zero and offset > 0 then the entire page MUST consist of zeroes. If not then diff --git a/storage/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc index 7014b8b99d2..b0c6f881f81 100644 --- a/storage/xtradb/row/row0log.cc +++ b/storage/xtradb/row/row0log.cc @@ -1462,6 +1462,7 @@ row_log_table_apply_insert_low( dtuple_t* entry; const row_log_t*log = dup->index->online_log; dict_index_t* index = dict_table_get_first_index(log->table); + ulint n_index = 0; ut_ad(dtuple_validate(row)); ut_ad(trx_id); @@ -1497,6 +1498,8 @@ row_log_table_apply_insert_low( } do { + n_index++; + if (!(index = dict_table_get_next_index(index))) { break; } @@ -1509,6 +1512,12 @@ row_log_table_apply_insert_low( error = row_ins_sec_index_entry_low( flags, BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx_id, thr); + + /* Report correct index name for duplicate key error. */ + if (error == DB_DUPLICATE_KEY) { + thr_get_trx(thr)->error_key_num = n_index; + } + } while (error == DB_SUCCESS); return(error); @@ -1816,6 +1825,7 @@ row_log_table_apply_update( mtr_t mtr; btr_pcur_t pcur; dberr_t error; + ulint n_index = 0; ut_ad(dtuple_get_n_fields_cmp(old_pk) == dict_index_get_n_unique(index)); @@ -2091,6 +2101,8 @@ func_exit_committed: break; } + n_index++; + if (index->type & DICT_FTS) { continue; } @@ -2134,6 +2146,11 @@ func_exit_committed: BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx_id, thr); + /* Report correct index name for duplicate key error. */ + if (error == DB_DUPLICATE_KEY) { + thr_get_trx(thr)->error_key_num = n_index; + } + mtr_start(&mtr); } diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index ad3e7619c8a..8d7fcd7388c 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -1,7 +1,6 @@ /***************************************************************************** Copyright (c) 2005, 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 @@ -971,7 +970,6 @@ row_merge_read( success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf, ofs, srv_sort_buf_size); - srv_stats.merge_buffers_read.inc(); /* For encrypted tables, decrypt data after reading and copy data */ if (crypt_data && crypt_buf) { @@ -1027,7 +1025,6 @@ row_merge_write( } ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), out_buf, ofs, buf_len); - srv_stats.merge_buffers_written.inc(); #ifdef UNIV_DEBUG if (row_merge_print_block_write) { @@ -1916,7 +1913,7 @@ write_buffers: /* We have enough data tuples to form a block. Sort them and write to disk. */ - if (UNIV_LIKELY(buf->n_tuples)) { + if (buf->n_tuples) { if (dict_index_is_unique(buf->index)) { row_merge_dup_t dup = { buf->index, table, col_map, 0}; @@ -1957,17 +1954,13 @@ write_buffers: dict_index_get_lock(buf->index)); } - /* Do not write empty buffers to temporary file */ - if (buf->n_tuples) { - - row_merge_buf_write(buf, file, block); + row_merge_buf_write(buf, file, block); - if (!row_merge_write(file->fd, file->offset++, block, - crypt_data, crypt_block, new_table->space)) { - err = DB_TEMP_FILE_WRITE_FAILURE; - trx->error_key_num = i; - break; - } + if (!row_merge_write(file->fd, file->offset++, block, + crypt_data, crypt_block, new_table->space)) { + err = DB_TEMP_FILE_WRITE_FAILURE; + trx->error_key_num = i; + break; } UNIV_MEM_INVALID(&block[0], srv_sort_buf_size); @@ -2284,8 +2277,6 @@ done1: b2, of->fd, &of->offset, crypt_data, crypt_block ? &crypt_block[2 * srv_sort_buf_size] : NULL, space); - srv_stats.merge_buffers_merged.inc(); - return(b2 ? DB_SUCCESS : DB_CORRUPTION); } @@ -3746,8 +3737,11 @@ row_merge_create_index( /*===================*/ trx_t* trx, /*!< in/out: trx (sets error_state) */ dict_table_t* table, /*!< in: the index is on this table */ - const index_def_t* index_def) + const index_def_t* index_def, /*!< in: the index definition */ + const char** col_names) + /*! in: column names if columns are + renamed or NULL */ { dict_index_t* index; dberr_t err; @@ -3767,9 +3761,24 @@ 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); + const char * col_name; + + /* + Alter table renaming a column and then adding a index + to this new name e.g ALTER TABLE t + CHANGE COLUMN b c INT NOT NULL, ADD UNIQUE INDEX (c); + requires additional check as column names are not yet + changed when new index definitions are created. Table's + new column names are on a array of column name pointers + if any of the column names are changed. */ + + if (col_names && col_names[i]) { + col_name = col_names[i]; + } else { + 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, @@ -4110,71 +4119,67 @@ wait_again: #ifdef FTS_INTERNAL_DIAG_PRINT DEBUG_FTS_SORT_PRINT("FTS_SORT: Complete Insert\n"); #endif - } else { - /* Sorting and inserting is required only if - there really is records */ - if (UNIV_LIKELY(merge_files[i].n_rec)) { - char buf[3 * NAME_LEN]; - char *bufend; - row_merge_dup_t dup = { - sort_idx, table, col_map, 0}; + } else if (UNIV_LIKELY(merge_files[i].n_rec)) { + char buf[3 * NAME_LEN]; + char *bufend; + row_merge_dup_t dup = { + sort_idx, table, col_map, 0}; - pct_cost = (COST_BUILD_INDEX_STATIC + - (total_dynamic_cost * merge_files[i].offset / - total_index_blocks)) / - (total_static_cost + total_dynamic_cost) - * PCT_COST_MERGESORT_INDEX * 100; + pct_cost = (COST_BUILD_INDEX_STATIC + + (total_dynamic_cost * merge_files[i].offset / + total_index_blocks)) / + (total_static_cost + total_dynamic_cost) + * PCT_COST_MERGESORT_INDEX * 100; + + bufend = innobase_convert_name(buf, sizeof buf, + indexes[i]->name, strlen(indexes[i]->name), + trx ? trx->mysql_thd : NULL, + FALSE); - bufend = innobase_convert_name(buf, sizeof buf, - indexes[i]->name, strlen(indexes[i]->name), - trx ? trx->mysql_thd : NULL, - FALSE); + buf[bufend - buf]='\0'; - buf[bufend - buf]='\0'; + sql_print_information("InnoDB: Online DDL : Start merge-sorting" + " index %s (%lu / %lu), estimated cost : %2.4f", + buf, (i+1), n_indexes, pct_cost); - sql_print_information("InnoDB: Online DDL : Start merge-sorting" - " index %s (%lu / %lu), estimated cost : %2.4f", - buf, (i+1), n_indexes, pct_cost); + error = row_merge_sort( + trx, &dup, &merge_files[i], + block, &tmpfd, true, + pct_progress, pct_cost, + crypt_data, crypt_block, new_table->space); - error = row_merge_sort( - trx, &dup, &merge_files[i], - block, &tmpfd, true, - pct_progress, pct_cost, - crypt_data, crypt_block, new_table->space); + pct_progress += pct_cost; + + sql_print_information("InnoDB: Online DDL : End of " + " merge-sorting index %s (%lu / %lu)", + buf, (i+1), n_indexes); + + DBUG_EXECUTE_IF( + "ib_merge_wait_after_sort", + os_thread_sleep(20000000);); /* 20 sec */ + if (error == DB_SUCCESS) { + pct_cost = (COST_BUILD_INDEX_STATIC + + (total_dynamic_cost * merge_files[i].offset / + total_index_blocks)) / + (total_static_cost + total_dynamic_cost) * + PCT_COST_INSERT_INDEX * 100; + + sql_print_information("InnoDB: Online DDL : Start " + "building index %s (%lu / %lu), estimated " + "cost : %2.4f", buf, (i+1), + n_indexes, pct_cost); + + error = row_merge_insert_index_tuples( + trx->id, sort_idx, old_table, + merge_files[i].fd, block, + merge_files[i].n_rec, pct_progress, pct_cost, + crypt_data, crypt_block, new_table->space); pct_progress += pct_cost; - sql_print_information("InnoDB: Online DDL : End of " - " merge-sorting index %s (%lu / %lu)", + sql_print_information("InnoDB: Online DDL : " + "End of building index %s (%lu / %lu)", buf, (i+1), n_indexes); - - DBUG_EXECUTE_IF( - "ib_merge_wait_after_sort", - os_thread_sleep(20000000);); /* 20 sec */ - - if (error == DB_SUCCESS) { - pct_cost = (COST_BUILD_INDEX_STATIC + - (total_dynamic_cost * merge_files[i].offset / - total_index_blocks)) / - (total_static_cost + total_dynamic_cost) * - PCT_COST_INSERT_INDEX * 100; - - sql_print_information("InnoDB: Online DDL : Start " - "building index %s (%lu / %lu), estimated " - "cost : %2.4f", buf, (i+1), - n_indexes, pct_cost); - - error = row_merge_insert_index_tuples( - trx->id, sort_idx, old_table, - merge_files[i].fd, block, - merge_files[i].n_rec, pct_progress, pct_cost, - crypt_data, crypt_block, new_table->space); - pct_progress += pct_cost; - - sql_print_information("InnoDB: Online DDL : " - "End of building index %s (%lu / %lu)", - buf, (i+1), n_indexes); - } } } diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index 55e685ac19c..9427b20daf9 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -4894,6 +4894,7 @@ row_rename_table_for_mysql( pars_info_t* info = NULL; int retry; bool aux_fts_rename = false; + char* is_part = NULL; ut_a(old_name != NULL); ut_a(new_name != NULL); @@ -4931,6 +4932,55 @@ row_rename_table_for_mysql( table = dict_table_open_on_name(old_name, dict_locked, FALSE, DICT_ERR_IGNORE_NONE); + /* We look for pattern #P# to see if the table is partitioned + MySQL table. */ +#ifdef __WIN__ + is_part = strstr((char *)old_name, (char *)"#p#"); +#else + is_part = strstr((char *)old_name, (char *)"#P#"); +#endif /* __WIN__ */ + + /* MySQL partition engine hard codes the file name + separator as "#P#". The text case is fixed even if + lower_case_table_names is set to 1 or 2. This is true + for sub-partition names as well. InnoDB always + normalises file names to lower case on Windows, this + can potentially cause problems when copying/moving + tables between platforms. + + 1) If boot against an installation from Windows + platform, then its partition table name could + be all be in lower case in system tables. So we + will need to check lower case name when load table. + + 2) If we boot an installation from other case + sensitive platform in Windows, we might need to + check the existence of table name without lowering + case them in the system table. */ + if (!table && + is_part && + innobase_get_lower_case_table_names() == 1) { + char par_case_name[MAX_FULL_NAME_LEN + 1]; +#ifndef __WIN__ + /* Check for the table using lower + case name, including the partition + separator "P" */ + memcpy(par_case_name, old_name, + strlen(old_name)); + par_case_name[strlen(old_name)] = 0; + innobase_casedn_str(par_case_name); +#else + /* On Windows platfrom, check + whether there exists table name in + system table whose name is + not being normalized to lower case */ + normalize_table_name_low( + par_case_name, old_name, FALSE); +#endif + table = dict_table_open_on_name(par_case_name, dict_locked, FALSE, + DICT_ERR_IGNORE_NONE); + } + if (!table) { err = DB_TABLE_NOT_FOUND; ut_print_timestamp(stderr); diff --git a/storage/xtradb/srv/srv0mon.cc b/storage/xtradb/srv/srv0mon.cc index 597e7cadc6a..e72868c6450 100644 --- a/storage/xtradb/srv/srv0mon.cc +++ b/storage/xtradb/srv/srv0mon.cc @@ -2,7 +2,7 @@ Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. +Copyright (c) 2013, 2016, 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 @@ -715,24 +715,6 @@ static monitor_info_t innodb_counter_info[] = MONITOR_EXISTING | MONITOR_DEFAULT_ON), MONITOR_DEFAULT_START, MONITOR_OVLD_OS_LOG_PENDING_WRITES}, - {"os_merge_blocks_written", "os", - "Number of merge blocks written (innodb_os_merge_blocks_written)", - static_cast<monitor_type_t>( - MONITOR_EXISTING | MONITOR_DEFAULT_ON), - MONITOR_DEFAULT_START, MONITOR_MERGE_BLOCKS_WRITTEN}, - - {"os_merge_blocks_read", "os", - "Number of merge blocks read (innodb_os_merge_blocks_read)", - static_cast<monitor_type_t>( - MONITOR_EXISTING | MONITOR_DEFAULT_ON), - MONITOR_DEFAULT_START, MONITOR_MERGE_BLOCKS_READ}, - - {"os_merge_blocks_merged", "os", - "Number of merge blocks merged (innodb_os_merge_blocks_merged)", - static_cast<monitor_type_t>( - MONITOR_EXISTING | MONITOR_DEFAULT_ON), - MONITOR_DEFAULT_START, MONITOR_MERGE_BLOCKS_MERGED}, - /* ========== Counters for Transaction Module ========== */ {"module_trx", "transaction", "Transaction Manager", MONITOR_MODULE, @@ -1790,21 +1772,6 @@ srv_mon_process_existing_counter( update_min = TRUE; break; - /* innodb_os_merge_blocks_written */ - case MONITOR_MERGE_BLOCKS_WRITTEN: - value = srv_stats.merge_buffers_written; - break; - - /* innodb_os_merge_blocks_read */ - case MONITOR_MERGE_BLOCKS_READ: - value = srv_stats.merge_buffers_read; - break; - - /* innodb_os_merge_blocks_merged */ - case MONITOR_MERGE_BLOCKS_MERGED: - value = srv_stats.merge_buffers_merged; - break; - /* innodb_log_waits */ case MONITOR_OVLD_LOG_WAITS: value = srv_stats.log_waits; diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 2164451225b..794b119a090 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -3,7 +3,7 @@ Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. +Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -2034,10 +2034,6 @@ srv_export_innodb_status(void) } #endif /* UNIV_DEBUG */ - export_vars.innodb_merge_buffers_written = srv_stats.merge_buffers_written; - export_vars.innodb_merge_buffers_read = srv_stats.merge_buffers_read; - export_vars.innodb_merge_buffers_merged = srv_stats.merge_buffers_merged; - export_vars.innodb_sec_rec_cluster_reads = srv_stats.n_sec_rec_cluster_reads; export_vars.innodb_sec_rec_cluster_reads_avoided = diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index e0f9bde63fa..17f9e53e76f 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -188,6 +188,9 @@ static const ulint SRV_UNDO_TABLESPACE_SIZE_IN_PAGES = #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 +/** The round off to MB is similar as done in srv_parse_megabytes() */ +#define CALC_NUMBER_OF_PAGES(size) ((size) / (1024 * 1024)) * \ + ((1024 * 1024) / (UNIV_PAGE_SIZE)) #ifdef UNIV_PFS_THREAD /* Keys to register InnoDB threads with performance schema */ UNIV_INTERN mysql_pfs_key_t io_handler_thread_key; @@ -1020,10 +1023,16 @@ open_or_create_data_files( size_check: size = os_file_get_size(files[i]); ut_a(size != (os_offset_t) -1); - /* Round size downward to megabytes */ - rounded_size_pages = (ulint) - (size >> UNIV_PAGE_SIZE_SHIFT); + /* Under some error conditions like disk full + narios or file size reaching filesystem + limit the data file could contain an incomplete + extent at the end. When we extend a data file + and if some failure happens, then also the data + file could contain an incomplete extent. So we + need to round the size downward to a megabyte.*/ + + rounded_size_pages = (ulint) CALC_NUMBER_OF_PAGES(size); if (i == srv_n_data_files - 1 && srv_auto_extend_last_data_file) { diff --git a/storage/xtradb/sync/sync0sync.cc b/storage/xtradb/sync/sync0sync.cc index 3facb99ac0a..702dd240f16 100644 --- a/storage/xtradb/sync/sync0sync.cc +++ b/storage/xtradb/sync/sync0sync.cc @@ -1657,34 +1657,49 @@ sync_print_wait_info( /*=================*/ FILE* file) /*!< in: file where to print */ { + // Sum counter values once + ib_int64_t mutex_spin_wait_count_val + = static_cast<ib_int64_t>(mutex_spin_wait_count); + ib_int64_t mutex_spin_round_count_val + = static_cast<ib_int64_t>(mutex_spin_round_count); + ib_int64_t mutex_os_wait_count_val + = static_cast<ib_int64_t>(mutex_os_wait_count); + ib_int64_t rw_s_spin_wait_count_val + = static_cast<ib_int64_t>(rw_lock_stats.rw_s_spin_wait_count); + ib_int64_t rw_s_spin_round_count_val + = static_cast<ib_int64_t>(rw_lock_stats.rw_s_spin_round_count); + ib_int64_t rw_s_os_wait_count_val + = static_cast<ib_int64_t>(rw_lock_stats.rw_s_os_wait_count); + ib_int64_t rw_x_spin_wait_count_val + = static_cast<ib_int64_t>(rw_lock_stats.rw_x_spin_wait_count); + ib_int64_t rw_x_spin_round_count_val + = static_cast<ib_int64_t>(rw_lock_stats.rw_x_spin_round_count); + ib_int64_t rw_x_os_wait_count_val + = static_cast<ib_int64_t>(rw_lock_stats.rw_x_os_wait_count); + fprintf(file, - "Mutex spin waits " UINT64PF ", rounds " UINT64PF ", " - "OS waits " UINT64PF "\n" - "RW-shared spins " UINT64PF ", rounds " UINT64PF ", " - "OS waits " UINT64PF "\n" - "RW-excl spins " UINT64PF ", rounds " UINT64PF ", " - "OS waits " UINT64PF "\n", - (ib_uint64_t) mutex_spin_wait_count, - (ib_uint64_t) mutex_spin_round_count, - (ib_uint64_t) mutex_os_wait_count, - (ib_uint64_t) rw_lock_stats.rw_s_spin_wait_count, - (ib_uint64_t) rw_lock_stats.rw_s_spin_round_count, - (ib_uint64_t) rw_lock_stats.rw_s_os_wait_count, - (ib_uint64_t) rw_lock_stats.rw_x_spin_wait_count, - (ib_uint64_t) rw_lock_stats.rw_x_spin_round_count, - (ib_uint64_t) rw_lock_stats.rw_x_os_wait_count); + "Mutex spin waits " INT64PF ", rounds " INT64PF ", " + "OS waits " INT64PF "\n" + "RW-shared spins " INT64PF ", rounds " INT64PF ", " + "OS waits " INT64PF "\n" + "RW-excl spins " INT64PF ", rounds " INT64PF ", " + "OS waits " INT64PF "\n", + mutex_spin_wait_count_val, mutex_spin_round_count_val, + mutex_os_wait_count_val, + rw_s_spin_wait_count_val, rw_s_spin_round_count_val, + rw_s_os_wait_count_val, + rw_x_spin_wait_count_val, rw_x_spin_round_count_val, + rw_x_os_wait_count_val); fprintf(file, "Spin rounds per wait: %.2f mutex, %.2f RW-shared, " "%.2f RW-excl\n", - (double) mutex_spin_round_count / - (mutex_spin_wait_count ? mutex_spin_wait_count : 1), - (double) rw_lock_stats.rw_s_spin_round_count / - (rw_lock_stats.rw_s_spin_wait_count - ? rw_lock_stats.rw_s_spin_wait_count : 1), - (double) rw_lock_stats.rw_x_spin_round_count / - (rw_lock_stats.rw_x_spin_wait_count - ? rw_lock_stats.rw_x_spin_wait_count : 1)); + (double) mutex_spin_round_count_val / + (mutex_spin_wait_count_val ? mutex_spin_wait_count_val : 1LL), + (double) rw_s_spin_round_count_val / + (rw_s_spin_wait_count_val ? rw_s_spin_wait_count_val : 1LL), + (double) rw_x_spin_round_count_val / + (rw_x_spin_wait_count_val ? rw_x_spin_wait_count_val : 1LL)); } /*******************************************************************//** |