summaryrefslogtreecommitdiff
path: root/storage/innobase/row
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row')
-rw-r--r--storage/innobase/row/row0import.cc11
-rw-r--r--storage/innobase/row/row0ins.cc12
-rw-r--r--storage/innobase/row/row0merge.cc13
-rw-r--r--storage/innobase/row/row0mysql.cc139
-rw-r--r--storage/innobase/row/row0purge.cc1
-rw-r--r--storage/innobase/row/row0sel.cc22
-rw-r--r--storage/innobase/row/row0trunc.cc9
-rw-r--r--storage/innobase/row/row0umod.cc13
8 files changed, 120 insertions, 100 deletions
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 01a55d0dc61..a2773baa34e 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -1959,16 +1959,13 @@ PageConverter::validate(
buf_block_t* block) UNIV_NOTHROW
{
buf_frame_t* page = get_frame(block);
- ulint space_id = mach_read_from_4(
- page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
- fil_space_t* space = fil_space_found_by_id(space_id);
/* Check that the page number corresponds to the offset in
the file. Flag as corrupt if it doesn't. Disable the check
for LSN in buf_page_is_corrupted() */
if (buf_page_is_corrupted(
- false, page, get_page_size(), space)
+ false, page, get_page_size(), NULL)
|| (page_get_page_no(page) != offset / m_page_size.physical()
&& page_get_page_no(page) != 0)) {
@@ -2101,7 +2098,7 @@ row_import_discard_changes(
index->space = FIL_NULL;
}
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
fil_close_tablespace(trx, table->space);
}
@@ -3357,7 +3354,7 @@ row_import_for_mysql(
ut_a(table->space);
ut_ad(prebuilt->trx);
- ut_a(table->ibd_file_missing);
+ ut_a(!table->is_readable());
ibuf_delete_for_discarded_space(table->space);
@@ -3691,7 +3688,7 @@ row_import_for_mysql(
return(row_import_error(prebuilt, trx, err));
}
- table->ibd_file_missing = false;
+ table->file_unreadable = false;
table->flags2 &= ~DICT_TF2_DISCARDED;
/* Set autoinc value read from .cfg file, if one was specified.
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index a44246dfd34..b7133a3e1ee 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -1656,7 +1656,7 @@ row_ins_check_foreign_constraint(
}
if (check_table == NULL
- || check_table->ibd_file_missing
+ || !check_table->is_readable()
|| check_index == NULL) {
if (!srv_read_only_mode && check_ref) {
@@ -2613,8 +2613,14 @@ row_ins_clust_index_entry_low(
/* Note that we use PAGE_CUR_LE as the search mode, because then
the function will return in both low_match and up_match of the
cursor sensible values */
- btr_pcur_open_low(index, 0, entry, PAGE_CUR_LE, mode, &pcur,
+ err = btr_pcur_open_low(index, 0, entry, PAGE_CUR_LE, mode, &pcur,
__FILE__, __LINE__, auto_inc, &mtr);
+ if (err != DB_SUCCESS) {
+ index->table->file_unreadable = true;
+ mtr.commit();
+ goto func_exit;
+ }
+
cursor = btr_pcur_get_btr_cur(&pcur);
cursor->thr = thr;
@@ -2950,7 +2956,7 @@ row_ins_sec_index_entry_low(
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
- index->table->is_encrypted = true;
+ index->table->file_unreadable = true;
}
goto func_exit;
}
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index aeff27c31eb..62cab870e9e 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -1996,7 +1996,8 @@ row_merge_read_clustered_index(
page_cur_t* cur = btr_pcur_get_page_cur(&pcur);
/* Do not continue if table pages are still encrypted */
- if (old_table->is_encrypted || new_table->is_encrypted) {
+ if (!old_table->is_readable() ||
+ !new_table->is_readable()) {
err = DB_DECRYPTION_FAILED;
trx->error_key_num = 0;
goto func_exit;
@@ -4300,7 +4301,7 @@ row_merge_rename_tables_dict(
renamed along with the table. */
if (err == DB_SUCCESS
&& dict_table_is_file_per_table(old_table)
- && !old_table->ibd_file_missing) {
+ && fil_space_get(old_table->space) != NULL) {
/* Make pathname to update SYS_DATAFILES. */
char* tmp_path = row_make_new_pathname(old_table, tmp_name);
@@ -4640,7 +4641,7 @@ row_merge_build_indexes(
double total_static_cost = 0;
double total_dynamic_cost = 0;
- uint total_index_blocks = 0;
+ ulint total_index_blocks = 0;
double pct_cost=0;
double pct_progress=0;
@@ -4779,13 +4780,15 @@ row_merge_build_indexes(
pct_cost = COST_READ_CLUSTERED_INDEX * 100 / (total_static_cost + total_dynamic_cost);
/* Do not continue if we can't encrypt table pages */
- if (old_table->is_encrypted || new_table->is_encrypted) {
+ if (!old_table->is_readable() ||
+ !new_table->is_readable()) {
error = DB_DECRYPTION_FAILED;
ib_push_warning(trx->mysql_thd, DB_DECRYPTION_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
- old_table->is_encrypted ? old_table->name : new_table->name);
+ !old_table->is_readable() ? old_table->name :
+ new_table->name);
goto func_exit;
}
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 7e3a7d580c5..57ba35a57f6 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2015, 2017, 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
@@ -819,6 +819,7 @@ handle_new_error:
break;
case DB_CORRUPTION:
+ case DB_PAGE_CORRUPTED:
ib::error() << "We detected index corruption in an InnoDB type"
" table. You have to dump + drop + reimport the"
" table or, in a case of widespread corruption,"
@@ -1399,6 +1400,55 @@ run_again:
return(err);
}
+/** Determine is tablespace encrypted but decryption failed, is table corrupted
+or is tablespace .ibd file missing.
+@param[in] table Table
+@param[in] trx Transaction
+@param[in] push_warning true if we should push warning to user
+@retval DB_DECRYPTION_FAILED table is encrypted but decryption failed
+@retval DB_CORRUPTION table is corrupted
+@retval DB_TABLESPACE_NOT_FOUND tablespace .ibd file not found */
+static
+dberr_t
+row_mysql_get_table_status(
+ const dict_table_t* table,
+ trx_t* trx,
+ bool push_warning = true)
+{
+ dberr_t err;
+ if (fil_space_t* space = fil_space_acquire_silent(table->space)) {
+ if (space->crypt_data && space->crypt_data->is_encrypted()) {
+ // maybe we cannot access the table due to failing
+ // to decrypt
+ if (push_warning) {
+ ib_push_warning(trx, DB_DECRYPTION_FAILED,
+ "Table %s in tablespace %lu encrypted."
+ "However key management plugin or used key_id is not found or"
+ " used encryption algorithm or method does not match.",
+ table->name, table->space);
+ }
+
+ err = DB_DECRYPTION_FAILED;
+ } else {
+ if (push_warning) {
+ ib_push_warning(trx, DB_CORRUPTION,
+ "Table %s in tablespace %lu corrupted.",
+ table->name, table->space);
+ }
+
+ err = DB_CORRUPTION;
+ }
+
+ fil_space_release(space);
+ } else {
+ ib::error() << ".ibd file is missing for table "
+ << table->name;
+ err = DB_TABLESPACE_NOT_FOUND;
+ }
+
+ return(err);
+}
+
/** Does an insert for MySQL.
@param[in] mysql_rec row in the MySQL format
@param[in,out] prebuilt prebuilt struct in MySQL handle
@@ -1432,19 +1482,8 @@ row_insert_for_mysql(
return(DB_TABLESPACE_DELETED);
- } else if (prebuilt->table->ibd_file_missing) {
-
- ib::error() << ".ibd file is missing for table "
- << prebuilt->table->name;
-
- return(DB_TABLESPACE_NOT_FOUND);
- } else if (prebuilt->table->is_encrypted) {
- ib_push_warning(trx, DB_DECRYPTION_FAILED,
- "Table %s in tablespace " ULINTPF " encrypted."
- "However key management plugin or used key_id is not found or"
- " used encryption algorithm or method does not match.",
- prebuilt->table->name, prebuilt->table->space);
- return(DB_DECRYPTION_FAILED);
+ } else if (!prebuilt->table->is_readable()) {
+ return(row_mysql_get_table_status(prebuilt->table, trx, true));
} else if (srv_force_recovery) {
ib::error() << MODIFICATIONS_NOT_ALLOWED_MSG_FORCE_RECOVERY;
@@ -1594,9 +1633,9 @@ error_exit:
que_thr_stop_for_mysql_no_error(thr, trx);
if (table->is_system_db) {
- srv_stats.n_system_rows_inserted.inc();
+ srv_stats.n_system_rows_inserted.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_inserted.inc();
+ srv_stats.n_rows_inserted.inc(size_t(trx->id));
}
/* Not protected by dict_table_stats_lock() for performance
@@ -1858,21 +1897,8 @@ row_update_for_mysql_using_upd_graph(
ut_a(prebuilt->magic_n2 == ROW_PREBUILT_ALLOCATED);
UT_NOT_USED(mysql_rec);
- if (prebuilt->table->ibd_file_missing) {
- ib::error() << "MySQL is trying to use a table handle but the"
- " .ibd file for table " << prebuilt->table->name
- << " does not exist. Have you deleted"
- " the .ibd file from the database directory under"
- " the MySQL datadir, or have you used DISCARD"
- " TABLESPACE? " << TROUBLESHOOTING_MSG;
- DBUG_RETURN(DB_ERROR);
- } else if (prebuilt->table->is_encrypted) {
- ib_push_warning(trx, DB_DECRYPTION_FAILED,
- "Table %s in tablespace " ULINTPF " encrypted."
- "However key management plugin or used key_id is not found or"
- " used encryption algorithm or method does not match.",
- prebuilt->table->name, prebuilt->table->space);
- return (DB_TABLE_NOT_FOUND);
+ if (!table->is_readable()) {
+ return(row_mysql_get_table_status(table, trx, true));
}
if(srv_force_recovery) {
@@ -2090,9 +2116,9 @@ run_again:
than protecting the following code with a latch. */
dict_table_n_rows_dec(node->table);
- srv_stats.n_rows_deleted.add((size_t)trx->id, 1);
+ srv_stats.n_rows_deleted.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_updated.add((size_t)trx->id, 1);
+ srv_stats.n_rows_updated.inc(size_t(trx->id));
}
row_update_statistics_if_needed(node->table);
@@ -2106,17 +2132,16 @@ run_again:
with a latch. */
dict_table_n_rows_dec(prebuilt->table);
- if (table->is_system_db) {
- srv_stats.n_system_rows_deleted.inc();
+ if (table->is_system_db) {
+ srv_stats.n_system_rows_deleted.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_deleted.inc();
+ srv_stats.n_rows_deleted.inc(size_t(trx->id));
}
-
} else {
if (table->is_system_db) {
- srv_stats.n_system_rows_updated.inc();
+ srv_stats.n_system_rows_updated.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_updated.inc();
+ srv_stats.n_rows_updated.inc(size_t(trx->id));
}
}
@@ -2424,7 +2449,7 @@ row_create_table_for_mysql(
trx_t* trx, /*!< in/out: transaction */
bool commit, /*!< in: if true, commit the transaction */
fil_encryption_t mode, /*!< in: encryption mode */
- ulint key_id) /*!< in: encryption key_id */
+ uint32_t key_id) /*!< in: encryption key_id */
{
tab_node_t* node;
mem_heap_t* heap;
@@ -3261,7 +3286,7 @@ row_discard_tablespace(
/* All persistent operations successful, update the
data dictionary memory cache. */
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
table->flags2 |= DICT_TF2_DISCARDED;
@@ -3300,7 +3325,7 @@ row_discard_tablespace(
/*********************************************************************//**
Discards the tablespace of a table which stored in an .ibd file. Discarding
means that this function renames the .ibd file and assigns a new table id for
-the table. Also the flag table->ibd_file_missing is set to TRUE.
+the table. Also the file_unreadable flag is set.
@return error code or DB_SUCCESS */
dberr_t
row_discard_tablespace_for_mysql(
@@ -3317,8 +3342,6 @@ row_discard_tablespace_for_mysql(
if (table == 0) {
err = DB_TABLE_NOT_FOUND;
- } else if (table->is_encrypted) {
- err = DB_DECRYPTION_FAILED;
} else if (dict_table_is_temporary(table)) {
ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
@@ -3326,7 +3349,7 @@ row_discard_tablespace_for_mysql(
err = DB_ERROR;
- } else if (table->space == srv_sys_space.space_id()) {
+ } else if (table->space == TRX_SYS_SPACE) {
char table_name[MAX_FULL_NAME_LEN + 1];
innobase_format_name(
@@ -3657,18 +3680,6 @@ row_drop_table_for_mysql(
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
}
- /* If table is encrypted and table page encryption failed
- return error. */
- if (table->is_encrypted) {
-
- if (table->can_be_evicted) {
- dict_table_move_from_lru_to_non_lru(table);
- }
-
- dict_table_close(table, TRUE, FALSE);
- err = DB_DECRYPTION_FAILED;
- goto funct_exit;
- }
/* This function is called recursively via fts_drop_tables(). */
if (!trx_is_started(trx)) {
@@ -4067,13 +4078,11 @@ row_drop_table_for_mysql(
switch (err) {
ulint space_id;
- bool ibd_file_missing;
bool is_discarded;
ulint table_flags;
case DB_SUCCESS:
space_id = table->space;
- ibd_file_missing = table->ibd_file_missing;
is_discarded = dict_table_is_discarded(table);
table_flags = table->flags;
ut_ad(!dict_table_is_temporary(table));
@@ -4104,8 +4113,7 @@ row_drop_table_for_mysql(
/* Do not attempt to drop known-to-be-missing tablespaces,
nor the system tablespace. */
- if (is_discarded || ibd_file_missing
- || is_system_tablespace(space_id)) {
+ if (is_discarded || is_system_tablespace(space_id)) {
break;
}
@@ -4338,7 +4346,8 @@ loop:
<< table->name << ".frm' was lost.";
}
- if (table->ibd_file_missing) {
+ if (!table->is_readable()
+ && !fil_space_get(table->space)) {
ib::warn() << "Missing .ibd file for table "
<< table->name << ".";
}
@@ -4594,7 +4603,8 @@ row_rename_table_for_mysql(
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
- } else if (table->ibd_file_missing
+ } else if (!table->is_readable()
+ && fil_space_get(table->space) == NULL
&& !dict_table_is_discarded(table)) {
err = DB_TABLE_NOT_FOUND;
@@ -4660,8 +4670,7 @@ row_rename_table_for_mysql(
/* SYS_TABLESPACES and SYS_DATAFILES need to be updated if
the table is in a single-table tablespace. */
if (err == DB_SUCCESS
- && dict_table_is_file_per_table(table)
- && !table->ibd_file_missing) {
+ && dict_table_is_file_per_table(table)) {
/* Make a new pathname to update SYS_DATAFILES. */
char* new_path = row_make_new_pathname(table, new_name);
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 492d864ec96..e49fd7f0f8c 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 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
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 4884fe99fef..2bee83808a5 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -3363,11 +3363,12 @@ row_sel_get_clust_rec_for_mysql(
dberr_t err;
trx_t* trx;
- srv_stats.n_sec_rec_cluster_reads.inc();
-
*out_rec = NULL;
trx = thr_get_trx(thr);
+ srv_stats.n_sec_rec_cluster_reads.inc(
+ thd_get_thread_id(trx->mysql_thd));
+
row_build_row_ref_in_tuple(prebuilt->clust_ref, rec,
sec_index, *offsets, trx);
@@ -4192,13 +4193,10 @@ row_search_mvcc(
DBUG_RETURN(DB_TABLESPACE_DELETED);
- } else if (prebuilt->table->ibd_file_missing) {
-
- DBUG_RETURN(DB_TABLESPACE_NOT_FOUND);
-
- } else if (prebuilt->table->is_encrypted) {
-
- return(DB_DECRYPTION_FAILED);
+ } else if (!prebuilt->table->is_readable()) {
+ DBUG_RETURN(fil_space_get(prebuilt->table->space)
+ ? DB_DECRYPTION_FAILED
+ : DB_TABLESPACE_NOT_FOUND);
} else if (!prebuilt->index_usable) {
DBUG_RETURN(DB_MISSING_HISTORY);
@@ -4682,7 +4680,7 @@ wait_table_again:
" used key_id is not available. "
" Can't continue reading table.",
prebuilt->table->name);
- index->table->is_encrypted = true;
+ index->table->file_unreadable = true;
}
rec = NULL;
goto lock_wait_or_error;
@@ -4704,7 +4702,7 @@ rec_loop:
rec = btr_pcur_get_rec(pcur);
- if (!rec) {
+ if (!index->table->is_readable()) {
err = DB_DECRYPTION_FAILED;
goto lock_wait_or_error;
}
@@ -4830,7 +4828,7 @@ wrong_offs:
if (!rec_validate(rec, offsets)
|| !btr_index_rec_validate(rec, index, FALSE)) {
- ib::info() << "Index corruption: rec offs "
+ ib::error() << "Index corruption: rec offs "
<< page_offset(rec) << " next offs "
<< next_offs << ", page no "
<< page_get_page_no(page_align(rec))
diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc
index 1fc30e714f4..5724fad801f 100644
--- a/storage/innobase/row/row0trunc.cc
+++ b/storage/innobase/row/row0trunc.cc
@@ -1681,10 +1681,13 @@ row_truncate_sanity_checks(
return(DB_TABLESPACE_DELETED);
- } else if (table->ibd_file_missing) {
-
- return(DB_TABLESPACE_NOT_FOUND);
+ } else if (!table->is_readable()) {
+ if (fil_space_get(table->space) == NULL) {
+ return(DB_TABLESPACE_NOT_FOUND);
+ } else {
+ return(DB_DECRYPTION_FAILED);
+ }
} else if (dict_table_is_corrupted(table)) {
return(DB_TABLE_CORRUPT);
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index ba072a72aa1..eefe9fb2bd8 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -1169,16 +1169,19 @@ close_table:
node->new_trx_id = trx_id;
node->cmpl_info = cmpl_info;
- if (UNIV_UNLIKELY(!row_undo_search_clust_to_pcur(node))) {
- /* This should never occur. As long as this
- rolling-back transaction exists, the PRIMARY KEY value
- pointed to by the undo log record must exist.
+ if (!row_undo_search_clust_to_pcur(node)) {
+ /* As long as this rolling-back transaction exists,
+ the PRIMARY KEY value pointed to by the undo log
+ record must exist. But, it is possible that the record
+ was not modified yet (the DB_ROLL_PTR does not match
+ node->roll_ptr) and thus there is nothing to roll back.
+
btr_cur_upd_lock_and_undo() only writes the undo log
record after successfully acquiring an exclusive lock
on the the clustered index record. That lock will not
be released before the transaction is committed or
fully rolled back. */
- ut_ad(0);
+ ut_ad(node->pcur.btr_cur.low_match == node->ref->n_fields);
goto close_table;
}