summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2016-02-16 12:06:16 +0100
committerSergei Golubchik <serg@mariadb.org>2016-02-16 12:06:16 +0100
commitd76eba6a6b7de3077487ff3e4e7fa0ef2a7a9b00 (patch)
tree8227fe96f1d5257f3fe53c01e344df010fbf96af /storage
parent1e270d504d56cb015efe060b319e3a5b9bc6513f (diff)
downloadmariadb-git-d76eba6a6b7de3077487ff3e4e7fa0ef2a7a9b00.tar.gz
5.6.28-76.1
Diffstat (limited to 'storage')
-rw-r--r--storage/xtradb/btr/btr0btr.cc20
-rw-r--r--storage/xtradb/btr/btr0cur.cc4
-rw-r--r--storage/xtradb/buf/buf0flu.cc26
-rw-r--r--storage/xtradb/dict/dict0dict.cc42
-rw-r--r--storage/xtradb/fil/fil0fil.cc159
-rw-r--r--storage/xtradb/fsp/fsp0fsp.cc26
-rw-r--r--storage/xtradb/handler/ha_innodb.cc1
-rw-r--r--storage/xtradb/handler/handler0alter.cc127
-rw-r--r--storage/xtradb/include/buf0flu.h5
-rw-r--r--storage/xtradb/include/fil0fil.h41
-rw-r--r--storage/xtradb/include/univ.i2
-rw-r--r--storage/xtradb/log/log0recv.cc4
-rw-r--r--storage/xtradb/row/row0import.cc16
-rw-r--r--storage/xtradb/row/row0log.cc17
-rw-r--r--storage/xtradb/srv/srv0start.cc15
-rw-r--r--storage/xtradb/sync/sync0sync.cc61
16 files changed, 447 insertions, 119 deletions
diff --git a/storage/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc
index 7e357f0a1cf..ee36302b75b 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.
This program is free software; you can redistribute it and/or modify it under
@@ -2143,7 +2143,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(
@@ -2204,6 +2204,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);
@@ -2980,7 +2985,7 @@ function must always succeed, we cannot reverse it: therefore enough
free disk space (2 pages) 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_page_split_and_insert(
@@ -3094,9 +3099,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 4c6fdd67c95..6e6e2e08390 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -1733,6 +1733,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 d9893fc49b8..97c86ee7ed8 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -2209,9 +2209,10 @@ Clears up tail of the LRU lists:
* Put replaceable pages at the tail of LRU to the free list
* 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. */
+config parameter innodb_LRU_scan_depth.
+@return number of pages flushed */
UNIV_INTERN
-void
+ulint
buf_flush_LRU_tail(void)
/*====================*/
{
@@ -2313,6 +2314,7 @@ buf_flush_LRU_tail(void)
MONITOR_LRU_BATCH_PAGES,
total_flushed);
}
+ return(total_flushed);
}
/*********************************************************************//**
@@ -2608,19 +2610,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;
@@ -2826,6 +2833,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);
@@ -2852,11 +2860,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 6406a784348..8b65b769444 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -1590,10 +1590,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)));
@@ -1631,8 +1634,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);
@@ -1651,7 +1652,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)) {
@@ -1663,8 +1664,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"
@@ -1678,34 +1677,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 8c27affc4ac..981df578acb 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -3022,6 +3022,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.
@@ -6630,31 +6672,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 b96f2c1bb7a..59328dadc38 100644
--- a/storage/xtradb/fsp/fsp0fsp.cc
+++ b/storage/xtradb/fsp/fsp0fsp.cc
@@ -958,10 +958,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;
@@ -970,6 +980,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(
@@ -986,7 +1004,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 4daf40df10c..4ce9df722c1 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -16273,7 +16273,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 actual_priority
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 764c6904853..49ae7c19cc5 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -156,10 +156,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;
@@ -5035,6 +5038,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.
@@ -5170,6 +5228,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)
@@ -5370,6 +5442,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);
@@ -5451,7 +5524,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) {
@@ -5586,14 +5659,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++);
}
@@ -5606,18 +5685,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
@@ -5639,7 +5725,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 b73037dfab1..2cd8eefb79d 100644
--- a/storage/xtradb/include/buf0flu.h
+++ b/storage/xtradb/include/buf0flu.h
@@ -202,9 +202,10 @@ Clears up tail of the LRU lists:
* Put replaceable pages at the tail of LRU to the free list
* 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. */
+config parameter innodb_LRU_scan_depth.
+@return number of pages flushed */
UNIV_INTERN
-void
+ulint
buf_flush_LRU_tail(void);
/*====================*/
/*********************************************************************//**
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index c5ac9d7de83..1c78519cac5 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2014, 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
@@ -490,6 +490,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.
@@ -990,21 +1005,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/univ.i b/storage/xtradb/include/univ.i
index 11900631a45..28a100ee757 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -47,7 +47,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_BUGFIX MYSQL_VERSION_PATCH
#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 82b0af828b0..cc0bb515988 100644
--- a/storage/xtradb/log/log0recv.cc
+++ b/storage/xtradb/log/log0recv.cc
@@ -828,6 +828,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 acf6be7d8d8..89496b4176b 100644
--- a/storage/xtradb/row/row0import.cc
+++ b/storage/xtradb/row/row0import.cc
@@ -2068,8 +2068,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 f88baa42d58..3989b669c28 100644
--- a/storage/xtradb/row/row0log.cc
+++ b/storage/xtradb/row/row0log.cc
@@ -1454,6 +1454,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);
@@ -1489,6 +1490,8 @@ row_log_table_apply_insert_low(
}
do {
+ n_index++;
+
if (!(index = dict_table_get_next_index(index))) {
break;
}
@@ -1501,6 +1504,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);
@@ -1808,6 +1817,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));
@@ -2083,6 +2093,8 @@ func_exit_committed:
break;
}
+ n_index++;
+
if (index->type & DICT_FTS) {
continue;
}
@@ -2126,6 +2138,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/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index bbd095dacf7..0d3f4691a50 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -159,6 +159,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;
@@ -988,10 +991,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 d6a7f569b4a..7fc992bf972 100644
--- a/storage/xtradb/sync/sync0sync.cc
+++ b/storage/xtradb/sync/sync0sync.cc
@@ -1690,34 +1690,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));
}
/*******************************************************************//**