summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2017-05-26 19:32:28 +0400
committerAlexander Barkov <bar@mariadb.org>2017-05-26 19:32:28 +0400
commit9bc32256427373e5bfa78f17c5854ac4e6a2fc31 (patch)
tree748fd55866bcbc4de5eee1c078ac8d2cad5b6fd7 /storage
parent77b2f55f61a4e3ba642049a01651c92bfb0a7d9d (diff)
parentca7cf69cb13285585922722063af888b957580ee (diff)
downloadmariadb-git-9bc32256427373e5bfa78f17c5854ac4e6a2fc31.tar.gz
Merge tag 'mariadb-10.2.6' into bb-10.2-ext
Diffstat (limited to 'storage')
-rw-r--r--storage/connect/mysql-test/connect/t/secure_file_priv.test2
-rw-r--r--storage/innobase/CMakeLists.txt1
-rw-r--r--storage/innobase/btr/btr0btr.cc24
-rw-r--r--storage/innobase/btr/btr0cur.cc39
-rw-r--r--storage/innobase/btr/btr0defragment.cc2
-rw-r--r--storage/innobase/btr/btr0pcur.cc9
-rw-r--r--storage/innobase/btr/btr0scrub.cc3
-rw-r--r--storage/innobase/buf/buf0buf.cc446
-rw-r--r--storage/innobase/buf/buf0checksum.cc46
-rw-r--r--storage/innobase/buf/buf0flu.cc9
-rw-r--r--storage/innobase/buf/buf0lru.cc2
-rw-r--r--storage/innobase/buf/buf0rea.cc155
-rw-r--r--storage/innobase/dict/dict0crea.cc10
-rw-r--r--storage/innobase/dict/dict0defrag_bg.cc19
-rw-r--r--storage/innobase/dict/dict0dict.cc57
-rw-r--r--storage/innobase/dict/dict0load.cc27
-rw-r--r--storage/innobase/dict/dict0mem.cc2
-rw-r--r--storage/innobase/dict/dict0stats.cc71
-rw-r--r--storage/innobase/fil/fil0crypt.cc191
-rw-r--r--storage/innobase/fil/fil0fil.cc109
-rw-r--r--storage/innobase/handler/ha_innodb.cc162
-rw-r--r--storage/innobase/handler/ha_xtradb.h1007
-rw-r--r--storage/innobase/handler/handler0alter.cc186
-rw-r--r--storage/innobase/handler/i_s.cc34
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc3
-rw-r--r--storage/innobase/include/btr0btr.ic2
-rw-r--r--storage/innobase/include/btr0pcur.h2
-rw-r--r--storage/innobase/include/btr0pcur.ic4
-rw-r--r--storage/innobase/include/buf0buf.h45
-rw-r--r--storage/innobase/include/buf0checksum.h38
-rw-r--r--storage/innobase/include/buf0rea.h18
-rw-r--r--storage/innobase/include/db0err.h4
-rw-r--r--storage/innobase/include/dict0crea.h4
-rw-r--r--storage/innobase/include/dict0dict.h8
-rw-r--r--storage/innobase/include/dict0dict.ic2
-rw-r--r--storage/innobase/include/dict0load.h2
-rw-r--r--storage/innobase/include/dict0mem.h30
-rw-r--r--storage/innobase/include/dict0stats.h11
-rw-r--r--storage/innobase/include/fil0crypt.h17
-rw-r--r--storage/innobase/include/fil0fil.h38
-rw-r--r--storage/innobase/include/fil0fil.ic13
-rw-r--r--storage/innobase/include/fil0pagecompress.h19
-rw-r--r--storage/innobase/include/fsp0space.h4
-rw-r--r--storage/innobase/include/mtr0log.ic16
-rw-r--r--storage/innobase/include/row0mysql.h4
-rw-r--r--storage/innobase/include/row0trunc.h2
-rw-r--r--storage/innobase/include/srv0srv.h21
-rw-r--r--storage/innobase/include/sync0types.h46
-rw-r--r--storage/innobase/include/trx0trx.h17
-rw-r--r--storage/innobase/include/ut0counter.h95
-rw-r--r--storage/innobase/include/ut0ut.h2
-rw-r--r--storage/innobase/lock/lock0lock.cc2
-rw-r--r--storage/innobase/lock/lock0wait.cc27
-rw-r--r--storage/innobase/log/log0crypt.cc2
-rw-r--r--storage/innobase/log/log0recv.cc16
-rw-r--r--storage/innobase/os/os0file.cc4
-rw-r--r--storage/innobase/os/os0proc.cc2
-rw-r--r--storage/innobase/page/page0cur.cc12
-rw-r--r--storage/innobase/page/page0zip.cc1
-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
-rw-r--r--storage/innobase/srv/srv0start.cc25
-rw-r--r--storage/innobase/sync/sync0rw.cc3
-rw-r--r--storage/innobase/trx/trx0sys.cc3
-rw-r--r--storage/innobase/trx/trx0trx.cc2
-rw-r--r--storage/innobase/ut/ut0ut.cc11
-rw-r--r--storage/maria/ma_pagecache.c59
-rw-r--r--storage/myisam/mi_delete_table.c2
-rw-r--r--storage/rocksdb/build_rocksdb.cmake102
-rw-r--r--storage/rocksdb/ha_rocksdb.cc14
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/r/use_direct_reads_writes.result2
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/t/disabled.def8
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/t/use_direct_reads_writes.test4
-rw-r--r--storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_io_for_flush_and_compaction_basic.result7
-rw-r--r--storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_writes_basic.result7
-rw-r--r--storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_use_direct_io_for_flush_and_compaction_basic.test (renamed from storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_use_direct_writes_basic.test)2
m---------storage/rocksdb/rocksdb0
-rw-r--r--storage/xtradb/CMakeLists.txt3
-rw-r--r--storage/xtradb/api/api0api.cc6
-rw-r--r--storage/xtradb/btr/btr0btr.cc10
-rw-r--r--storage/xtradb/btr/btr0cur.cc33
-rw-r--r--storage/xtradb/btr/btr0defragment.cc2
-rw-r--r--storage/xtradb/btr/btr0pcur.cc10
-rw-r--r--storage/xtradb/btr/btr0scrub.cc3
-rw-r--r--storage/xtradb/buf/buf0buf.cc528
-rw-r--r--storage/xtradb/buf/buf0dblwr.cc9
-rw-r--r--storage/xtradb/buf/buf0flu.cc19
-rw-r--r--storage/xtradb/buf/buf0lru.cc5
-rw-r--r--storage/xtradb/buf/buf0rea.cc289
-rw-r--r--storage/xtradb/dict/dict0crea.cc2
-rw-r--r--storage/xtradb/dict/dict0dict.cc103
-rw-r--r--storage/xtradb/dict/dict0load.cc50
-rw-r--r--storage/xtradb/dict/dict0mem.cc3
-rw-r--r--storage/xtradb/dict/dict0stats.cc100
-rw-r--r--storage/xtradb/fil/fil0crypt.cc128
-rw-r--r--storage/xtradb/fil/fil0fil.cc744
-rw-r--r--storage/xtradb/handler/ha_innodb.cc341
-rw-r--r--storage/xtradb/handler/handler0alter.cc62
-rw-r--r--storage/xtradb/include/btr0btr.ic2
-rw-r--r--storage/xtradb/include/buf0buf.h51
-rw-r--r--storage/xtradb/include/buf0rea.h38
-rw-r--r--storage/xtradb/include/db0err.h2
-rw-r--r--storage/xtradb/include/dict0dict.h27
-rw-r--r--storage/xtradb/include/dict0dict.ic17
-rw-r--r--storage/xtradb/include/dict0mem.h40
-rw-r--r--storage/xtradb/include/fil0crypt.h13
-rw-r--r--storage/xtradb/include/fil0fil.h171
-rw-r--r--storage/xtradb/include/os0sync.h57
-rw-r--r--storage/xtradb/include/srv0srv.h28
-rw-r--r--storage/xtradb/include/trx0sys.h5
-rw-r--r--storage/xtradb/include/univ.i2
-rw-r--r--storage/xtradb/include/ut0counter.h90
-rw-r--r--storage/xtradb/lock/lock0wait.cc23
-rw-r--r--storage/xtradb/log/log0crypt.cc5
-rw-r--r--storage/xtradb/log/log0log.cc2
-rw-r--r--storage/xtradb/log/log0recv.cc116
-rw-r--r--storage/xtradb/os/os0file.cc14
-rw-r--r--storage/xtradb/row/row0import.cc11
-rw-r--r--storage/xtradb/row/row0ins.cc7
-rw-r--r--storage/xtradb/row/row0log.cc2
-rw-r--r--storage/xtradb/row/row0merge.cc12
-rw-r--r--storage/xtradb/row/row0mysql.cc174
-rw-r--r--storage/xtradb/row/row0purge.cc2
-rw-r--r--storage/xtradb/row/row0sel.cc49
-rw-r--r--storage/xtradb/row/row0uins.cc2
-rw-r--r--storage/xtradb/row/row0umod.cc2
-rw-r--r--storage/xtradb/srv/srv0srv.cc12
-rw-r--r--storage/xtradb/srv/srv0start.cc45
-rw-r--r--storage/xtradb/trx/trx0sys.cc27
-rw-r--r--storage/xtradb/trx/trx0trx.cc26
-rw-r--r--storage/xtradb/ut/ut0ut.cc2
137 files changed, 4474 insertions, 2669 deletions
diff --git a/storage/connect/mysql-test/connect/t/secure_file_priv.test b/storage/connect/mysql-test/connect/t/secure_file_priv.test
index 46633502034..f7792536892 100644
--- a/storage/connect/mysql-test/connect/t/secure_file_priv.test
+++ b/storage/connect/mysql-test/connect/t/secure_file_priv.test
@@ -10,4 +10,4 @@ let $SECUREDIR= `select @@secure_file_priv`;
INSERT INTO t1 VALUES (10);
SELECT * FROM t1;
DROP TABLE t1;
---remove_file $SECUREDIR/t1.dbf
+--remove_file $MYSQL_TMP_DIR/t1.dbf
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index 1ecf80bb92d..22aaa8a6f5d 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -164,6 +164,7 @@ MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE
${ZLIB_LIBRARY}
${CRC32_VPMSUM_LIBRARY}
${NUMA_LIBRARY}
+ ${LIBSYSTEMD}
${LINKER_SCRIPT})
IF(WITH_INNOBASE_STORAGE_ENGINE)
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 489b612a17a..3d778c49012 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -169,8 +169,7 @@ btr_root_block_get(
if (!block) {
if (index && index->table) {
- index->table->is_encrypted = TRUE;
- index->table->corrupted = FALSE;
+ index->table->file_unreadable = true;
ib_push_warning(index->table->thd, DB_DECRYPTION_FAILED,
"Table %s in tablespace %lu is encrypted but encryption service or"
@@ -183,6 +182,7 @@ btr_root_block_get(
}
btr_assert_not_corrupted(block, index);
+
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
@@ -713,7 +713,7 @@ btr_page_free_low(
* pages should be possible
*/
uint cnt = 0;
- uint bytes = 0;
+ ulint bytes = 0;
page_t* page = buf_block_get_frame(block);
mem_heap_t* heap = NULL;
ulint* offsets = NULL;
@@ -731,7 +731,7 @@ btr_page_free_low(
#ifdef UNIV_DEBUG_SCRUBBING
fprintf(stderr,
"btr_page_free_low: scrub %lu/%lu - "
- "%u records %u bytes\n",
+ "%u records " ULINTPF " bytes\n",
buf_block_get_space(block),
buf_block_get_page_no(block),
cnt, bytes);
@@ -1991,10 +1991,9 @@ btr_root_raise_and_insert(
longer is a leaf page. (Older versions of InnoDB did
set PAGE_MAX_TRX_ID on all secondary index pages.) */
if (root_page_zip) {
- page_zip_write_header(
- root_page_zip,
- PAGE_HEADER + PAGE_MAX_TRX_ID
- + root, 0, mtr);
+ byte* p = PAGE_HEADER + PAGE_MAX_TRX_ID + root;
+ memset(p, 0, 8);
+ page_zip_write_header(root_page_zip, p, 8, mtr);
} else {
mlog_write_ull(PAGE_HEADER + PAGE_MAX_TRX_ID
+ root, 0, mtr);
@@ -2004,10 +2003,9 @@ btr_root_raise_and_insert(
root page; on other clustered index pages, we want to reserve
the field PAGE_MAX_TRX_ID for future use. */
if (new_page_zip) {
- page_zip_write_header(
- new_page_zip,
- PAGE_HEADER + PAGE_MAX_TRX_ID
- + new_page, 0, mtr);
+ byte* p = PAGE_HEADER + PAGE_MAX_TRX_ID + new_page;
+ memset(p, 0, 8);
+ page_zip_write_header(new_page_zip, p, 8, mtr);
} else {
mlog_write_ull(PAGE_HEADER + PAGE_MAX_TRX_ID
+ new_page, 0, mtr);
@@ -5418,7 +5416,7 @@ btr_validate_index(
page_t* root = btr_root_get(index, &mtr);
- if (root == NULL && index->table->is_encrypted) {
+ if (root == NULL && !index->is_readable()) {
err = DB_DECRYPTION_FAILED;
mtr_commit(&mtr);
return err;
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 773b03775be..aa24cb5d423 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -1109,7 +1109,11 @@ retry_page_get:
buf_mode, file, line, mtr, &err);
tree_blocks[n_blocks] = block;
+ /* Note that block==NULL signifies either an error or change
+ buffering. */
+
if (err != DB_SUCCESS) {
+ ut_ad(block == NULL);
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
@@ -1117,7 +1121,7 @@ retry_page_get:
" 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;
@@ -1230,7 +1234,7 @@ retry_page_get:
" 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;
@@ -1259,7 +1263,7 @@ retry_page_get:
" 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;
@@ -2057,7 +2061,7 @@ btr_cur_open_at_index_side_func(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
dberr_t err = DB_SUCCESS;
-
+
rec_offs_init(offsets_);
estimate = latch_mode & BTR_ESTIMATE;
@@ -2139,8 +2143,7 @@ btr_cur_open_at_index_side_func(
height = ULINT_UNDEFINED;
for (;;) {
- buf_block_t* block=NULL;
- page_t* page=NULL;
+ buf_block_t* block;
ulint rw_latch;
ut_ad(n_blocks < BTR_MAX_LEVELS);
@@ -2156,6 +2159,7 @@ btr_cur_open_at_index_side_func(
tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
BUF_GET, file, line, mtr, &err);
+ ut_ad((block != NULL) == (err == DB_SUCCESS));
tree_blocks[n_blocks] = block;
if (err != DB_SUCCESS) {
@@ -2166,13 +2170,13 @@ btr_cur_open_at_index_side_func(
" 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 exit_loop;
}
- page = buf_block_get_frame(block);
+ const page_t* page = buf_block_get_frame(block);
if (height == ULINT_UNDEFINED
&& page_is_leaf(page)
@@ -2516,6 +2520,8 @@ btr_cur_open_at_rnd_pos_func(
BUF_GET, file, line, mtr, &err);
tree_blocks[n_blocks] = block;
+ ut_ad((block != NULL) == (err == DB_SUCCESS));
+
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
@@ -2524,8 +2530,9 @@ btr_cur_open_at_rnd_pos_func(
" 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 exit_loop;
}
@@ -5323,6 +5330,8 @@ btr_estimate_n_rows_in_range_on_level(
NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err);
+ ut_ad((block != NULL) == (err == DB_SUCCESS));
+
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
@@ -5331,7 +5340,7 @@ btr_estimate_n_rows_in_range_on_level(
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
- index->table->is_encrypted = true;
+ index->table->file_unreadable = true;
}
mtr_commit(&mtr);
@@ -5518,6 +5527,10 @@ btr_estimate_n_rows_in_range_low(
mtr_commit(&mtr);
+ if (!index->is_readable()) {
+ return 0;
+ }
+
mtr_start(&mtr);
cursor.path_arr = path2;
@@ -5997,6 +6010,11 @@ btr_estimate_number_of_different_key_vals(
because otherwise our algorithm would give a wrong estimate
for an index where there is just one key value. */
+ if (!index->is_readable()) {
+ mtr_commit(&mtr);
+ goto exit_loop;
+ }
+
page = btr_cur_get_page(&cursor);
rec = page_rec_get_next(page_get_infimum_rec(page));
@@ -6080,6 +6098,7 @@ btr_estimate_number_of_different_key_vals(
mtr_commit(&mtr);
}
+exit_loop:
/* If we saw k borders between different key values on
n_sample_pages leaf pages, we can estimate how many
there will be in index->stat_n_leaf_pages */
diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc
index 06cd1315590..6913124cea1 100644
--- a/storage/innobase/btr/btr0defragment.cc
+++ b/storage/innobase/btr/btr0defragment.cc
@@ -227,7 +227,7 @@ btr_defragment_add_index(
page = buf_block_get_frame(block);
}
- if (page == NULL && index->table->is_encrypted) {
+ if (page == NULL && !index->is_readable()) {
mtr_commit(&mtr);
*err = DB_DECRYPTION_FAILED;
return NULL;
diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc
index 445aa3504b7..fdde6f5d3e7 100644
--- a/storage/innobase/btr/btr0pcur.cc
+++ b/storage/innobase/btr/btr0pcur.cc
@@ -418,6 +418,11 @@ btr_pcur_move_to_next_page(
cursor->old_stored = false;
page = btr_pcur_get_page(cursor);
+
+ if (UNIV_UNLIKELY(!page)) {
+ return;
+ }
+
next_page_no = btr_page_get_next(page, mtr);
ut_ad(next_page_no != FIL_NULL);
@@ -438,6 +443,10 @@ btr_pcur_move_to_next_page(
block->page.size, mode,
btr_pcur_get_btr_cur(cursor)->index, mtr);
+ if (UNIV_UNLIKELY(!next_block)) {
+ return;
+ }
+
next_page = buf_block_get_frame(next_block);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(next_page) == page_is_comp(page));
diff --git a/storage/innobase/btr/btr0scrub.cc b/storage/innobase/btr/btr0scrub.cc
index 307d6d0ec6c..f427a137c4d 100644
--- a/storage/innobase/btr/btr0scrub.cc
+++ b/storage/innobase/btr/btr0scrub.cc
@@ -140,6 +140,7 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table,
} else {
return false;
}
+
os_thread_sleep(250000);
time_t now = time(0);
@@ -571,7 +572,7 @@ btr_scrub_table_needs_scrubbing(
return false;
}
- if (table->corrupted) {
+ if (!table->is_readable()) {
return false;
}
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 754b2cd1c25..e63c234b2f6 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -412,16 +412,6 @@ bool
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
MY_ATTRIBUTE((nonnull));
-/** Check if page is maybe compressed, encrypted or both when we encounter
-corrupted page. Note that we can't be 100% sure if page is corrupted
-or decrypt/decompress just failed.
-@param[in,out] bpage Page
-@return true if page corrupted, false if not */
-static
-bool
-buf_page_check_corrupt(buf_page_t* bpage)
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
@@ -782,20 +772,18 @@ buf_page_is_checksum_valid_none(
&& checksum_field1 == BUF_NO_CHECKSUM_MAGIC);
}
-/** Checks if a page is corrupt.
-@param[in] check_lsn true if we need to check and complain about
-the LSN
+/** Check if a page is corrupt.
+@param[in] check_lsn whether the LSN should be checked
@param[in] read_buf database page
@param[in] page_size page size
@param[in] space tablespace
-@return TRUE if corrupted */
+@return whether the page is corrupted */
bool
buf_page_is_corrupted(
bool check_lsn,
const byte* read_buf,
const page_size_t& page_size,
- const fil_space_t* space
-)
+ const fil_space_t* space)
{
ulint checksum_field1;
ulint checksum_field2;
@@ -970,25 +958,23 @@ buf_page_is_corrupted(
SRV_CHECKSUM_ALGORITHM_NONE,
page_id);
}
-#endif /* !UNIV_INNOCHECKSUM */
-
-#ifdef UNIV_INNOCHECKSUM
+#else /* !UNIV_INNOCHECKSUM */
if (log_file) {
-
fprintf(log_file, "page::%lu;"
- " old style: calculated = " ULINTPF ";"
- " recorded = " ULINTPF "\n", cur_page_num,
+ " old style: calculated = %u;"
+ " recorded = " ULINTPF "\n",
+ cur_page_num,
buf_calc_page_old_checksum(read_buf),
checksum_field2);
fprintf(log_file, "page::%lu;"
- " new style: calculated = " ULINTPF ";"
+ " new style: calculated = %u;"
" crc32 = %u; recorded = " ULINTPF "\n",
cur_page_num,
buf_calc_page_new_checksum(read_buf),
buf_calc_page_crc32(read_buf),
checksum_field1);
}
-#endif /* UNIV_INNOCHECKSUM */
+#endif /* !UNIV_INNOCHECKSUM */
return(false);
}
@@ -1055,24 +1041,22 @@ buf_page_is_corrupted(
SRV_CHECKSUM_ALGORITHM_NONE,
page_id);
}
-#endif /* !UNIV_INNOCHECKSUM */
-
-#ifdef UNIV_INNOCHECKSUM
+#else /* !UNIV_INNOCHECKSUM */
if (log_file) {
fprintf(log_file, "page::%lu;"
- " old style: calculated = %lu;"
+ " old style: calculated = %u;"
" recorded = %lu\n", cur_page_num,
buf_calc_page_old_checksum(read_buf),
checksum_field2);
fprintf(log_file, "page::%lu;"
- " new style: calculated = %lu;"
+ " new style: calculated = %u;"
" crc32 = %u; recorded = %lu\n",
cur_page_num,
buf_calc_page_new_checksum(read_buf),
buf_calc_page_crc32(read_buf),
checksum_field1);
}
-#endif /* UNIV_INNOCHECKSUM */
+#endif /* !UNIV_INNOCHECKSUM */
return(false);
}
@@ -1423,7 +1407,6 @@ buf_block_init(
block->page.buf_fix_count = 0;
block->page.io_fix = BUF_IO_NONE;
block->page.flush_observer = NULL;
- block->page.key_version = 0;
block->page.encrypted = false;
block->page.real_size = 0;
block->page.write_size = 0;
@@ -3709,7 +3692,6 @@ buf_page_get_zip(
ibool discard_attempted = FALSE;
ibool must_read;
buf_pool_t* buf_pool = buf_pool_get(page_id);
- buf_page_t* rpage = NULL;
buf_pool->stat.n_page_gets++;
@@ -3728,7 +3710,14 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(page_id, page_size, &rpage);
+ dberr_t err = buf_read_page(page_id, page_size);
+
+ if (err != DB_SUCCESS) {
+ ib::error() << "Reading compressed page " << page_id
+ << " failed with error: " << ut_strerr(err);
+
+ goto err_exit;
+ }
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -4205,7 +4194,6 @@ loop:
}
if (block == NULL) {
- buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
@@ -4263,7 +4251,20 @@ loop:
return(NULL);
}
- if (buf_read_page(page_id, page_size, &bpage)) {
+ /* The call path is buf_read_page() ->
+ buf_read_page_low() (fil_io()) ->
+ buf_page_io_complete() ->
+ buf_decrypt_after_read(). Here fil_space_t* is used
+ and we decrypt -> buf_page_check_corrupt() where page
+ checksums are compared. Decryption, decompression as
+ well as error handling takes place at a lower level.
+ Here we only need to know whether the page really is
+ corrupted, or if an encrypted page with a valid
+ checksum cannot be decypted. */
+
+ dberr_t local_err = buf_read_page(page_id, page_size);
+
+ if (local_err == DB_SUCCESS) {
buf_read_ahead_random(page_id, page_size,
ibuf_inside(mtr));
@@ -4271,82 +4272,44 @@ loop:
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
- }
-
- /* Do not try again for encrypted pages */
- if (corrupted && bpage->encrypted) {
- BPageMutex* pmutex = buf_page_get_mutex(bpage);
-
- buf_pool = buf_pool_from_bpage(bpage);
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- my_atomic_addlint(&buf_pool->n_pend_reads, -1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(pmutex);
- buf_LRU_free_page(bpage, true);
- buf_pool_mutex_exit(buf_pool);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
-
- return (NULL);
- }
-
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
+ if (err) {
+ *err = local_err;
}
- if (corrupted && !bpage->encrypted) {
- ib::fatal() << "Unable to read page " << page_id
- << " into the buffer pool after "
- << BUF_PAGE_READ_MAX_RETRIES << " attempts."
- " The most probable cause of this error may"
- " be that the table has been corrupted. Or,"
- " the table was compressed with with an"
- " algorithm that is not supported by this"
- " instance. If it is not a decompress failure,"
- " you can try to fix this problem by using"
- " innodb_force_recovery."
- " Please see " REFMAN " for more"
- " details. Aborting...";
- } else {
- BPageMutex* pmutex = buf_page_get_mutex(bpage);
-
- buf_pool = buf_pool_from_bpage(bpage);
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- my_atomic_addlint(&buf_pool->n_pend_reads, -1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(pmutex);
- buf_LRU_free_page(bpage, true);
- buf_pool_mutex_exit(buf_pool);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
+ /* Pages whose encryption key is unavailable or used
+ key, encryption algorithm or encryption method is
+ incorrect are marked as encrypted in
+ buf_page_check_corrupt(). Unencrypted page could be
+ corrupted in a way where the key_id field is
+ nonzero. There is no checksum on field
+ FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION. */
+ if (local_err == DB_DECRYPTION_FAILED) {
+ return (NULL);
+ }
+ /* Try to set table as corrupted instead of
+ asserting. */
+ if (page_id.space() != TRX_SYS_SPACE &&
+ dict_set_corrupted_by_space(page_id.space())) {
return (NULL);
}
+
+ ib::fatal() << "Unable to read page " << page_id
+ << " into the buffer pool after "
+ << BUF_PAGE_READ_MAX_RETRIES
+ << ". The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted."
+ " You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery."
+ " Please see " REFMAN " for more"
+ " details. Aborting...";
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -5113,7 +5076,6 @@ buf_page_init_low(
bpage->newest_modification = 0;
bpage->oldest_modification = 0;
bpage->write_size = 0;
- bpage->key_version = 0;
bpage->encrypted = false;
bpage->real_size = 0;
bpage->slot = NULL;
@@ -5210,7 +5172,7 @@ buf_page_init(
}
}
-/** Inits a page for read to the buffer buf_pool. If the page is
+/** Initialize a page for read to the buffer buf_pool. If the page is
(1) already in buf_pool, or
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
(3) if the space is deleted or being deleted,
@@ -5221,15 +5183,17 @@ and the lock released later.
@param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED
@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...
@param[in] page_id page id
-@param[in] unzip TRUE=request uncompressed page
-@return pointer to the block or NULL */
+@param[in] unzip whether the uncompressed page is
+ requested (for ROW_FORMAT=COMPRESSED)
+@return pointer to the block
+@retval NULL in case of an error */
buf_page_t*
buf_page_init_for_read(
dberr_t* err,
ulint mode,
const page_id_t& page_id,
const page_size_t& page_size,
- ibool unzip)
+ bool unzip)
{
buf_block_t* block;
buf_page_t* bpage = NULL;
@@ -5708,72 +5672,74 @@ buf_page_monitor(
/********************************************************************//**
Mark a table with the specified space pointed by bpage->id.space() corrupted.
Also remove the bpage from LRU list.
-@return TRUE if successful */
+@param[in,out] bpage Block */
static
-ibool
-buf_mark_space_corrupt(
-/*===================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+void
+buf_mark_space_corrupt(buf_page_t* bpage)
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
- ib_uint32_t space = bpage->id.space();
- ibool ret = TRUE;
+ uint32_t space = bpage->id.space();
- if (!bpage->encrypted) {
- /* First unfix and release lock on the bpage */
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
-
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ /* First unfix and release lock on the bpage */
+ buf_pool_mutex_enter(buf_pool);
+ mutex_enter(buf_page_get_mutex(bpage));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(buf_page_get_mutex(bpage));
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
}
- /* Find the table with specified space id, and mark it corrupted */
- if (dict_set_corrupted_by_space(space)) {
- if (!bpage->encrypted) {
- buf_LRU_free_one_page(bpage);
- }
+ mutex_exit(buf_page_get_mutex(bpage));
+
+ /* If block is not encrypted find the table with specified
+ space id, and mark it corrupted. Encrypted tables
+ are marked unusable later e.g. in ::open(). */
+ if (!bpage->encrypted) {
+ dict_set_corrupted_by_space(space);
} else {
- ret = FALSE;
+ dict_set_encrypted_by_space(space);
}
- if (!bpage->encrypted) {
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
+ /* After this point bpage can't be referenced. */
+ buf_LRU_free_one_page(bpage);
- buf_pool_mutex_exit(buf_pool);
- }
+ ut_ad(buf_pool->n_pend_reads > 0);
+ buf_pool->n_pend_reads--;
- return(ret);
+ buf_pool_mutex_exit(buf_pool);
}
/** Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
-@param[in,out] bpage Page
-@return true if page corrupted, false if not */
+@param[in,out] bpage page
+@param[in,out] space tablespace from fil_space_acquire_for_io()
+@return whether the operation succeeded
+@retval DB_SUCCESS if page has been read and is not corrupted
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if accessed tablespace is not found */
static
-bool
-buf_page_check_corrupt(buf_page_t* bpage)
+dberr_t
+buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space)
{
+ ut_ad(space->n_pending_ios > 0);
+
byte* dst_frame = (bpage->zip.data) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
- fil_space_t* space = fil_space_acquire_silent(bpage->id.space());
bool still_encrypted = false;
+ dberr_t err = DB_SUCCESS;
bool corrupted = false;
- fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL;
+ fil_space_crypt_t* crypt_data = space->crypt_data;
/* In buf_decrypt_after_read we have either decrypted the page if
page post encryption checksum matches and used key_id is found
@@ -5784,9 +5750,9 @@ buf_page_check_corrupt(buf_page_t* bpage)
still_encrypted = crypt_data
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& !bpage->encrypted
- && fil_space_verify_crypt_checksum(dst_frame, bpage->size,
- bpage->id.space(),
- bpage->id.page_no());
+ && fil_space_verify_crypt_checksum(
+ dst_frame, bpage->size,
+ bpage->id.space(), bpage->id.page_no());
if (!still_encrypted) {
/* If traditional checksums match, we assume that page is
@@ -5796,6 +5762,8 @@ buf_page_check_corrupt(buf_page_t* bpage)
if (!corrupted) {
bpage->encrypted = false;
+ } else {
+ err = DB_PAGE_CORRUPTED;
}
}
@@ -5806,16 +5774,18 @@ buf_page_check_corrupt(buf_page_t* bpage)
buf_page_io_complete(). */
} else if (still_encrypted || (bpage->encrypted && corrupted)) {
bpage->encrypted = true;
- corrupted = true;
+ err = DB_DECRYPTION_FAILED;
ib::error()
- << "The page " << bpage->id << " in file "
- << (space && space->name ? space->name : "NULL")
- << " cannot be decrypted.";
+ << "The page " << bpage->id << " in file '"
+ << space->chain.start->name
+ << "' cannot be decrypted.";
ib::info()
<< "However key management plugin or used key_version "
- << bpage->key_version << " is not found or"
+ << mach_read_from_4(dst_frame
+ + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)
+ << " is not found or"
" used encryption algorithm or method does not match.";
if (bpage->id.space() != TRX_SYS_SPACE) {
@@ -5827,32 +5797,28 @@ buf_page_check_corrupt(buf_page_t* bpage)
}
}
- if (space) {
- fil_space_release(space);
- }
-
- return corrupted;
+ return (err);
}
-/********************************************************************//**
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool.
-@return true if successful */
-bool
-buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage, /*!< in: pointer to the block in question */
- bool evict) /*!< in: whether or not to evict the page
- from LRU list. */
-
+/** Complete a read or write request of a file page to or from the buffer pool.
+@param[in,out] bpage Page to complete
+@param[in] evict whether or not to evict the page
+ from LRU list.
+@return whether the operation succeeded
+@retval DB_SUCCESS always when writing, or if a read page was OK
+@retval DB_TABLESPACE_DELETED if the tablespace does not exist
+@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+ after decryption normal page checksum does
+ not match */
+UNIV_INTERN
+dberr_t
+buf_page_io_complete(buf_page_t* bpage, bool evict)
{
enum buf_io_fix io_type;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
- const ibool uncompressed = (buf_page_get_state(bpage)
+ const bool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
- byte* frame = NULL;
- bool corrupted = false;
-
ut_a(buf_page_in_file(bpage));
/* We do not need protect io_fix here by mutex to read
@@ -5863,46 +5829,42 @@ buf_page_io_complete(
io_type = buf_page_get_io_fix(bpage);
ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
+ ut_ad(bpage->size.is_compressed() == (bpage->zip.data != NULL));
+ ut_ad(uncompressed || bpage->zip.data);
if (io_type == BUF_IO_READ) {
- ulint read_page_no;
- ulint read_space_id;
+ ulint read_page_no = 0;
+ ulint read_space_id = 0;
+ uint key_version = 0;
ut_ad(bpage->zip.data != NULL || ((buf_block_t*)bpage)->frame != NULL);
fil_space_t* space = fil_space_acquire_for_io(
bpage->id.space());
if (!space) {
- return false;
+ return DB_TABLESPACE_DELETED;
}
buf_page_decrypt_after_read(bpage, space);
- if (bpage->size.is_compressed()) {
- frame = bpage->zip.data;
- } else {
- frame = ((buf_block_t*) bpage)->frame;
- }
-
- if (bpage->size.is_compressed()) {
- frame = bpage->zip.data;
- buf_pool->n_pend_unzip++;
-
- if (uncompressed
- && !buf_zip_decompress((buf_block_t*) bpage,
- FALSE)) {
+ byte* frame = bpage->zip.data
+ ? bpage->zip.data
+ : reinterpret_cast<buf_block_t*>(bpage)->frame;
+ dberr_t err;
- buf_pool->n_pend_unzip--;
+ if (bpage->zip.data && uncompressed) {
+ my_atomic_addlint(&buf_pool->n_pend_unzip, 1);
+ ibool ok = buf_zip_decompress((buf_block_t*) bpage,
+ FALSE);
+ my_atomic_addlint(&buf_pool->n_pend_unzip, -1);
+ if (!ok) {
ib::info() << "Page "
<< bpage->id
<< " zip_decompress failure.";
+ err = DB_PAGE_CORRUPTED;
goto database_corrupted;
}
- buf_pool->n_pend_unzip--;
- } else {
- ut_a(uncompressed);
- frame = ((buf_block_t*) bpage)->frame;
}
/* If this page is not uninitialized and not in the
@@ -5911,6 +5873,8 @@ buf_page_io_complete(
read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
read_space_id = mach_read_from_4(
frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ key_version = mach_read_from_4(
+ frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
if (bpage->id.space() == TRX_SYS_SPACE
&& buf_dblwr_page_inside(bpage->id.page_no())) {
@@ -5934,28 +5898,29 @@ buf_page_io_complete(
<< ", should be " << bpage->id;
}
- corrupted = buf_page_check_corrupt(bpage);
+ err = buf_page_check_corrupt(bpage, space);
database_corrupted:
- if (corrupted) {
+ if (err != DB_SUCCESS) {
/* Not a real corruption if it was triggered by
error injection */
DBUG_EXECUTE_IF(
"buf_page_import_corrupt_failure",
if (bpage->id.space()
> srv_undo_tablespaces_open
- && bpage->id.space() != SRV_TMP_SPACE_ID
- && buf_mark_space_corrupt(bpage)) {
+ && bpage->id.space() != SRV_TMP_SPACE_ID) {
+ buf_mark_space_corrupt(bpage);
ib::info() << "Simulated IMPORT "
"corruption";
fil_space_release_for_io(space);
- return(true);
+ return(err);
}
+ err = DB_SUCCESS;
goto page_not_corrupt;
);
- if (!bpage->encrypted) {
+ if (err == DB_PAGE_CORRUPTED) {
ib::error()
<< "Database page corruption on disk"
" or a failed file read of tablespace "
@@ -5985,38 +5950,14 @@ database_corrupted:
/* If page space id is larger than TRX_SYS_SPACE
(0), we will attempt to mark the corresponding
table as corrupted instead of crashing server */
-
- if (bpage->id.space() > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
- fil_space_release_for_io(space);
- return(false);
- } else {
- if (!bpage->encrypted) {
- ib::fatal()
- << "Aborting because of a"
- " corrupt database page in"
- " the system tablespace. Or, "
- " there was a failure in"
- " tagging the tablespace "
- " as corrupt.";
- }
-
- ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
- "Table in tablespace %u encrypted."
- "However key management plugin or used key_id %lu is not found or"
- " used encryption algorithm or method does not match."
- " Can't continue opening the table.",
- bpage->id.space(), bpage->key_version);
-
- if (bpage->encrypted && bpage->id.space() > TRX_SYS_SPACE) {
- buf_mark_space_corrupt(bpage);
- } else {
- ut_error;
- }
-
- fil_space_release_for_io(space);
- return(false);
+ if (bpage->id.space() == TRX_SYS_SPACE) {
+ ib::fatal() << "Aborting because of"
+ " a corrupt database page.";
}
+
+ buf_mark_space_corrupt(bpage);
+ fil_space_release_for_io(space);
+ return(err);
}
}
@@ -6046,7 +5987,7 @@ database_corrupted:
<< bpage->id.space()
<< " encrypted. However key "
"management plugin or used "
- << "key_version " << bpage->key_version
+ << "key_version " << key_version
<< "is not found or"
" used encryption algorithm or method does not match."
" Can't continue opening the table.";
@@ -6150,7 +6091,7 @@ database_corrupted:
buf_pool_mutex_exit(buf_pool);
- return(true);
+ return DB_SUCCESS;
}
/*********************************************************************//**
@@ -6173,9 +6114,7 @@ buf_all_freed_instance(
for (i = buf_pool->n_chunks; i--; chunk++) {
- const buf_block_t* block = buf_chunk_not_freed(chunk);
-
- if (UNIV_LIKELY_NULL(block) && block->page.key_version == 0) {
+ if (const buf_block_t* block = buf_chunk_not_freed(chunk)) {
ib::fatal() << "Page " << block->page.id
<< " still fixed or dirty";
}
@@ -7324,33 +7263,29 @@ buf_page_encrypt_before_write(
switch (bpage->id.page_no()) {
case 0:
/* Page 0 of a tablespace is not encrypted/compressed */
- ut_ad(bpage->key_version == 0);
return src_frame;
case TRX_SYS_PAGE_NO:
if (bpage->id.space() == TRX_SYS_SPACE) {
/* don't encrypt/compress page as it contains
address to dblwr buffer */
- bpage->key_version = 0;
return src_frame;
}
}
- const page_size_t page_size(space->flags);
fil_space_crypt_t* crypt_data = space->crypt_data;
+
const bool encrypted = crypt_data
&& !crypt_data->not_encrypted()
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
|| srv_encrypt_tables);
- if (!encrypted) {
- bpage->key_version = 0;
- }
-
bool page_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags);
if (!encrypted && !page_compressed) {
- /* No need to encrypt or page compress the page */
+ /* No need to encrypt or page compress the page.
+ Clear key-version & crypt-checksum. */
+ memset(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
return src_frame;
}
@@ -7370,11 +7305,6 @@ buf_page_encrypt_before_write(
src_frame,
dst_frame);
- uint32_t key_version = mach_read_from_4(
- dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
- ut_ad(key_version == 0 || key_version >= bpage->key_version);
- bpage->key_version = key_version;
- bpage->real_size = page_size.physical();
slot->out_buf = dst_frame = tmp;
ut_d(fil_page_type_validate(tmp));
@@ -7386,7 +7316,7 @@ buf_page_encrypt_before_write(
space,
(byte *)src_frame,
slot->comp_buf,
- page_size.logical(),
+ srv_page_size,
fsp_flags_get_page_compression_level(space->flags),
fil_space_get_block_size(space, bpage->id.page_no()),
encrypted,
@@ -7440,8 +7370,6 @@ buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
bool success = true;
- bpage->key_version = key_version;
-
if (bpage->id.page_no() == 0) {
/* File header pages are not encrypted/compressed */
return (true);
@@ -7481,6 +7409,10 @@ buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
if (!fil_space_verify_crypt_checksum(
dst_frame, size,
bpage->id.space(), bpage->id.page_no())) {
+ if (space->crypt_data->type
+ != CRYPT_SCHEME_UNENCRYPTED) {
+ bpage->encrypted = true;
+ }
return (false);
}
@@ -7490,12 +7422,8 @@ buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
ut_d(fil_page_type_validate(dst_frame));
/* decrypt using crypt_buf to dst_frame */
- byte* res = fil_space_decrypt(space,
- slot->crypt_buf,
- dst_frame,
- &bpage->encrypted);
-
- if (!res) {
+ if (!fil_space_decrypt(space, slot->crypt_buf,
+ dst_frame, &bpage->encrypted)) {
success = false;
}
diff --git a/storage/innobase/buf/buf0checksum.cc b/storage/innobase/buf/buf0checksum.cc
index 94eafec0584..4b56cc81e98 100644
--- a/storage/innobase/buf/buf0checksum.cc
+++ b/storage/innobase/buf/buf0checksum.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, 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
@@ -80,15 +81,13 @@ buf_calc_page_crc32(
return(c1 ^ c2);
}
-/********************************************************************//**
-Calculates a page checksum which is stored to the page when it is written
+/** Calculate a checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
32-bit and 64-bit architectures.
+@param[in] page file page (srv_page_size bytes)
@return checksum */
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
- const byte* page) /*!< in: buffer page */
+uint32_t
+buf_calc_page_new_checksum(const byte* page)
{
ulint checksum;
@@ -106,40 +105,29 @@ buf_calc_page_new_checksum(
+ ut_fold_binary(page + FIL_PAGE_DATA,
UNIV_PAGE_SIZE - FIL_PAGE_DATA
- FIL_PAGE_END_LSN_OLD_CHKSUM);
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
+ return(static_cast<uint32_t>(checksum));
}
-/********************************************************************//**
-In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
-looked at the first few bytes of the page. This calculates that old
-checksum.
+/** In MySQL before 4.0.14 or 4.1.1 there was an InnoDB bug that
+the checksum only looked at the first few bytes of the page.
+This calculates that old checksum.
NOTE: we must first store the new formula checksum to
FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
because this takes that field as an input!
+@param[in] page file page (srv_page_size bytes)
@return checksum */
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
- const byte* page) /*!< in: buffer page */
+uint32_t
+buf_calc_page_old_checksum(const byte* page)
{
- ulint checksum;
-
- checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
-
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
+ return(static_cast<uint32_t>
+ (ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)));
}
-/********************************************************************//**
-Return a printable string describing the checksum algorithm.
+/** Return a printable string describing the checksum algorithm.
+@param[in] algo algorithm
@return algorithm name */
const char*
-buf_checksum_algorithm_name(
-/*========================*/
- srv_checksum_algorithm_t algo) /*!< in: algorithm */
+buf_checksum_algorithm_name(srv_checksum_algorithm_t algo)
{
switch (algo) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 7b0597f27ea..2a9acc8c298 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -1119,15 +1119,20 @@ buf_flush_write_block_low(
fil_flush(space);
}
- /* true means we want to evict this page from the
- LRU list as well. */
/* The tablespace could already have been dropped,
because fil_io(request, sync) would already have
decremented the node->n_pending. However,
buf_page_io_complete() only needs to look up the
tablespace during read requests, not during writes. */
ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_WRITE);
+#ifdef UNIV_DEBUG
+ dberr_t err =
+#endif
+ /* true means we want to evict this page from the
+ LRU list as well. */
buf_page_io_complete(bpage, true);
+
+ ut_ad(err == DB_SUCCESS);
}
fil_space_release_for_io(space);
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 10a8561d38d..1e7b7065b12 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -1420,7 +1420,7 @@ loop:
++flush_failures;
}
- srv_stats.buf_pool_wait_free.add(n_iterations, 1);
+ srv_stats.buf_pool_wait_free.inc();
n_iterations++;
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index f5bd088ce5c..12775c74daf 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2016 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
@@ -118,8 +118,7 @@ buf_read_page_low(
ulint mode,
const page_id_t& page_id,
const page_size_t& page_size,
- bool unzip,
- buf_page_t** rbpage) /*!< out: page */
+ bool unzip)
{
buf_page_t* bpage;
@@ -155,12 +154,9 @@ buf_read_page_low(
return(0);
}
- DBUG_PRINT("ib_buf", ("read page %u:%u size=%u unzip=%u,%s",
- (unsigned) page_id.space(),
- (unsigned) page_id.page_no(),
- (unsigned) page_size.physical(),
- (unsigned) unzip,
- sync ? "sync" : "async"));
+ DBUG_LOG("ib_buf",
+ "read page " << page_id << " size=" << page_size.physical()
+ << " unzip=" << unzip << ',' << (sync ? "sync" : "async"));
ut_ad(buf_page_in_file(bpage));
@@ -213,19 +209,13 @@ buf_read_page_low(
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
+ *err = buf_page_io_complete(bpage);
- if (!buf_page_io_complete(bpage)) {
- if (rbpage) {
- *rbpage = bpage;
- }
+ if (*err != DB_SUCCESS) {
return(0);
}
}
- if (rbpage) {
- *rbpage = bpage;
- }
-
return(1);
}
@@ -256,7 +246,7 @@ buf_read_ahead_random(
ulint ibuf_mode;
ulint count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_random_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -369,19 +359,25 @@ read_ahead:
const page_id_t cur_page_id(page_id.space(), i);
if (!ibuf_bitmap_page(cur_page_id, page_size)) {
- buf_page_t* rpage = NULL;
count += buf_read_page_low(
&err, false,
IORequest::DO_NOT_WAKE,
ibuf_mode,
- cur_page_id, page_size, false, &rpage);
+ cur_page_id, page_size, false);
- if (err == DB_TABLESPACE_DELETED) {
- ib::warn() << "Random readahead trying to"
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib::info() << "Random readahead trying to"
" access page " << cur_page_id
<< " in nonexisting or"
" being-dropped tablespace";
break;
+ default:
+ ut_error;
}
}
}
@@ -414,15 +410,18 @@ an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@param[in] page_id page id
@param[in] page_size page size
-@return TRUE if page has been read in, FALSE in case of failure */
-ibool
+@retval DB_SUCCESS if the page was read and is not corrupted,
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */
+dberr_t
buf_read_page(
const page_id_t& page_id,
- const page_size_t& page_size,
- buf_page_t** bpage) /*!< out: page */
+ const page_size_t& page_size)
{
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
/* We do synchronous IO because our AIO completion code
is sub-optimal. See buf_page_io_complete(), we have to
@@ -432,19 +431,19 @@ buf_read_page(
count = buf_read_page_low(
&err, true,
- 0, BUF_READ_ANY_PAGE, page_id, page_size, false, bpage);
+ 0, BUF_READ_ANY_PAGE, page_id, page_size, false);
srv_stats.buf_pool_reads.add(count);
if (err == DB_TABLESPACE_DELETED) {
- ib::error() << "trying to read page " << page_id
+ ib::info() << "trying to read page " << page_id
<< " in nonexisting or being-dropped tablespace";
}
/* Increment number of I/O operations used for LRU policy. */
buf_LRU_stat_inc_io();
- return(count > 0);
+ return(err);
}
/** High-level function which reads a page asynchronously from a file to the
@@ -453,9 +452,8 @@ an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@param[in] page_id page id
@param[in] page_size page size
-@param[in] sync true if synchronous aio is desired
-@return TRUE if page has been read in, FALSE in case of failure */
-ibool
+@param[in] sync true if synchronous aio is desired */
+void
buf_read_page_background(
const page_id_t& page_id,
const page_size_t& page_size,
@@ -463,13 +461,31 @@ buf_read_page_background(
{
ulint count;
dberr_t err;
- buf_page_t* rbpage = NULL;
count = buf_read_page_low(
&err, sync,
IORequest::DO_NOT_WAKE | IORequest::IGNORE_MISSING,
BUF_READ_ANY_PAGE,
- page_id, page_size, false, &rbpage);
+ page_id, page_size, false);
+
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib::info() << "trying to read page " << page_id
+ << " in the background"
+ " in a non-existing or being-dropped tablespace";
+ break;
+ case DB_DECRYPTION_FAILED:
+ ib::error()
+ << "Background Page read failed to decrypt page "
+ << page_id;
+ break;
+ default:
+ ut_error;
+ }
srv_stats.buf_pool_reads.add(count);
@@ -479,8 +495,6 @@ buf_read_page_background(
buffer pool. Since this function is called from buffer pool load
these IOs are deliberate and are not part of normal workload we can
ignore these in our heuristics. */
-
- return(count > 0);
}
/** Applies linear read-ahead if in the buf_pool the page is a border page of
@@ -525,7 +539,7 @@ buf_read_ahead_linear(
ulint new_offset;
ulint fail_count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_linear_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -730,19 +744,29 @@ buf_read_ahead_linear(
const page_id_t cur_page_id(page_id.space(), i);
if (!ibuf_bitmap_page(cur_page_id, page_size)) {
- buf_page_t* rpage = NULL;
-
count += buf_read_page_low(
&err, false,
IORequest::DO_NOT_WAKE,
- ibuf_mode, cur_page_id, page_size, false, &rpage);
+ ibuf_mode, cur_page_id, page_size, false);
- if (err == DB_TABLESPACE_DELETED) {
- ib::warn() << "linear readahead trying to"
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib::info() << "linear readahead trying to"
" access page "
<< page_id_t(page_id.space(), i)
<< " in nonexisting or being-dropped"
" tablespace";
+ case DB_DECRYPTION_FAILED:
+ ib::error() << "linear readahead failed to"
+ " decrypt page "
+ << page_id_t(page_id.space(), i);
+ break;
+ default:
+ ut_error;
}
}
}
@@ -797,13 +821,13 @@ buf_read_ibuf_merge_pages(
const page_id_t page_id(space_ids[i], page_nos[i]);
buf_pool_t* buf_pool = buf_pool_get(page_id);
- buf_page_t* rpage = NULL;
bool found;
const page_size_t page_size(fil_space_get_page_size(
space_ids[i], &found));
if (!found) {
+tablespace_deleted:
/* The tablespace was not found, remove the
entries for that page */
ibuf_merge_or_delete_for_page(NULL, page_id,
@@ -822,13 +846,21 @@ buf_read_ibuf_merge_pages(
sync && (i + 1 == n_stored),
0,
BUF_READ_ANY_PAGE, page_id, page_size,
- true, &rpage);
-
- if (err == DB_TABLESPACE_DELETED) {
- /* We have deleted or are deleting the single-table
- tablespace: remove the entries for that page */
- ibuf_merge_or_delete_for_page(NULL, page_id,
- &page_size, FALSE);
+ true);
+
+ switch(err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ goto tablespace_deleted;
+ case DB_DECRYPTION_FAILED:
+ ib::error() << "Failed to decrypt page " << page_id
+ << " for change buffer merge";
+ break;
+ default:
+ ut_error;
}
}
@@ -855,9 +887,6 @@ buf_read_recv_pages(
const ulint* page_nos,
ulint n_stored)
{
- ulint count;
- dberr_t err;
- ulint i;
fil_space_t* space = fil_space_get(space_id);
if (space == NULL) {
@@ -869,12 +898,11 @@ buf_read_recv_pages(
const page_size_t page_size(space->flags);
- for (i = 0; i < n_stored; i++) {
+ for (ulint i = 0; i < n_stored; i++) {
buf_pool_t* buf_pool;
const page_id_t cur_page_id(space_id, page_nos[i]);
- buf_page_t* rpage = NULL;
- count = 0;
+ ulint count = 0;
buf_pool = buf_pool_get(cur_page_id);
while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) {
@@ -894,18 +922,25 @@ buf_read_recv_pages(
}
}
- if ((i + 1 == n_stored) && sync) {
+ dberr_t err;
+
+ if (sync && i + 1 == n_stored) {
buf_read_page_low(
&err, true,
0,
BUF_READ_ANY_PAGE,
- cur_page_id, page_size, true, &rpage);
+ cur_page_id, page_size, true);
} else {
buf_read_page_low(
&err, false,
IORequest::DO_NOT_WAKE,
BUF_READ_ANY_PAGE,
- cur_page_id, page_size, true, &rpage);
+ cur_page_id, page_size, true);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib::error() << "Recovery failed to decrypt page "
+ << cur_page_id;
}
}
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index c1bd5c2d368..1b5b6ff3850 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -890,7 +890,7 @@ dict_create_index_tree_step(
mtr_start(&mtr);
- const bool missing = index->table->ibd_file_missing
+ const bool missing = !index->is_readable()
|| dict_table_is_discarded(index->table);
if (!missing) {
@@ -963,8 +963,8 @@ dict_create_index_tree_in_mem(
/* Currently this function is being used by temp-tables only.
Import/Discard of temp-table is blocked and so this assert. */
- ut_ad(index->table->ibd_file_missing == 0
- && !dict_table_is_discarded(index->table));
+ ut_ad(index->is_readable());
+ ut_ad(!dict_table_is_discarded(index->table));
page_no = btr_create(
index->type, index->space,
@@ -1246,7 +1246,7 @@ tab_create_graph_create(
structure */
mem_heap_t* heap, /*!< in: heap where created */
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;
@@ -2054,7 +2054,7 @@ dict_foreign_def_get_fields(
trx_t* trx, /*!< in: trx */
char** field, /*!< out: foreign column */
char** field2, /*!< out: referenced column */
- int col_no) /*!< in: column number */
+ ulint col_no) /*!< in: column number */
{
char* bufend;
char* fieldbuf = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc
index 016b774217f..ccb73e02f43 100644
--- a/storage/innobase/dict/dict0defrag_bg.cc
+++ b/storage/innobase/dict/dict0defrag_bg.cc
@@ -320,25 +320,14 @@ dict_stats_save_defrag_stats(
{
dberr_t ret;
- if (index->table->ibd_file_missing) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save defragment stats because "
- ".ibd file is missing.\n");
- return (DB_TABLESPACE_DELETED);
- }
- if (dict_index_is_corrupted(index)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save defragment stats because "
- "index is corrupted.\n");
- return(DB_CORRUPTION);
- }
-
if (dict_index_is_univ(index)) {
return DB_SUCCESS;
}
+ if (!index->is_readable()) {
+ return dict_stats_report_error(index->table, true);
+ }
+
lint now = (lint) ut_time();
mtr_t mtr;
ulint n_leaf_pages;
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 0d949a00b27..b733ac580d9 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1178,12 +1178,24 @@ dict_table_open_on_name(
if (table != NULL) {
- /* If table is encrypted return table */
+ /* If table is encrypted or corrupted */
if (ignore_err == DICT_ERR_IGNORE_NONE
- && table->is_encrypted) {
+ && !table->is_readable()) {
/* Make life easy for drop table. */
dict_table_prevent_eviction(table);
+ if (table->corrupted) {
+
+ ib::error() << "Table " << table->name
+ << " is corrupted. Please "
+ "drop the table and recreate.";
+ if (!dict_locked) {
+ mutex_exit(&dict_sys->mutex);
+ }
+
+ DBUG_RETURN(NULL);
+ }
+
if (table->can_be_evicted) {
dict_move_to_mru(table);
}
@@ -1196,22 +1208,6 @@ dict_table_open_on_name(
DBUG_RETURN(table);
}
- /* If table is corrupted, return NULL */
- else if (ignore_err == DICT_ERR_IGNORE_NONE
- && table->corrupted) {
- /* Make life easy for drop table. */
- dict_table_prevent_eviction(table);
- if (!dict_locked) {
- mutex_exit(&dict_sys->mutex);
- }
-
- ib::info() << "Table "
- << table->name
- << " is corrupted. Please drop the table"
- " and recreate it";
-
- DBUG_RETURN(NULL);
- }
if (table->can_be_evicted) {
dict_move_to_mru(table);
@@ -6068,11 +6064,29 @@ dict_set_corrupted_by_space(
/* mark the table->corrupted bit only, since the caller
could be too deep in the stack for SYS_INDEXES update */
- table->corrupted = TRUE;
+ table->corrupted = true;
+ table->file_unreadable = true;
return(TRUE);
}
+
+/** Flag a table with specified space_id encrypted in the data dictionary
+cache
+@param[in] space_id Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(ulint space_id)
+{
+ dict_table_t* table;
+
+ table = dict_find_single_table_by_space(space_id);
+
+ if (table) {
+ table->file_unreadable = true;
+ }
+}
+
/**********************************************************************//**
Flags an index corrupted both in the data dictionary cache
and in the SYS_INDEXES */
@@ -6582,7 +6596,8 @@ dict_table_schema_check(
}
}
- if (table->ibd_file_missing) {
+ if (!table->is_readable() &&
+ fil_space_get(table->space) == NULL) {
/* missing tablespace */
ut_snprintf(errstr, errstr_sz,
@@ -6746,7 +6761,7 @@ dict_fs2utf8(
db[db_len] = '\0';
strconvert(
- &my_charset_filename, db, db_len, system_charset_info,
+ &my_charset_filename, db, uint(db_len), system_charset_info,
db_utf8, uint(db_utf8_size), &errors);
/* convert each # to @0023 in table name and store the result in buf */
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index da72126793f..ba1fbc5eb5d 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -80,7 +80,7 @@ key constraints are loaded into memory.
constraints are loaded.
@return table, NULL if does not exist; if the table is stored in an
.ibd file, but the file does not exist, then we set the
-ibd_file_missing flag TRUE in the table object we return */
+file_unreadable flag in the table object we return */
static
dict_table_t*
dict_load_table_one(
@@ -2430,7 +2430,7 @@ dict_load_indexes(
dict_mem_index_free(index);
goto func_exit;
} else if (index->page == FIL_NULL
- && !table->ibd_file_missing
+ && table->is_readable()
&& (!(index->type & DICT_FTS))) {
ib::error() << "Trying to load index " << index->name
@@ -2551,7 +2551,7 @@ dict_load_table_low(table_name_t& name, const rec_t* rec, dict_table_t** table)
*table = dict_mem_table_create(
name.m_name, space_id, n_cols + n_v_col, n_v_col, flags, flags2);
(*table)->id = table_id;
- (*table)->ibd_file_missing = FALSE;
+ (*table)->file_unreadable = false;
return(NULL);
}
@@ -2644,7 +2644,7 @@ a foreign key references columns in this table.
@param[in] ignore_err Error to be ignored when loading
table and its index definition
@return table, NULL if does not exist; if the table is stored in an
-.ibd file, but the file does not exist, then we set the ibd_file_missing
+.ibd file, but the file does not exist, then we set the file_unreadable
flag in the table object we return. */
dict_table_t*
dict_load_table(
@@ -2709,7 +2709,7 @@ dict_load_tablespace(
if (table->flags2 & DICT_TF2_DISCARDED) {
ib::warn() << "Tablespace for table " << table->name
<< " is set as discarded.";
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
return;
}
@@ -2754,7 +2754,7 @@ dict_load_tablespace(
if (err != DB_SUCCESS) {
/* We failed to find a sensible tablespace file */
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
}
ut_free(filepath);
@@ -2777,7 +2777,7 @@ key constraints are loaded into memory.
constraints are loaded.
@return table, NULL if does not exist; if the table is stored in an
.ibd file, but the file does not exist, then we set the
-ibd_file_missing flag TRUE in the table object we return */
+file_unreadable flag in the table object we return */
static
dict_table_t*
dict_load_table_one(
@@ -2886,9 +2886,10 @@ err_exit:
were not allowed while the table is being locked by a transaction. */
dict_err_ignore_t index_load_err =
!(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)
- && table->ibd_file_missing
+ && !table->is_readable()
? DICT_ERR_IGNORE_ALL
: ignore_err;
+
err = dict_load_indexes(table, heap, index_load_err);
if (err == DB_INDEX_CORRUPT) {
@@ -2908,7 +2909,7 @@ err_exit:
clust_index = dict_table_get_first_index(table);
if (dict_index_is_corrupted(clust_index)) {
- table->corrupted = TRUE;
+ table->corrupted = true;
}
}
}
@@ -2947,7 +2948,7 @@ err_exit:
of the error condition, since the user may want to dump data from the
clustered index. However we load the foreign key information only if
all indexes were loaded. */
- if (!cached || table->ibd_file_missing) {
+ if (!cached || !table->is_readable()) {
/* Don't attempt to load the indexes from disk. */
} else if (err == DB_SUCCESS) {
err = dict_load_foreigns(table->name.m_name, NULL,
@@ -2981,12 +2982,12 @@ err_exit:
table = NULL;
} else if (dict_index_is_corrupted(index)
- && !table->ibd_file_missing) {
+ && table->is_readable()) {
/* It is possible we force to load a corrupted
clustered index if srv_load_corrupted is set.
Mark the table as corrupted in this case */
- table->corrupted = TRUE;
+ table->corrupted = true;
}
}
@@ -2995,7 +2996,7 @@ func_exit:
ut_ad(!table
|| ignore_err != DICT_ERR_IGNORE_NONE
- || table->ibd_file_missing
+ || !table->is_readable()
|| !table->corrupted);
if (table && table->fts) {
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 7a6f09569a6..230706976dc 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2013, 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/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 537a70c2069..54988b910d8 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2009, 2016, 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
@@ -913,10 +913,15 @@ dict_stats_update_transient_for_index(
index->stat_n_leaf_pages = size;
- /* We don't handle the return value since it will be false
- only when some thread is dropping the table and we don't
- have to empty the statistics of the to be dropped index */
- btr_estimate_number_of_different_key_vals(index);
+ /* Do not continue if table decryption has failed or
+ table is already marked as corrupted. */
+ if (index->is_readable()) {
+ /* We don't handle the return value since it
+ will be false only when some thread is
+ dropping the table and we don't have to empty
+ the statistics of the to be dropped index */
+ btr_estimate_number_of_different_key_vals(index);
+ }
}
}
@@ -967,8 +972,9 @@ dict_stats_update_transient(
continue;
}
- /* Do not continue if table decryption has failed. */
- if (index->table->is_encrypted) {
+ /* Do not continue if table decryption has failed or
+ table is already marked as corrupted. */
+ if (!index->is_readable()) {
break;
}
@@ -2419,6 +2425,41 @@ dict_stats_save_index_stat(
return(ret);
}
+/** Report an error if updating table statistics failed because
+.ibd file is missing, table decryption failed or table is corrupted.
+@param[in,out] table Table
+@param[in] defragment true if statistics is for defragment
+@retval DB_DECRYPTION_FAILED if decryption of the table failed
+@retval DB_TABLESPACE_DELETED if .ibd file is missing
+@retval DB_CORRUPTION if table is marked as corrupted */
+dberr_t
+dict_stats_report_error(dict_table_t* table, bool defragment)
+{
+ dberr_t err;
+
+ FilSpace space(table->space);
+ const char* df = defragment ? " defragment" : "";
+
+ if (!space()) {
+ ib::warn() << "Cannot save" << df << " statistics for table "
+ << table->name
+ << " because the .ibd file is missing. "
+ << TROUBLESHOOTING_MSG;
+ err = DB_TABLESPACE_DELETED;
+ } else {
+ ib::warn() << "Cannot save" << df << " statistics for table "
+ << table->name
+ << " because file " << space()->chain.start->name
+ << (table->corrupted
+ ? " is corrupted."
+ : " cannot be decrypted.");
+ err = table->corrupted ? DB_CORRUPTION : DB_DECRYPTION_FAILED;
+ }
+
+ dict_stats_empty_table(table, defragment);
+ return err;
+}
+
/** Save the table's statistics into the persistent statistics storage.
@param[in] table_orig table whose stats to save
@param[in] only_for_index if this is non-NULL, then stats for indexes
@@ -2438,6 +2479,11 @@ dict_stats_save(
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
+ if (table_orig->is_readable()) {
+ } else {
+ return (dict_stats_report_error(table_orig));
+ }
+
table = dict_stats_snapshot_create(table_orig);
dict_fs2utf8(table->name.m_name, db_utf8, sizeof(db_utf8),
@@ -3160,15 +3206,8 @@ dict_stats_update(
{
ut_ad(!mutex_own(&dict_sys->mutex));
- if (table->ibd_file_missing) {
-
- ib::warn() << "Cannot calculate statistics for table "
- << table->name
- << " because the .ibd file is missing. "
- << TROUBLESHOOTING_MSG;
-
- dict_stats_empty_table(table, true);
- return(DB_TABLESPACE_DELETED);
+ if (!table->is_readable()) {
+ return (dict_stats_report_error(table));
} else if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
/* If we have set a high innodb_force_recovery level, do
not calculate statistics, as a badly corrupted index can
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index b031a77baa8..3216e6ef99e 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -277,8 +277,8 @@ fil_space_read_crypt_data(const page_size_t& page_size, const byte* page)
return NULL;
}
- ulint type = mach_read_from_1(page + offset + MAGIC_SZ + 0);
- ulint iv_length = mach_read_from_1(page + offset + MAGIC_SZ + 1);
+ uint8_t type = mach_read_from_1(page + offset + MAGIC_SZ + 0);
+ uint8_t iv_length = mach_read_from_1(page + offset + MAGIC_SZ + 1);
fil_space_crypt_t* crypt_data;
if (!(type == CRYPT_SCHEME_UNENCRYPTED ||
@@ -444,11 +444,12 @@ Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
@param[in] block buffer block
@return position on log buffer */
UNIV_INTERN
-const byte*
+byte*
fil_parse_write_crypt_data(
- const byte* ptr,
+ byte* ptr,
const byte* end_ptr,
- const buf_block_t* block)
+ const buf_block_t* block,
+ dberr_t* err)
{
/* check that redo log entry is complete */
uint entry_size =
@@ -460,6 +461,8 @@ fil_parse_write_crypt_data(
4 + // size of key_id
1; // fil_encryption_t
+ *err = DB_SUCCESS;
+
if (ptr + entry_size > end_ptr) {
return NULL;
}
@@ -499,11 +502,16 @@ fil_parse_write_crypt_data(
ptr += len;
/* update fil_space memory cache with crypt_data */
- fil_space_t* space = fil_space_acquire_silent(space_id);
-
- if (space) {
+ if (fil_space_t* space = fil_space_acquire_silent(space_id)) {
crypt_data = fil_space_set_crypt_data(space, crypt_data);
fil_space_release(space);
+ /* Check is used key found from encryption plugin */
+ if (crypt_data->should_encrypt()
+ && !crypt_data->is_key_found()) {
+ *err = DB_DECRYPTION_FAILED;
+ }
+ } else {
+ fil_space_destroy_crypt_data(&crypt_data);
}
return ptr;
@@ -529,14 +537,14 @@ fil_encrypt_buf(
const page_size_t& page_size,
byte* dst_frame)
{
- ulint size = page_size.physical();
+ uint size = uint(page_size.physical());
uint key_version = fil_crypt_get_latest_key_version(crypt_data);
ut_a(key_version != ENCRYPTION_KEY_VERSION_INVALID);
ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
ibool page_compressed = (orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
- ulint header_len = FIL_PAGE_DATA;
+ uint header_len = FIL_PAGE_DATA;
if (page_compressed) {
header_len += (FIL_PAGE_COMPRESSED_SIZE + FIL_PAGE_COMPRESSION_METHOD_SIZE);
@@ -549,8 +557,8 @@ fil_encrypt_buf(
mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, key_version);
/* Calculate the start offset in a page */
- ulint unencrypted_bytes = header_len + FIL_PAGE_DATA_END;
- ulint srclen = size - unencrypted_bytes;
+ uint unencrypted_bytes = header_len + FIL_PAGE_DATA_END;
+ uint srclen = size - unencrypted_bytes;
const byte* src = src_frame + header_len;
byte* dst = dst_frame + header_len;
uint32 dstlen = 0;
@@ -663,10 +671,12 @@ fil_space_encrypt(
}
bool corrupted = buf_page_is_corrupted(true, tmp_mem, page_size, space);
+ memcpy(tmp_mem+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, src+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8);
bool different = memcmp(src, tmp_mem, page_size.physical());
if (!ok || corrupted || corrupted1 || err != DB_SUCCESS || different) {
- fprintf(stderr, "ok %d corrupted %d corrupted1 %d err %d different %d\n", ok , corrupted, corrupted1, err, different);
+ fprintf(stderr, "ok %d corrupted %d corrupted1 %d err %d different %d\n",
+ ok , corrupted, corrupted1, err, different);
fprintf(stderr, "src_frame\n");
buf_page_print(src_frame, page_size, BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr, "encrypted_frame\n");
@@ -709,8 +719,8 @@ fil_space_decrypt(
ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
- ulint offset = mach_read_from_4(src_frame + FIL_PAGE_OFFSET);
- ulint space = mach_read_from_4(src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ uint offset = mach_read_from_4(src_frame + FIL_PAGE_OFFSET);
+ uint space = mach_read_from_4(src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ib_uint64_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN);
*err = DB_SUCCESS;
@@ -719,31 +729,10 @@ fil_space_decrypt(
return false;
}
- if (crypt_data == NULL) {
- if (!(space == 0 && offset == 0) && key_version != 0) {
- /* FIL_PAGE_FILE_FLUSH_LSN field i.e.
- FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
- should be only defined for the
- first page in a system tablespace
- data file (ibdata*, not *.ibd), if not
- clear it. */
-
- DBUG_LOG("crypt",
- "Page " << page_id_t(space, offset)
- << " carries key_version " << key_version
- << " (should be undefined)");
-
- memset(src_frame
- + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 4);
- }
-
- return false;
- }
-
ut_a(crypt_data != NULL && crypt_data->is_encrypted());
/* read space & lsn */
- ulint header_len = FIL_PAGE_DATA;
+ uint header_len = FIL_PAGE_DATA;
if (page_compressed) {
header_len += (FIL_PAGE_COMPRESSED_SIZE + FIL_PAGE_COMPRESSION_METHOD_SIZE);
@@ -756,7 +745,8 @@ fil_space_decrypt(
const byte* src = src_frame + header_len;
byte* dst = tmp_frame + header_len;
uint32 dstlen = 0;
- ulint srclen = page_size.physical() - (header_len + FIL_PAGE_DATA_END);
+ uint srclen = uint(page_size.physical())
+ - header_len - FIL_PAGE_DATA_END;
if (page_compressed) {
srclen = mach_read_from_2(src_frame + FIL_PAGE_DATA);
@@ -789,9 +779,6 @@ fil_space_decrypt(
memcpy(tmp_frame + page_size.physical() - FIL_PAGE_DATA_END,
src_frame + page_size.physical() - FIL_PAGE_DATA_END,
FIL_PAGE_DATA_END);
-
- // clear key-version & crypt-checksum from dst
- memset(tmp_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
}
srv_stats.pages_decrypted.inc();
@@ -847,12 +834,12 @@ Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC
not needed. */
UNIV_INTERN
-ulint
+uint32_t
fil_crypt_calculate_checksum(
const page_size_t& page_size,
const byte* dst_frame)
{
- ib_uint32_t checksum = 0;
+ uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
@@ -1018,7 +1005,8 @@ fil_crypt_start_encrypting_space(
do
{
mtr_t mtr;
- mtr_start(&mtr);
+ mtr.start();
+ mtr.set_named_space(space);
/* 2 - get page 0 */
dberr_t err = DB_SUCCESS;
@@ -1034,7 +1022,7 @@ fil_crypt_start_encrypting_space(
crypt_data->type = CRYPT_SCHEME_1;
crypt_data->write_page0(space, frame, &mtr);
- mtr_commit(&mtr);
+ mtr.commit();
/* record lsn of update */
lsn_t end_lsn = mtr.commit_lsn();
@@ -1097,7 +1085,7 @@ struct rotate_thread_t {
uint estimated_max_iops; /*!< estimation of max iops */
uint allocated_iops; /*!< allocated iops */
- uint cnt_waited; /*!< #times waited during this slot */
+ ulint cnt_waited; /*!< #times waited during this slot */
uintmax_t sum_waited_us; /*!< wait time during this slot */
fil_crypt_stat_t crypt_stat; // statistics
@@ -1615,7 +1603,7 @@ fil_crypt_get_page_throttle_func(
mtr_t* mtr,
ulint* sleeptime_ms,
const char* file,
- ulint line)
+ unsigned line)
{
fil_space_t* space = state->space;
const page_size_t page_size = page_size_t(space->flags);
@@ -1772,21 +1760,20 @@ fil_crypt_rotate_page(
}
mtr_t mtr;
- mtr_start(&mtr);
- buf_block_t* block = fil_crypt_get_page_throttle(state,
- offset, &mtr,
- &sleeptime_ms);
-
- if (block) {
+ mtr.start();
+ if (buf_block_t* block = fil_crypt_get_page_throttle(state,
+ offset, &mtr,
+ &sleeptime_ms)) {
+ mtr.set_named_space(space);
bool modified = false;
int needs_scrubbing = BTR_SCRUB_SKIP_PAGE;
lsn_t block_lsn = block->page.newest_modification;
- uint kv = block->page.key_version;
+ byte* frame = buf_block_get_frame(block);
+ uint kv = mach_read_from_4(frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
/* check if tablespace is closing after reading page */
- if (space->is_stopping()) {
- byte* frame = buf_block_get_frame(block);
+ if (!space->is_stopping()) {
if (kv == 0 &&
fil_crypt_is_page_uninitialized(frame, page_size)) {
@@ -1796,11 +1783,6 @@ fil_crypt_rotate_page(
kv, key_state->key_version,
key_state->rotate_key_age)) {
- /* page can be "fresh" i.e never written in case
- * kv == 0 or it should have a key version at least
- * as big as the space minimum key version*/
- ut_a(kv == 0 || kv >= crypt_data->min_key_version);
-
modified = true;
/* force rotation by dummy updating page */
@@ -1808,16 +1790,10 @@ fil_crypt_rotate_page(
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
space_id, MLOG_4BYTES, &mtr);
- /* update block */
- block->page.key_version = key_state->key_version;
-
/* statistics */
state->crypt_stat.pages_modified++;
} else {
if (crypt_data->is_encrypted()) {
- ut_a(kv >= crypt_data->min_key_version ||
- (kv == 0 && key_state->key_version == 0));
-
if (kv < state->min_key_version_found) {
state->min_key_version_found = kv;
}
@@ -1829,11 +1805,11 @@ fil_crypt_rotate_page(
BTR_SCRUB_PAGE_ALLOCATION_UNKNOWN);
}
- mtr_commit(&mtr);
+ mtr.commit();
lsn_t end_lsn = mtr.commit_lsn();
if (needs_scrubbing == BTR_SCRUB_PAGE) {
- mtr_start(&mtr);
+ mtr.start();
/*
* refetch page and allocation status
*/
@@ -1845,6 +1821,7 @@ fil_crypt_rotate_page(
&sleeptime_ms);
if (block) {
+ mtr.set_named_space(space);
/* get required table/index and index-locks */
needs_scrubbing = btr_scrub_recheck_page(
@@ -1902,6 +1879,13 @@ fil_crypt_rotate_page(
state->end_lsn = block_lsn;
}
}
+ } else {
+ /* If block read failed mtr memo and log should be empty. */
+ ut_ad(!mtr.has_modifications());
+ ut_ad(!mtr.is_dirty());
+ ut_ad(mtr.get_memo()->size() == 0);
+ ut_ad(mtr.get_log()->size() == 0);
+ mtr.commit();
}
if (sleeptime_ms) {
@@ -1999,6 +1983,7 @@ fil_crypt_flush_space(
page_id_t(space->id, 0), page_size_t(space->flags),
RW_X_LATCH, NULL, BUF_GET,
__FILE__, __LINE__, &mtr, &err)) {
+ mtr.set_named_space(space);
crypt_data->write_page0(space, block->frame, &mtr);
}
@@ -2085,6 +2070,11 @@ fil_crypt_complete_rotate_space(
crypt_data->rotate_state.flushing = false;
mutex_exit(&crypt_data->mutex);
}
+ } else {
+ mutex_enter(&crypt_data->mutex);
+ ut_a(crypt_data->rotate_state.active_threads > 0);
+ crypt_data->rotate_state.active_threads--;
+ mutex_exit(&crypt_data->mutex);
}
}
@@ -2345,7 +2335,7 @@ fil_space_crypt_close_tablespace(
mutex_enter(&crypt_data->mutex);
mutex_exit(&fil_crypt_threads_mutex);
- uint cnt = crypt_data->rotate_state.active_threads;
+ ulint cnt = crypt_data->rotate_state.active_threads;
bool flushing = crypt_data->rotate_state.flushing;
while (cnt > 0 || flushing) {
@@ -2527,29 +2517,29 @@ fil_space_verify_crypt_checksum(
return (true);
}
- /* Compressed pages use different checksum method. We first store
- the post encryption checksum on checksum location and after function
- restore the original. */
- if (page_size.is_compressed()) {
- ib_uint32_t old = static_cast<ib_uint32_t>(mach_read_from_4(
- page + FIL_PAGE_SPACE_OR_CHKSUM));
-
- mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, checksum);
-
- bool valid = page_zip_verify_checksum(page,
- page_size.physical());
+ uint32 cchecksum1, cchecksum2;
- mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, old);
-
- return (valid);
+ /* Calculate checksums */
+ if (page_size.is_compressed()) {
+ cchecksum1 = page_zip_calc_checksum(
+ page, page_size.physical(),
+ SRV_CHECKSUM_ALGORITHM_CRC32);
+
+ cchecksum2 = (cchecksum1 == checksum)
+ ? 0
+ : page_zip_calc_checksum(
+ page, page_size.physical(),
+ SRV_CHECKSUM_ALGORITHM_INNODB);
+ } else {
+ cchecksum1 = buf_calc_page_crc32(page);
+ cchecksum2 = (cchecksum1 == checksum)
+ ? 0
+ : buf_calc_page_new_checksum(page);
}
/* If stored checksum matches one of the calculated checksums
page is not corrupted. */
- ib_uint32_t cchecksum1 = buf_calc_page_crc32(page);
- ib_uint32_t cchecksum2 = (ib_uint32_t) buf_calc_page_new_checksum(
- page);
bool encrypted = (checksum == cchecksum1 || checksum == cchecksum2
|| checksum == BUF_NO_CHECKSUM_MAGIC);
@@ -2577,17 +2567,24 @@ fil_space_verify_crypt_checksum(
when FIL_PAGE_FILE_FLUSH_LSN does not contain 0.
*/
- ulint checksum1 = mach_read_from_4(
- page + FIL_PAGE_SPACE_OR_CHKSUM);
+ uint32_t checksum1 = mach_read_from_4(page + FIL_PAGE_SPACE_OR_CHKSUM);
+ uint32_t checksum2;
- ulint checksum2 = mach_read_from_4(
- page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
+ bool valid;
- bool valid = buf_page_is_checksum_valid_crc32(
- page, checksum1, checksum2, false
- /* FIXME: also try the original crc32 that was
- buggy on big-endian architectures? */)
- || buf_page_is_checksum_valid_innodb(page, checksum1, checksum2);
+ if (page_size.is_compressed()) {
+ valid = checksum1 == cchecksum1;
+ checksum2 = checksum1;
+ } else {
+ checksum2 = mach_read_from_4(
+ page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
+ valid = buf_page_is_checksum_valid_crc32(
+ page, checksum1, checksum2, false
+ /* FIXME: also try the original crc32 that was
+ buggy on big-endian architectures? */)
+ || buf_page_is_checksum_valid_innodb(
+ page, checksum1, checksum2);
+ }
if (encrypted && valid) {
/* If page is encrypted and traditional checksums match,
@@ -2597,7 +2594,7 @@ fil_space_verify_crypt_checksum(
fprintf(log_file ? log_file : stderr,
"Page " ULINTPF ":" ULINTPF " may be corrupted."
" Post encryption checksum %u"
- " stored [" ULINTPF ":" ULINTPF "] key_version %u\n",
+ " stored [%u:%u] key_version %u\n",
space, offset, checksum, checksum1, checksum2,
key_version);
#else /* UNIV_INNOCHECKSUM */
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 7a169c0bf2c..ce417b1e511 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -306,7 +306,9 @@ fil_write(
}
/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
+Returns the table space by a given id, NULL if not found.
+It is unsafe to dereference the returned pointer. It is fine to check
+for NULL. */
fil_space_t*
fil_space_get_by_id(
/*================*/
@@ -2276,7 +2278,7 @@ for concurrency control.
@param[in] silent whether to silently ignore missing tablespaces
@return the tablespace
@retval NULL if missing or being deleted or truncated */
-inline
+UNIV_INTERN
fil_space_t*
fil_space_acquire_low(ulint id, bool silent)
{
@@ -2302,30 +2304,6 @@ fil_space_acquire_low(ulint id, bool silent)
return(space);
}
-/** Acquire a tablespace when it could be dropped concurrently.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@return the tablespace
-@retval NULL if missing or being deleted or truncated */
-fil_space_t*
-fil_space_acquire(ulint id)
-{
- return(fil_space_acquire_low(id, false));
-}
-
-/** Acquire a tablespace that may not exist.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@return the tablespace
-@retval NULL if missing or being deleted */
-fil_space_t*
-fil_space_acquire_silent(ulint id)
-{
- return(fil_space_acquire_low(id, true));
-}
-
/** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */
void
@@ -3102,7 +3080,7 @@ checked @return whether the table is accessible */
bool
fil_table_accessible(const dict_table_t* table)
{
- if (UNIV_UNLIKELY(table->ibd_file_missing || table->corrupted)) {
+ if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) {
return(false);
}
@@ -3816,7 +3794,7 @@ fil_ibd_create(
ulint flags,
ulint size,
fil_encryption_t mode,
- ulint key_id)
+ uint32_t key_id)
{
os_file_t file;
dberr_t err;
@@ -3880,17 +3858,21 @@ fil_ibd_create(
success= false;
#ifdef HAVE_POSIX_FALLOCATE
- /*
- Extend the file using posix_fallocate(). This is required by
- FusionIO HW/Firmware but should also be the prefered way to extend
- a file.
- */
- int ret = posix_fallocate(file, 0, size * UNIV_PAGE_SIZE);
-
- if (ret == 0) {
+ /*
+ Extend the file using posix_fallocate(). This is required by
+ FusionIO HW/Firmware but should also be the prefered way to extend
+ a file.
+ */
+ int ret;
+ do {
+ ret = posix_fallocate(file, 0, size * UNIV_PAGE_SIZE);
+ } while (ret == EINTR
+ && srv_shutdown_state == SRV_SHUTDOWN_NONE);
+
+ if (ret == 0) {
success = true;
} else if (ret != EINVAL) {
- ib::error() <<
+ ib::error() <<
"posix_fallocate(): Failed to preallocate"
" data for file " << path
<< ", desired size "
@@ -4791,7 +4773,7 @@ fsp_flags_try_adjust(ulint space_id, ulint flags)
ut_ad(fsp_flags_is_valid(flags));
mtr_t mtr;
- mtr_start(&mtr);
+ mtr.start();
if (buf_block_t* b = buf_page_get(
page_id_t(space_id, 0), page_size_t(flags),
RW_X_LATCH, &mtr)) {
@@ -4805,12 +4787,13 @@ fsp_flags_try_adjust(ulint space_id, ulint flags)
<< " to " << ib::hex(flags);
}
if (f != flags) {
+ mtr.set_named_space(space_id);
mlog_write_ulint(FSP_HEADER_OFFSET
+ FSP_SPACE_FLAGS + b->frame,
flags, MLOG_4BYTES, &mtr);
}
}
- mtr_commit(&mtr);
+ mtr.commit();
}
/** Determine if a matching tablespace exists in the InnoDB tablespace
@@ -4921,7 +4904,7 @@ fil_space_for_table_exists_in_mem(
" deleted or moved .ibd files?";
}
error_exit:
- ib::warn() << TROUBLESHOOT_DATADICT_MSG;
+ ib::info() << TROUBLESHOOT_DATADICT_MSG;
valid = false;
goto func_exit;
}
@@ -5509,6 +5492,8 @@ fil_aio_wait(
mutex_enter(&fil_system->mutex);
fil_node_complete_io(node, type);
+ const fil_type_t purpose = node->space->purpose;
+ const ulint space_id = node->space->id;
mutex_exit(&fil_system->mutex);
@@ -5520,7 +5505,11 @@ fil_aio_wait(
deadlocks in the i/o system. We keep tablespace 0 data files always
open, and use a special i/o thread to serve insert buffer requests. */
- switch (node->space->purpose) {
+ switch (purpose) {
+ case FIL_TYPE_LOG:
+ srv_set_io_thread_op_info(segment, "complete io for log");
+ log_io_complete(static_cast<log_group_t*>(message));
+ return;
case FIL_TYPE_TABLESPACE:
case FIL_TYPE_TEMPORARY:
case FIL_TYPE_IMPORT:
@@ -5528,13 +5517,32 @@ fil_aio_wait(
/* async single page writes from the dblwr buffer don't have
access to the page */
- if (message != NULL) {
- buf_page_io_complete(static_cast<buf_page_t*>(message));
+ buf_page_t* bpage = static_cast<buf_page_t*>(message);
+ if (!bpage) {
+ return;
+ }
+
+ ulint offset = bpage->id.page_no();
+ dberr_t err = buf_page_io_complete(bpage);
+ if (err == DB_SUCCESS) {
+ return;
+ }
+
+ ut_ad(type.is_read());
+ if (recv_recovery_is_on() && !srv_force_recovery) {
+ recv_sys->found_corrupt_fs = true;
+ }
+
+ if (fil_space_t* space = fil_space_acquire_for_io(space_id)) {
+ if (space == node->space) {
+ ib::error() << "Failed to read file '"
+ << node->name
+ << "' at offset " << offset
+ << ": " << ut_strerr(err);
+ }
+
+ fil_space_release_for_io(space);
}
- return;
- case FIL_TYPE_LOG:
- srv_set_io_thread_op_info(segment, "complete io for log");
- log_io_complete(static_cast<log_group_t*>(message));
return;
}
@@ -6920,8 +6928,8 @@ fil_space_keyrotate_next(
or dropped or truncated. Note that rotation_list contains only
space->purpose == FIL_TYPE_TABLESPACE. */
while (space != NULL
- && (UT_LIST_GET_LEN(space->chain) == 0
- || space->is_stopping())) {
+ && (UT_LIST_GET_LEN(space->chain) == 0
+ || space->is_stopping())) {
old = space;
space = UT_LIST_GET_NEXT(rotation_list, space);
@@ -6952,9 +6960,10 @@ fil_space_get_block_size(const fil_space_t* space, unsigned offset)
node = UT_LIST_GET_NEXT(chain, node)) {
block_size = node->block_size;
if (node->size > offset) {
+ ut_ad(node->size <= 0xFFFFFFFFU);
break;
}
- offset -= node->size;
+ offset -= static_cast<unsigned>(node->size);
}
/* Currently supporting block size up to 4K,
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 45d00e9a2ff..c2ccd0fab36 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -133,6 +133,12 @@ void reset_thd(MYSQL_THD thd);
TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
const char *tb, size_t tblen);
+/** Check if user has used xtradb extended system variable that
+is not currently supported by innodb or marked as deprecated. */
+static
+void
+innodb_check_deprecated(void);
+
#ifdef MYSQL_DYNAMIC_PLUGIN
#define tc_size 400
#define tdc_size 400
@@ -1835,6 +1841,7 @@ innobase_srv_conc_enter_innodb(
#endif /* WITH_WSREP */
trx_t* trx = prebuilt->trx;
+
if (srv_thread_concurrency) {
if (trx->n_tickets_to_enter_innodb > 0) {
@@ -3443,11 +3450,35 @@ innobase_invalidate_query_cache(
above the InnoDB trx_sys_t->lock. The caller of this function must
not have latches of a lower rank. */
- /* Argument TRUE below means we are using transactions */
- mysql_query_cache_invalidate4(trx->mysql_thd,
- full_name,
- (uint32) full_name_len,
- TRUE);
+#ifdef HAVE_QUERY_CACHE
+ char qcache_key_name[2 * (NAME_LEN + 1)];
+ char db_name[NAME_CHAR_LEN * MY_CS_MBMAXLEN + 1];
+ const char *key_ptr;
+ size_t tabname_len;
+ size_t dbname_len;
+
+ // Extract the database name.
+ key_ptr= strchr(full_name, '/');
+ DBUG_ASSERT(key_ptr != NULL); // Database name should be present
+ memcpy(db_name, full_name, (dbname_len= (key_ptr - full_name)));
+ db_name[dbname_len]= '\0';
+
+ /* Construct the key("db-name\0table$name\0") for the query cache using
+ the path name("db@002dname\0table@0024name\0") of the table in its
+ canonical form. */
+ dbname_len = filename_to_tablename(db_name, qcache_key_name,
+ sizeof(qcache_key_name));
+ tabname_len = filename_to_tablename(++key_ptr,
+ (qcache_key_name + dbname_len + 1),
+ sizeof(qcache_key_name) -
+ dbname_len - 1);
+
+ /* Argument TRUE below means we are using transactions */
+ mysql_query_cache_invalidate4(trx->mysql_thd,
+ qcache_key_name,
+ (dbname_len + tabname_len + 2),
+ TRUE);
+#endif
}
/** Quote a standard SQL identifier like index or column name.
@@ -4023,6 +4054,8 @@ innobase_init(
goto error;
}
+ innodb_check_deprecated();
+
/* First calculate the default path for innodb_data_home_dir etc.,
in case the user has not given any value.
@@ -6603,6 +6636,7 @@ ha_innobase::open(
/* Mark this table as corrupted, so the drop table
or force recovery can still use it, but not others. */
+ ib_table->file_unreadable = true;
ib_table->corrupted = true;
dict_table_close(ib_table, FALSE, FALSE);
ib_table = NULL;
@@ -6631,7 +6665,7 @@ ha_innobase::open(
ib_table->thd = (void*)thd;
/* No point to init any statistics if tablespace is still encrypted. */
- if (!ib_table->is_encrypted) {
+ if (ib_table->is_readable()) {
dict_stats_init(ib_table);
} else {
ib_table->stat_initialized = 1;
@@ -6639,7 +6673,9 @@ ha_innobase::open(
MONITOR_INC(MONITOR_TABLE_OPEN);
- bool no_tablespace;
+ bool no_tablespace = false;
+ bool encrypted = false;
+ FilSpace space;
if (dict_table_is_discarded(ib_table)) {
@@ -6654,21 +6690,28 @@ ha_innobase::open(
no_tablespace = false;
- } else if (ib_table->ibd_file_missing) {
+ } else if (!ib_table->is_readable()) {
+ space = fil_space_acquire_silent(ib_table->space);
- ib_senderrf(
- thd, IB_LOG_LEVEL_WARN,
- ER_TABLESPACE_MISSING, norm_name);
-
- /* This means we have no idea what happened to the tablespace
- file, best to play it safe. */
-
- no_tablespace = true;
- } else if (ib_table->is_encrypted) {
- /* This means that tablespace was found but we could not
- decrypt encrypted page. */
- no_tablespace = true;
- ib_table->ibd_file_missing = true;
+ if (space()) {
+ if (space()->crypt_data && space()->crypt_data->is_encrypted()) {
+ /* This means that tablespace was found but we could not
+ decrypt encrypted page. */
+ no_tablespace = true;
+ encrypted = true;
+ } else {
+ no_tablespace = true;
+ }
+ } else {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN,
+ ER_TABLESPACE_MISSING, norm_name);
+
+ /* This means we have no idea what happened to the tablespace
+ file, best to play it safe. */
+
+ no_tablespace = true;
+ }
} else {
no_tablespace = false;
}
@@ -6681,34 +6724,35 @@ ha_innobase::open(
/* If table has no talespace but it has crypt data, check
is tablespace made unaccessible because encryption service
or used key_id is not available. */
- if (ib_table) {
+ if (encrypted) {
bool warning_pushed = false;
- fil_space_crypt_t* crypt_data = ib_table->crypt_data;
-
- if (crypt_data && crypt_data->should_encrypt()) {
- if (!encryption_key_id_exists(crypt_data->key_id)) {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- HA_ERR_DECRYPTION_FAILED,
- "Table %s is encrypted but encryption service or"
- " used key_id %u is not available. "
- " Can't continue reading table.",
- ib_table->name, crypt_data->key_id);
- ret_err = HA_ERR_DECRYPTION_FAILED;
- warning_pushed = true;
- }
+ if (!encryption_key_id_exists(space()->crypt_data->key_id)) {
+ push_warning_printf(
+ thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_DECRYPTION_FAILED,
+ "Table %s in file %s is encrypted but encryption service or"
+ " used key_id %u is not available. "
+ " Can't continue reading table.",
+ table_share->table_name.str,
+ space()->chain.start->name,
+ space()->crypt_data->key_id);
+ ret_err = HA_ERR_DECRYPTION_FAILED;
+ warning_pushed = true;
}
/* If table is marked as encrypted then we push
warning if it has not been already done as used
key_id might be found but it is incorrect. */
- if (ib_table->is_encrypted && !warning_pushed) {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ if (!warning_pushed) {
+ push_warning_printf(
+ thd, Sql_condition::WARN_LEVEL_WARN,
HA_ERR_DECRYPTION_FAILED,
- "Table %s is encrypted but encryption service or"
+ "Table %s in file %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
- ib_table->name);
+ table_share->table_name.str,
+ space()->chain.start->name);
ret_err = HA_ERR_DECRYPTION_FAILED;
}
}
@@ -6867,7 +6911,7 @@ ha_innobase::open(
if (m_prebuilt->table == NULL
|| dict_table_is_temporary(m_prebuilt->table)
|| m_prebuilt->table->persistent_autoinc
- || m_prebuilt->table->ibd_file_missing) {
+ || !m_prebuilt->table->is_readable()) {
} else if (const Field* ai = table->found_next_number_field) {
initialize_auto_increment(m_prebuilt->table, ai);
}
@@ -10305,7 +10349,6 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
const trx_t* trx = m_prebuilt->trx;
- dberr_t ret;
ut_ad(trx == thd_to_trx(m_user_thd));
@@ -10317,9 +10360,20 @@ ha_innobase::general_fetch(
DB_FORCED_ABORT, 0, m_user_thd));
}
+ if (m_prebuilt->table->is_readable()) {
+ } else if (m_prebuilt->table->corrupted) {
+ DBUG_RETURN(HA_ERR_CRASHED);
+ } else {
+ FilSpace space(m_prebuilt->table->space, true);
+
+ DBUG_RETURN(space()
+ ? HA_ERR_DECRYPTION_FAILED
+ : HA_ERR_NO_SUCH_TABLE);
+ }
+
innobase_srv_conc_enter_innodb(m_prebuilt);
- ret = row_search_mvcc(
+ dberr_t ret = row_search_mvcc(
buf, PAGE_CUR_UNSUPP, m_prebuilt, match_mode, direction);
innobase_srv_conc_exit_innodb(m_prebuilt);
@@ -10522,6 +10576,8 @@ ha_innobase::rnd_next(
DBUG_ENTER("rnd_next");
+ TrxInInnoDB trx_in_innodb(m_prebuilt->trx);
+
if (m_start_of_scan) {
error = index_first(buf);
@@ -11922,8 +11978,7 @@ err_col:
err = row_create_table_for_mysql(
table, m_trx, false,
(fil_encryption_t)options->encryption,
- (ulint)options->encryption_key_id);
-
+ options->encryption_key_id);
}
DBUG_EXECUTE_IF("ib_crash_during_create_for_encryption",
@@ -13656,7 +13711,7 @@ ha_innobase::discard_or_import_tablespace(
user may want to set the DISCARD flag in order to IMPORT
a new tablespace. */
- if (dict_table->ibd_file_missing) {
+ if (!dict_table->is_readable()) {
ib_senderrf(
m_prebuilt->trx->mysql_thd,
IB_LOG_LEVEL_WARN, ER_TABLESPACE_MISSING,
@@ -13666,7 +13721,7 @@ ha_innobase::discard_or_import_tablespace(
err = row_discard_tablespace_for_mysql(
dict_table->name.m_name, m_prebuilt->trx);
- } else if (!dict_table->ibd_file_missing) {
+ } else if (dict_table->is_readable()) {
/* Commit the transaction in order to
release the table lock. */
trx_commit_for_mysql(m_prebuilt->trx);
@@ -15258,7 +15313,8 @@ ha_innobase::optimize(
This works OK otherwise, but MySQL locks the entire table during
calls to OPTIMIZE, which is undesirable. */
- if (srv_defragment) {
+ /* TODO: Defragment is disabled for now */
+ if (0) {
int err;
err = defragment_table(m_prebuilt->table->name.m_name, NULL, false);
@@ -15335,7 +15391,8 @@ ha_innobase::check(
DBUG_RETURN(HA_ADMIN_CORRUPT);
- } else if (m_prebuilt->table->ibd_file_missing) {
+ } else if (!m_prebuilt->table->is_readable() &&
+ !fil_space_get(m_prebuilt->table->space)) {
ib_senderrf(
thd, IB_LOG_LEVEL_ERROR,
@@ -16652,6 +16709,8 @@ innodb_show_status(
DBUG_RETURN(0);
}
+ srv_wake_purge_thread_if_not_active();
+
trx_t* trx = check_trx_exists(thd);
trx_assert_no_search_latch(trx);
@@ -21851,6 +21910,8 @@ static MYSQL_SYSVAR_BOOL(instrument_semaphores, innodb_instrument_semaphores,
"DEPRECATED. This setting has no effect.",
NULL, innodb_instrument_semaphores_update, FALSE);
+#include "ha_xtradb.h"
+
static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(autoextend_increment),
MYSQL_SYSVAR(buffer_pool_size),
@@ -22063,6 +22124,11 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(instrument_semaphores),
MYSQL_SYSVAR(buf_dump_status_frequency),
MYSQL_SYSVAR(background_thread),
+
+ /* XtraDB compatibility system variables */
+#define HA_XTRADB_SYSVARS
+#include "ha_xtradb.h"
+
NULL
};
diff --git a/storage/innobase/handler/ha_xtradb.h b/storage/innobase/handler/ha_xtradb.h
new file mode 100644
index 00000000000..09628b7ec48
--- /dev/null
+++ b/storage/innobase/handler/ha_xtradb.h
@@ -0,0 +1,1007 @@
+/*****************************************************************************
+
+Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2009, Percona Inc.
+
+Portions of this file contain modifications contributed and copyrighted
+by Percona Inc.. Those modifications are
+gratefully acknowledged and are described briefly in the InnoDB
+documentation. The contributions by Percona Inc. are incorporated with
+their permission, and subject to the conditions contained in the file
+COPYING.Percona.
+
+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
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/** @file ha_xtradb.h */
+
+#ifndef HA_XTRADB_H
+#define HA_XTRADB_H
+
+static
+void
+innodb_print_deprecation(const char* param);
+
+/* XtraDB compatibility system variables. Note that default value and
+minimum value can be different compared to original to detect has user
+really used the parameter or not. */
+
+static my_bool innodb_buffer_pool_populate;
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+static ulong srv_cleaner_max_lru_time;
+static ulong srv_cleaner_max_flush_time;
+static ulong srv_cleaner_flush_chunk_size;
+static ulong srv_cleaner_lru_chunk_size;
+static ulong srv_cleaner_free_list_lwm;
+static my_bool srv_cleaner_eviction_factor;
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+static ulong srv_pass_corrupt_table;
+static ulong srv_empty_free_list_algorithm;
+static ulong innobase_file_io_threads;
+static ulong srv_foreground_preflush;
+static longlong srv_kill_idle_transaction;
+static my_bool srv_fake_changes_locks;
+static my_bool innobase_log_archive;
+static char* innobase_log_arch_dir = NULL;
+static ulong srv_log_arch_expire_sec;
+static ulong innobase_log_block_size;
+static ulong srv_log_checksum_algorithm;
+static ulonglong srv_max_bitmap_file_size;
+static ulonglong srv_max_changed_pages;
+static ulong innobase_mirrored_log_groups;
+#ifdef UNIV_LINUX
+static ulong srv_sched_priority_cleaner;
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+static my_bool srv_cleaner_thread_priority;
+static my_bool srv_io_thread_priority;
+static my_bool srv_master_thread_priority;
+static my_bool srv_purge_thread_priority;
+static ulong srv_sched_priority_io;
+static ulong srv_sched_priority_master;
+static ulong srv_sched_priority_purge;
+#endif /* UNIV_DEBUG || UNIV_PERF_DEBUG */
+#endif /* UNIV_LINUX */
+static ulong srv_cleaner_lsn_age_factor;
+static ulong srv_show_locks_held;
+static ulong srv_show_verbose_locks;
+static my_bool srv_track_changed_pages;
+static my_bool innodb_track_redo_log_now;
+static my_bool srv_use_global_flush_log_at_trx_commit;
+static my_bool srv_use_stacktrace;
+
+
+static const char innodb_deprecated_msg[]= "Using %s is deprecated and the"
+ " parameter may be removed in future releases."
+ " Ignoning the parameter.";
+
+
+#ifdef BTR_CUR_HASH_ADAPT
+/* it is just alias for innodb_adaptive_hash_index_parts */
+/** Number of distinct partitions of AHI.
+Each partition is protected by its own latch and so we have parts number
+of latches protecting complete search system. */
+static MYSQL_SYSVAR_ULONG(adaptive_hash_index_partitions, btr_ahi_parts,
+ PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
+ "It is an alias for innodb_adaptive_hash_index_parts; "
+ "only exists to allow easier upgrade from earlier XtraDB versions.",
+ NULL, NULL, 8, 1, 512, 0);
+#endif /* BTR_CUR_HASH_ADAPT */
+
+static MYSQL_SYSVAR_BOOL(buffer_pool_populate, innodb_buffer_pool_populate,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, FALSE);
+
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+static
+void
+set_cleaner_max_lru_time(THD*thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_max_lru_time");
+}
+/* Original default 1000 */
+static MYSQL_SYSVAR_ULONG(cleaner_max_lru_time, srv_cleaner_max_lru_time,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, set_cleaner_max_lru_time, 0, 0, ~0UL, 0);
+
+static
+void
+set_cleaner_max_flush_time(THD*thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_max_flush_time");
+}
+/* Original default 1000 */
+static MYSQL_SYSVAR_ULONG(cleaner_max_flush_time, srv_cleaner_max_flush_time,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_cleaner_max_flush_time, 0, 0, ~0UL, 0);
+
+static
+void
+set_cleaner_flush_chunk_size(THD*thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_flush_chunk_size");
+}
+/* Original default 100 */
+static MYSQL_SYSVAR_ULONG(cleaner_flush_chunk_size,
+ srv_cleaner_flush_chunk_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_cleaner_flush_chunk_size, 0, 0, ~0UL, 0);
+
+static
+void
+set_cleaner_lru_chunk_size(THD*thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_lru_chunk_size");
+}
+/* Original default 100 */
+static MYSQL_SYSVAR_ULONG(cleaner_lru_chunk_size,
+ srv_cleaner_lru_chunk_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_cleaner_lru_chunk_size, 0, 0, ~0UL, 0);
+
+static
+void
+set_cleaner_free_list_lwm(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_free_list_lwm");
+}
+/* Original default 10 */
+static MYSQL_SYSVAR_ULONG(cleaner_free_list_lwm, srv_cleaner_free_list_lwm,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_cleaner_free_list_lwm, 0, 0, 100, 0);
+
+static
+void
+set_cleaner_eviction_factor(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_eviction_factor");
+}
+static MYSQL_SYSVAR_BOOL(cleaner_eviction_factor, srv_cleaner_eviction_factor,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_cleaner_eviction_factor, FALSE);
+
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+
+/* Added new default DEPRECATED */
+/** Possible values for system variable "innodb_cleaner_lsn_age_factor". */
+static const char* innodb_cleaner_lsn_age_factor_names[] = {
+ "LEGACY",
+ "HIGH_CHECKPOINT",
+ "DEPRECATED",
+ NullS
+};
+
+/** Enumeration for innodb_cleaner_lsn_age_factor. */
+static TYPELIB innodb_cleaner_lsn_age_factor_typelib = {
+ array_elements(innodb_cleaner_lsn_age_factor_names) - 1,
+ "innodb_cleaner_lsn_age_factor_typelib",
+ innodb_cleaner_lsn_age_factor_names,
+ NULL
+};
+
+/** Alternatives for srv_cleaner_lsn_age_factor, set through
+innodb_cleaner_lsn_age_factor variable */
+enum srv_cleaner_lsn_age_factor_t {
+ SRV_CLEANER_LSN_AGE_FACTOR_LEGACY, /*!< Original Oracle MySQL 5.6
+ formula */
+ SRV_CLEANER_LSN_AGE_FACTOR_HIGH_CHECKPOINT,
+ /*!< Percona Server 5.6 formula
+ that returns lower values than
+ legacy option for low
+ checkpoint ages, and higher
+ values for high ages. This has
+ the effect of stabilizing the
+ checkpoint age higher. */
+ SRV_CLEANER_LSN_AGE_FACTOR_DEPRECATED /*!< Deprecated, do not use */
+};
+
+/** Alternatives for srv_foreground_preflush, set through
+innodb_foreground_preflush variable */
+enum srv_foreground_preflush_t {
+ SRV_FOREGROUND_PREFLUSH_SYNC_PREFLUSH, /*!< Original Oracle MySQL 5.6
+ behavior of performing a sync
+ flush list flush */
+ SRV_FOREGROUND_PREFLUSH_EXP_BACKOFF, /*!< Exponential backoff wait
+ for the page cleaner to flush
+ for us */
+ SRV_FOREGROUND_PREFLUSH_DEPRECATED /*!< Deprecated, do not use */
+};
+
+/** Alternatives for srv_empty_free_list_algorithm, set through
+innodb_empty_free_list_algorithm variable */
+enum srv_empty_free_list_t {
+ SRV_EMPTY_FREE_LIST_LEGACY, /*!< Original Oracle MySQL 5.6
+ algorithm */
+ SRV_EMPTY_FREE_LIST_BACKOFF, /*!< Percona Server 5.6 algorithm that
+ loops in a progressive backoff until a
+ free page is produced by the cleaner
+ thread */
+ SRV_EMPTY_FREE_LIST_DEPRECATED /*!< Deprecated, do not use */
+};
+
+#define SRV_CHECKSUM_ALGORITHM_DEPRECATED 6
+
+static
+void
+set_cleaner_lsn_age_factor(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_cleaner_lsn_age_factor");
+}
+static MYSQL_SYSVAR_ENUM(cleaner_lsn_age_factor,
+ srv_cleaner_lsn_age_factor,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_cleaner_lsn_age_factor, SRV_CLEANER_LSN_AGE_FACTOR_DEPRECATED,
+ &innodb_cleaner_lsn_age_factor_typelib);
+
+/* Added new default drepcated, 3 */
+const char *corrupt_table_action_names[]=
+{
+ "assert", /* 0 */
+ "warn", /* 1 */
+ "salvage", /* 2 */
+ "deprecated", /* 3 */
+ NullS
+};
+
+TYPELIB corrupt_table_action_typelib=
+{
+ array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib",
+ corrupt_table_action_names, NULL
+};
+
+static
+void
+set_corrupt_table_action(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_corrupt_table_action");
+}
+static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_corrupt_table_action, 3, &corrupt_table_action_typelib);
+
+/* Added new default DEPRECATED */
+/** Possible values for system variable "innodb_empty_free_list_algorithm". */
+static const char* innodb_empty_free_list_algorithm_names[] = {
+ "LEGACY",
+ "BACKOFF",
+ "DEPRECATED",
+ NullS
+};
+
+/** Enumeration for innodb_empty_free_list_algorithm. */
+static TYPELIB innodb_empty_free_list_algorithm_typelib = {
+ array_elements(innodb_empty_free_list_algorithm_names) - 1,
+ "innodb_empty_free_list_algorithm_typelib",
+ innodb_empty_free_list_algorithm_names,
+ NULL
+};
+
+static
+void
+set_empty_free_list_algorithm(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_empty_free_list_algorithm");
+}
+static MYSQL_SYSVAR_ENUM(empty_free_list_algorithm,
+ srv_empty_free_list_algorithm,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_empty_free_list_algorithm, SRV_EMPTY_FREE_LIST_DEPRECATED,
+ &innodb_empty_free_list_algorithm_typelib);
+
+static
+void
+set_fake_changes(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_fake_changes");
+}
+static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_fake_changes, FALSE);
+
+/* Original default, min 4. */
+static MYSQL_SYSVAR_ULONG(file_io_threads, innobase_file_io_threads,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, 0, 0, 64, 0);
+
+/** Possible values for system variable "innodb_foreground_preflush". */
+static const char* innodb_foreground_preflush_names[] = {
+ "SYNC_PREFLUSH",
+ "EXPONENTIAL_BACKOFF",
+ "DEPRECATED",
+ NullS
+};
+
+/* Enumeration for innodb_foreground_preflush. */
+static TYPELIB innodb_foreground_preflush_typelib = {
+ array_elements(innodb_foreground_preflush_names) - 1,
+ "innodb_foreground_preflush_typelib",
+ innodb_foreground_preflush_names,
+ NULL
+};
+
+static
+void
+set_foreground_preflush(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_foreground_preflush");
+}
+static MYSQL_SYSVAR_ENUM(foreground_preflush, srv_foreground_preflush,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_foreground_preflush, SRV_FOREGROUND_PREFLUSH_DEPRECATED,
+ &innodb_foreground_preflush_typelib);
+
+#ifdef EXTENDED_FOR_KILLIDLE
+#define kill_idle_help_text "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB."
+#else
+#define kill_idle_help_text "No effect for this build."
+#endif
+static
+void
+set_kill_idle_transaction(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_kill_idle_transaction");
+}
+static MYSQL_SYSVAR_LONGLONG(kill_idle_transaction, srv_kill_idle_transaction,
+ PLUGIN_VAR_RQCMDARG, kill_idle_help_text,
+ NULL, &set_kill_idle_transaction, 0, 0, LONG_MAX, 0);
+
+static
+void
+set_locking_fake_changes(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_locking_fake_changes");
+}
+/* Original default: TRUE */
+static MYSQL_SYSVAR_BOOL(locking_fake_changes, srv_fake_changes_locks,
+ PLUGIN_VAR_NOCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_locking_fake_changes, FALSE);
+
+static MYSQL_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, NULL);
+
+static
+void
+set_log_archive(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_log_archive");
+}
+static MYSQL_SYSVAR_BOOL(log_archive, innobase_log_archive,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_log_archive, FALSE);
+
+static
+void
+set_log_arch_expire_sec(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_log_arch_expire_sec");
+}
+static MYSQL_SYSVAR_ULONG(log_arch_expire_sec,
+ srv_log_arch_expire_sec, PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_log_arch_expire_sec, 0, 0, ~0UL, 0);
+
+/* Original default, min 512 */
+static MYSQL_SYSVAR_ULONG(log_block_size, innobase_log_block_size,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, 0, 0,
+ (1 << UNIV_PAGE_SIZE_SHIFT_MAX), 0);
+
+/* Added new default deprecated */
+/** Possible values for system variables "innodb_checksum_algorithm" and
+"innodb_log_checksum_algorithm". */
+static const char* innodb_checksum_algorithm_names2[] = {
+ "CRC32",
+ "STRICT_CRC32",
+ "INNODB",
+ "STRICT_INNODB",
+ "NONE",
+ "STRICT_NONE",
+ "DEPRECATED",
+ NullS
+};
+
+/** Used to define an enumerate type of the system variables
+innodb_checksum_algorithm and innodb_log_checksum_algorithm. */
+static TYPELIB innodb_checksum_algorithm_typelib2 = {
+ array_elements(innodb_checksum_algorithm_names2) - 1,
+ "innodb_checksum_algorithm_typelib2",
+ innodb_checksum_algorithm_names2,
+ NULL
+};
+static
+void
+set_log_checksum_algorithm(THD* thd, st_mysql_sys_var*, void*, const void* save)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_log_checksum_algorithm");
+ log_mutex_enter();
+ srv_log_checksum_algorithm = *static_cast<const ulong*>(save);
+ if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_NONE) {
+ ib::info() << "Setting innodb_log_checksums = false";
+ innodb_log_checksums = false;
+ log_checksum_algorithm_ptr = log_block_calc_checksum_none;
+ } else {
+ ib::info() << "Setting innodb_log_checksums = true";
+ innodb_log_checksums = true;
+ log_checksum_algorithm_ptr = log_block_calc_checksum_crc32;
+ }
+ log_mutex_exit();
+}
+static MYSQL_SYSVAR_ENUM(log_checksum_algorithm, srv_log_checksum_algorithm,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and translated to innodb_log_checksums (NONE to OFF, "
+ "everything else to ON); only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_log_checksum_algorithm, SRV_CHECKSUM_ALGORITHM_DEPRECATED,
+ &innodb_checksum_algorithm_typelib2);
+
+static
+void
+set_max_bitmap_file_size(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_max_bitmap_file_size");
+}
+/* Original default 100M, min 4K */
+static MYSQL_SYSVAR_ULONGLONG(max_bitmap_file_size, srv_max_bitmap_file_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_max_bitmap_file_size, 0, 0, ULONGLONG_MAX, 0);
+
+static
+void
+set_max_changed_pages(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_max_changed_pages");
+}
+/* Original default 1000000 */
+static MYSQL_SYSVAR_ULONGLONG(max_changed_pages, srv_max_changed_pages,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_max_changed_pages, 0, 0, ~0ULL, 0);
+
+/* Note that the default and minimum values are set to 0 to
+detect if the option is passed and print deprecation message */
+static MYSQL_SYSVAR_ULONG(mirrored_log_groups, innobase_mirrored_log_groups,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, 0, 0, 10, 0);
+
+#ifdef UNIV_LINUX
+
+static
+void
+set_sched_priority_cleaner(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_sched_priority_cleaner");
+}
+/* Original default 19 */
+static MYSQL_SYSVAR_ULONG(sched_priority_cleaner, srv_sched_priority_cleaner,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_sched_priority_cleaner, 0, 0, 39, 0);
+
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+static
+void
+set_priority_cleaner(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_priority_cleaner");
+}
+static MYSQL_SYSVAR_BOOL(priority_cleaner, srv_cleaner_thread_priority,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_priority_cleaner, FALSE);
+
+static
+void
+set_priority_io(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_priority_io");
+}
+static MYSQL_SYSVAR_BOOL(priority_io, srv_io_thread_priority,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_priority_io, FALSE);
+
+static
+void
+set_priority_master(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_priority_master");
+}
+static MYSQL_SYSVAR_BOOL(priority_master, srv_master_thread_priority,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_priority_master, FALSE);
+
+static
+void
+set_priority_purge(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_priority_purge");
+}
+static MYSQL_SYSVAR_BOOL(priority_purge, srv_purge_thread_priority,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_priority_purge, FALSE);
+
+static
+void
+set_sched_priority_io(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_sched_priority_io");
+}
+/* Original default 19 */
+static MYSQL_SYSVAR_ULONG(sched_priority_io, srv_sched_priority_io,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_sched_priority_io, 0, 0, 39, 0);
+
+static
+void
+set_sched_priority_master(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_sched_priority_master");
+}
+/* Original default 19 */
+static MYSQL_SYSVAR_ULONG(sched_priority_master, srv_sched_priority_master,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_sched_priority_master, 0, 0, 39, 0);
+
+static
+void
+set_sched_priority_purge(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_sched_priority_purge");
+}
+/* Original default 19 */
+static MYSQL_SYSVAR_ULONG(sched_priority_purge, srv_sched_priority_purge,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_sched_priority_purge, 0, 0, 39, 0);
+#endif /* UNIV_DEBUG || UNIV_PERF_DEBUG */
+#endif /* UNIV_LINUX */
+
+static
+void
+set_show_locks_held(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_show_locks_held");
+}
+/* TODO: Implement */
+static MYSQL_SYSVAR_ULONG(show_locks_held, srv_show_locks_held,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_show_locks_held, 0, 0, 1000, 0);
+
+static
+void
+set_show_verbose_locks(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_show_verbose_locks");
+}
+/* TODO: Implement */
+static MYSQL_SYSVAR_ULONG(show_verbose_locks, srv_show_verbose_locks,
+ PLUGIN_VAR_RQCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_show_verbose_locks, 0, 0, 1, 0);
+
+static MYSQL_SYSVAR_BOOL(track_changed_pages, srv_track_changed_pages,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, FALSE);
+
+static
+void
+set_track_redo_log_now(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_track_redo_log_now");
+}
+static MYSQL_SYSVAR_BOOL(track_redo_log_now,
+ innodb_track_redo_log_now,
+ PLUGIN_VAR_OPCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_track_redo_log_now, FALSE);
+
+static
+void
+set_use_global_flush_log_at_trx_commit(THD* thd, st_mysql_sys_var*, void*, const void*)
+{
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ innodb_deprecated_msg,
+ "innodb_use_global_flush_log_at_trx_commit");
+}
+static MYSQL_SYSVAR_BOOL(use_global_flush_log_at_trx_commit, srv_use_global_flush_log_at_trx_commit,
+ PLUGIN_VAR_NOCMDARG,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, &set_use_global_flush_log_at_trx_commit, FALSE);
+
+static MYSQL_SYSVAR_BOOL(use_stacktrace, srv_use_stacktrace,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Deprecated and ignored; only exists to allow easier upgrade from "
+ "earlier XtraDB versions.",
+ NULL, NULL, FALSE);
+
+/** Print deprecation message for a given system variable.
+@param[in] param System parameter name */
+static
+void
+innodb_print_deprecation(const char* param)
+{
+ ib::warn() << "Using " << param << " is deprecated and the"
+ " parameter may be removed in future releases."
+ " Ignoning the parameter.";
+}
+
+/** Check if user has used xtradb extended system variable that
+is not currently supported by innodb or marked as deprecated. */
+static
+void
+innodb_check_deprecated(void)
+{
+ if (innodb_buffer_pool_populate) {
+ innodb_print_deprecation("innodb-buffer-pool-populate");
+ }
+
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+ if (srv_cleaner_max_lru_time) {
+ innodb_print_deprecation("innodb-cleaner-max-lru-time");
+ }
+
+ if (srv_cleaner_max_flush_time) {
+ innodb_print_deprecation("innodb-cleaner-max-flush-time");
+ }
+
+ if (srv_cleaner_flush_chunk_size) {
+ innodb_print_deprecation("innodb-cleaner-flush-chunk-size");
+ }
+
+ if (srv_cleaner_lru_chunk_size) {
+ innodb_print_deprecation("innodb-cleaner-lru_chunk_size");
+ }
+ if (srv_cleaner_free_list_lwm) {
+ innodb_print_deprecation("innodb-cleaner-free-list-lwm");
+ }
+
+ if (srv_cleaner_eviction_factor) {
+ innodb_print_deprecation("innodb-cleaner-eviction-factor");
+ }
+
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+
+ if (srv_cleaner_lsn_age_factor != SRV_CLEANER_LSN_AGE_FACTOR_DEPRECATED) {
+ innodb_print_deprecation("innodb-cleaner-lsn-age-factor");
+ }
+
+ if (srv_pass_corrupt_table != 3) {
+ innodb_print_deprecation("innodb-pass-corrupt-table");
+ }
+
+ if (srv_empty_free_list_algorithm != SRV_EMPTY_FREE_LIST_DEPRECATED) {
+ innodb_print_deprecation("innodb-empty-free-list-algorithm");
+ }
+
+ if (THDVAR((THD*) NULL, fake_changes)) {
+ innodb_print_deprecation("innodb-fake-changes");
+ }
+
+ if (innobase_file_io_threads) {
+ innodb_print_deprecation("innodb-file-io-threads");
+ }
+
+ if (srv_foreground_preflush != SRV_FOREGROUND_PREFLUSH_DEPRECATED) {
+ innodb_print_deprecation("innodb-foreground-preflush");
+ }
+
+ if (srv_kill_idle_transaction != 0) {
+ innodb_print_deprecation("innodb-kill-idle-transaction");
+ }
+
+ if (srv_fake_changes_locks) {
+ innodb_print_deprecation("innodb-fake-changes-locks");
+ }
+
+ if (innobase_log_arch_dir) {
+ innodb_print_deprecation("innodb-log-arch-dir");
+ }
+
+ if (innobase_log_archive) {
+ innodb_print_deprecation("innodb-log-archive");
+ }
+
+ if (srv_log_arch_expire_sec) {
+ innodb_print_deprecation("innodb-log-arch-expire-sec");
+ }
+
+ if (innobase_log_block_size) {
+ innodb_print_deprecation("innodb-log-block-size");
+ }
+
+ if (srv_log_checksum_algorithm != SRV_CHECKSUM_ALGORITHM_DEPRECATED) {
+ innodb_print_deprecation("innodb-log-checksum-algorithm");
+ if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_NONE) {
+ ib::info() << "Setting innodb_log_checksums = false";
+ innodb_log_checksums = false;
+ log_checksum_algorithm_ptr = log_block_calc_checksum_none;
+ } else {
+ ib::info() << "Setting innodb_log_checksums = true";
+ innodb_log_checksums = true;
+ log_checksum_algorithm_ptr = log_block_calc_checksum_crc32;
+ }
+ }
+
+ if (srv_max_changed_pages) {
+ innodb_print_deprecation("innodb-max-changed-pages");
+ }
+
+ if (innobase_mirrored_log_groups) {
+ innodb_print_deprecation("innodb-mirrored-log-groups");
+ }
+
+#ifdef UNIV_LINUX
+ if (srv_sched_priority_cleaner) {
+ innodb_print_deprecation("innodb-sched-priority-cleaner");
+ }
+
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+ if (srv_cleaner_thread_priority) {
+ innodb_print_deprecation("innodb-cleaner-thread-priority");
+ }
+
+ if (srv_io_thread_priority) {
+ innodb_print_deprecation("innodb-io-thread-priority");
+ }
+
+ if (srv_master_thread_priority) {
+ innodb_print_deprecation("inodb-master-thread-priority");
+ }
+
+ if (srv_purge_thread_priority) {
+ innodb_print_deprecation("inodb-purge-thread-priority");
+ }
+
+ if (srv_sched_priority_io) {
+ innodb_print_deprecation("innodb-sched-priority-io");
+ }
+
+ if (srv_sched_priority_master) {
+ innodb_print_deprecation("innodb-sched-priority-master");
+ }
+
+ if (srv_sched_priority_purge) {
+ innodb_print_deprecation("innodb-sched-priority-purge");
+ }
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+#endif /* UNIV_LINUX */
+
+ if (srv_track_changed_pages) {
+ innodb_print_deprecation("innodb-track-changed-pages");
+ }
+
+ if (innodb_track_redo_log_now) {
+ innodb_print_deprecation("innodb-track-redo-log-now");
+ }
+
+ if (srv_use_global_flush_log_at_trx_commit) {
+ innodb_print_deprecation("innodb-use-global-flush-log-at-trx-commit");
+ }
+
+ if (srv_use_stacktrace) {
+ innodb_print_deprecation("innodb-use-stacktrace");
+ }
+
+ if (srv_max_bitmap_file_size) {
+ innodb_print_deprecation("innodb-max-bitmap-file-size");
+ }
+
+ if (srv_show_locks_held) {
+ innodb_print_deprecation("innodb-show-locks-held");
+ }
+
+ if (srv_show_verbose_locks) {
+ innodb_print_deprecation("innodb-show-verbose-locks");
+ }
+}
+
+#endif /* HA_XTRADB_H */
+
+#ifdef HA_XTRADB_SYSVARS
+ /* XtraDB compatibility system variables */
+ MYSQL_SYSVAR(adaptive_hash_index_partitions),
+ MYSQL_SYSVAR(buffer_pool_populate),
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+ MYSQL_SYSVAR(cleaner_eviction_factor),
+ MYSQL_SYSVAR(cleaner_flush_chunk_size),
+ MYSQL_SYSVAR(cleaner_free_list_lwm),
+ MYSQL_SYSVAR(cleaner_lru_chunk_size),
+ MYSQL_SYSVAR(cleaner_max_lru_time),
+ MYSQL_SYSVAR(cleaner_max_flush_time),
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+ MYSQL_SYSVAR(cleaner_lsn_age_factor),
+ MYSQL_SYSVAR(corrupt_table_action),
+ MYSQL_SYSVAR(empty_free_list_algorithm),
+ MYSQL_SYSVAR(fake_changes),
+ MYSQL_SYSVAR(file_io_threads),
+ MYSQL_SYSVAR(foreground_preflush),
+ MYSQL_SYSVAR(kill_idle_transaction),
+ MYSQL_SYSVAR(locking_fake_changes),
+ MYSQL_SYSVAR(log_arch_dir),
+ MYSQL_SYSVAR(log_archive),
+ MYSQL_SYSVAR(log_arch_expire_sec),
+ MYSQL_SYSVAR(log_block_size),
+ MYSQL_SYSVAR(log_checksum_algorithm),
+ MYSQL_SYSVAR(max_bitmap_file_size),
+ MYSQL_SYSVAR(max_changed_pages),
+ MYSQL_SYSVAR(mirrored_log_groups),
+#ifdef UNIV_LINUX
+ MYSQL_SYSVAR(sched_priority_cleaner),
+#endif
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+#ifdef UNIV_LINUX
+ MYSQL_SYSVAR(priority_cleaner),
+ MYSQL_SYSVAR(priority_io),
+ MYSQL_SYSVAR(priority_master),
+ MYSQL_SYSVAR(priority_purge),
+ MYSQL_SYSVAR(sched_priority_io),
+ MYSQL_SYSVAR(sched_priority_master),
+ MYSQL_SYSVAR(sched_priority_purge),
+#endif /* UNIV_LINUX */
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+ MYSQL_SYSVAR(show_locks_held),
+ MYSQL_SYSVAR(show_verbose_locks),
+ MYSQL_SYSVAR(track_changed_pages),
+ MYSQL_SYSVAR(track_redo_log_now),
+ MYSQL_SYSVAR(use_global_flush_log_at_trx_commit),
+ MYSQL_SYSVAR(use_stacktrace),
+
+#endif /* HA_XTRADB_SYSVARS */
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 153484c9941..60e742f27f7 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2013, 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
@@ -722,35 +722,6 @@ ha_innobase::check_if_supported_inplace_alter(
}
}
- /* If we have column that has changed from NULL -> NOT NULL
- and column default has changed we need to do additional
- check. */
- if ((ha_alter_info->handler_flags
- & Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) &&
- (ha_alter_info->handler_flags
- & Alter_inplace_info::ALTER_COLUMN_DEFAULT)) {
- Alter_info *alter_info = ha_alter_info->alter_info;
- List_iterator<Create_field> def_it(alter_info->create_list);
- Create_field *def;
- while ((def=def_it++)) {
-
- /* If this is first column definition whose SQL type
- is TIMESTAMP and it is defined as NOT NULL and
- it has either constant default or function default
- we must use "Copy" method. */
- if (def->is_timestamp_type()) {
- if ((def->flags & NOT_NULL_FLAG) != 0 && // NOT NULL
- (def->default_value != NULL || // constant default ?
- def->unireg_check != Field::NONE)) { // function default
- ha_alter_info->unsupported_reason = innobase_get_err_msg(
- ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
- DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
- }
- break;
- }
- }
- }
-
ulint n_indexes = UT_LIST_GET_LEN((m_prebuilt->table)->indexes);
/* If InnoDB dictionary and MySQL frm file are not consistent
@@ -1035,6 +1006,72 @@ ha_innobase::check_if_supported_inplace_alter(
}
}
+ /* When changing a NULL column to NOT NULL and specifying a
+ DEFAULT value, ensure that the DEFAULT expression is a constant.
+ Also, in ADD COLUMN, for now we only support a
+ constant DEFAULT expression. */
+ cf_it.rewind();
+ Field **af = altered_table->field;
+ while (Create_field* cf = cf_it++) {
+ DBUG_ASSERT(cf->field
+ || (ha_alter_info->handler_flags
+ & Alter_inplace_info::ADD_COLUMN));
+
+ if (const Field* f = cf->field) {
+ /* This could be changing an existing column
+ from NULL to NOT NULL. For now, ensure that
+ the DEFAULT is a constant. */
+ if (~ha_alter_info->handler_flags
+ & (Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE
+ | Alter_inplace_info::ALTER_COLUMN_DEFAULT)
+ || (*af)->real_maybe_null()) {
+ /* This ALTER TABLE is not both changing
+ a column to NOT NULL and changing the
+ DEFAULT value of a column, or this column
+ does allow NULL after the ALTER TABLE. */
+ goto next_column;
+ }
+
+ /* Find the matching column in the old table. */
+ Field** fp;
+ for (fp = table->field; *fp; fp++) {
+ if (f != *fp) {
+ continue;
+ }
+ if (!f->real_maybe_null()) {
+ /* The column already is NOT NULL. */
+ goto next_column;
+ }
+ break;
+ }
+
+ /* The column must be found in the old table. */
+ DBUG_ASSERT(fp < &table->field[table->s->fields]);
+ }
+
+ if (!(*af)->default_value
+ || (*af)->default_value->flags == 0) {
+ /* The NOT NULL column is not
+ carrying a non-constant DEFAULT. */
+ goto next_column;
+ }
+
+ /* TODO: Allow NULL column values to
+ be replaced with a non-constant DEFAULT. */
+ if (cf->field) {
+ ha_alter_info->unsupported_reason
+ = innobase_get_err_msg(
+ ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
+ }
+
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+
+next_column:
+ af++;
+ }
+
+ cf_it.rewind();
+
DBUG_RETURN(online
? HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE
: HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE);
@@ -4520,7 +4557,7 @@ prepare_inplace_alter_table_dict(
dtuple_t* add_cols;
ulint space_id = 0;
ulint z = 0;
- ulint key_id = FIL_DEFAULT_ENCRYPTION_KEY;
+ uint32_t key_id = FIL_DEFAULT_ENCRYPTION_KEY;
fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT;
fil_space_t* space = fil_space_acquire(ctx->prebuilt->table->space);
@@ -4863,7 +4900,7 @@ new_clustered_failed:
clustered index of the old table, later. */
if (new_clustered
|| !ctx->online
- || user_table->ibd_file_missing
+ || !user_table->is_readable()
|| dict_table_is_discarded(user_table)) {
/* No need to allocate a modification log. */
ut_ad(!ctx->add_index[a]->online_log);
@@ -5545,30 +5582,6 @@ ha_innobase::prepare_inplace_alter_table(
indexed_table = m_prebuilt->table;
- if (indexed_table->is_encrypted) {
- String str;
- const char* engine= table_type();
- push_warning_printf(m_user_thd, Sql_condition::WARN_LEVEL_WARN,
- HA_ERR_DECRYPTION_FAILED,
- "Table %s is encrypted but encryption service or"
- " used key_id is not available. "
- " Can't continue reading table.",
- indexed_table->name);
- get_error_message(HA_ERR_DECRYPTION_FAILED, &str);
- my_error(ER_GET_ERRMSG, MYF(0), HA_ERR_DECRYPTION_FAILED, str.c_ptr(), engine);
-
- DBUG_RETURN(true);
- }
-
- if (indexed_table->corrupted
- || dict_table_get_first_index(indexed_table) == NULL
- || dict_index_is_corrupted(
- dict_table_get_first_index(indexed_table))) {
- /* The clustered index is corrupted. */
- my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0));
- DBUG_RETURN(true);
- }
-
/* ALTER TABLE will not implicitly move a table from a single-table
tablespace to the system tablespace when innodb_file_per_table=OFF.
But it will implicitly move a table from the system tablespace to a
@@ -5588,6 +5601,42 @@ ha_innobase::prepare_inplace_alter_table(
}
}
+ if (indexed_table->is_readable()) {
+ } else {
+ if (indexed_table->corrupted) {
+ /* Handled below */
+ } else {
+ FilSpace space(indexed_table->space, true);
+
+ if (space()) {
+ String str;
+ const char* engine= table_type();
+
+ push_warning_printf(
+ m_user_thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_DECRYPTION_FAILED,
+ "Table %s in file %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ table_share->table_name.str,
+ space()->chain.start->name);
+
+ my_error(ER_GET_ERRMSG, MYF(0), HA_ERR_DECRYPTION_FAILED, str.c_ptr(), engine);
+ DBUG_RETURN(true);
+ }
+ }
+ }
+
+ if (indexed_table->corrupted
+ || dict_table_get_first_index(indexed_table) == NULL
+ || dict_index_is_corrupted(
+ dict_table_get_first_index(indexed_table))) {
+ /* The clustered index is corrupted. */
+ my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0));
+ DBUG_RETURN(true);
+ }
+
if (ha_alter_info->handler_flags
& Alter_inplace_info::CHANGE_CREATE_OPTION) {
const char* invalid_opt = info.create_options_are_invalid();
@@ -6381,7 +6430,7 @@ ok_exit:
ctx->m_stage = UT_NEW_NOKEY(ut_stage_alter_t(pk));
- if (m_prebuilt->table->ibd_file_missing
+ if (!m_prebuilt->table->is_readable()
|| dict_table_is_discarded(m_prebuilt->table)) {
goto all_done;
}
@@ -7804,7 +7853,7 @@ commit_try_rebuild(
/* The new table must inherit the flag from the
"parent" table. */
if (dict_table_is_discarded(user_table)) {
- rebuilt_table->ibd_file_missing = true;
+ rebuilt_table->file_unreadable = true;
rebuilt_table->flags2 |= DICT_TF2_DISCARDED;
}
@@ -8311,20 +8360,20 @@ alter_stats_rebuild(
}
#ifndef DBUG_OFF
- bool ibd_file_missing_orig = false;
+ bool file_unreadable_orig = false;
#endif /* DBUG_OFF */
DBUG_EXECUTE_IF(
"ib_rename_index_fail2",
- ibd_file_missing_orig = table->ibd_file_missing;
- table->ibd_file_missing = TRUE;
+ file_unreadable_orig = table->file_unreadable;
+ table->file_unreadable = true;
);
dberr_t ret = dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT);
DBUG_EXECUTE_IF(
"ib_rename_index_fail2",
- table->ibd_file_missing = ibd_file_missing_orig;
+ table->file_unreadable = file_unreadable_orig;
);
if (ret != DB_SUCCESS) {
@@ -8455,6 +8504,19 @@ ha_innobase::commit_inplace_alter_table(
= static_cast<ha_innobase_inplace_ctx*>(*pctx);
DBUG_ASSERT(ctx->prebuilt->trx == m_prebuilt->trx);
+ /* If decryption failed for old table or new table
+ fail here. */
+ if ((!ctx->old_table->is_readable()
+ && fil_space_get(ctx->old_table->space))
+ || (!ctx->new_table->is_readable()
+ && fil_space_get(ctx->new_table->space))) {
+ String str;
+ const char* engine= table_type();
+ get_error_message(HA_ERR_DECRYPTION_FAILED, &str);
+ my_error(ER_GET_ERRMSG, MYF(0), HA_ERR_DECRYPTION_FAILED, str.c_ptr(), engine);
+ DBUG_RETURN(true);
+ }
+
/* Exclusively lock the table, to ensure that no other
transaction is holding locks on the table while we
change the table definition. The MySQL meta-data lock
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index 3d764ef6e7a..ced45b96ea2 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -7117,11 +7117,11 @@ i_s_dict_fill_sys_virtual(
fields = table_to_fill->field;
- OK(fields[SYS_VIRTUAL_TABLE_ID]->store((longlong) table_id, TRUE));
+ OK(fields[SYS_VIRTUAL_TABLE_ID]->store(table_id, true));
- OK(fields[SYS_VIRTUAL_POS]->store(pos));
+ OK(fields[SYS_VIRTUAL_POS]->store(pos, true));
- OK(fields[SYS_VIRTUAL_BASE_POS]->store(base_pos));
+ OK(fields[SYS_VIRTUAL_BASE_POS]->store(base_pos, true));
OK(schema_table_store_record(thd, table_to_fill));
@@ -8601,31 +8601,31 @@ i_s_dict_fill_tablespaces_encryption(
fil_space_crypt_get_status(space, &status);
- OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id));
+ OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true));
OK(field_store_string(fields[TABLESPACES_ENCRYPTION_NAME],
space->name));
OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store(
- status.scheme));
+ status.scheme, true));
OK(fields[TABLESPACES_ENCRYPTION_KEYSERVER_REQUESTS]->store(
- status.keyserver_requests));
+ status.keyserver_requests, true));
OK(fields[TABLESPACES_ENCRYPTION_MIN_KEY_VERSION]->store(
- status.min_key_version));
+ status.min_key_version, true));
OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_VERSION]->store(
- status.current_key_version));
+ status.current_key_version, true));
OK(fields[TABLESPACES_ENCRYPTION_CURRENT_KEY_ID]->store(
- status.key_id));
+ status.key_id, true));
OK(fields[TABLESPACES_ENCRYPTION_ROTATING_OR_FLUSHING]->store(
- (status.rotating || status.flushing) ? 1 : 0));
+ status.rotating || status.flushing, true));
if (status.rotating) {
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->set_notnull();
OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]->store(
- status.rotate_next_page_number));
+ status.rotate_next_page_number, true));
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->set_notnull();
OK(fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_MAX_PAGE_NUMBER]->store(
- status.rotate_max_page_number));
+ status.rotate_max_page_number, true));
} else {
fields[TABLESPACES_ENCRYPTION_KEY_ROTATION_PAGE_NUMBER]
->set_null();
@@ -8910,13 +8910,13 @@ i_s_dict_fill_tablespaces_scrubbing(
fil_space_get_scrub_status(space, &status);
- OK(fields[TABLESPACES_SCRUBBING_SPACE]->store(space->id));
+ OK(fields[TABLESPACES_SCRUBBING_SPACE]->store(space->id, true));
OK(field_store_string(fields[TABLESPACES_SCRUBBING_NAME],
space->name));
OK(fields[TABLESPACES_SCRUBBING_COMPRESSED]->store(
- status.compressed ? 1 : 0));
+ status.compressed ? 1 : 0, true));
if (status.last_scrub_completed == 0) {
fields[TABLESPACES_SCRUBBING_LAST_SCRUB_COMPLETED]->set_null();
@@ -8943,11 +8943,11 @@ i_s_dict_fill_tablespaces_scrubbing(
fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_STARTED],
status.current_scrub_started));
OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_ACTIVE_THREADS]
- ->store(status.current_scrub_active_threads));
+ ->store(status.current_scrub_active_threads, true));
OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_PAGE_NUMBER]
- ->store(status.current_scrub_page_number));
+ ->store(status.current_scrub_page_number, true));
OK(fields[TABLESPACES_SCRUBBING_CURRENT_SCRUB_MAX_PAGE_NUMBER]
- ->store(status.current_scrub_max_page_number));
+ ->store(status.current_scrub_max_page_number, true));
} else {
for (uint i = 0; i < array_elements(field_numbers); i++) {
fields[field_numbers[i]]->set_null();
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index c7ffecd00c1..014d9f1a1a1 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -2829,8 +2829,7 @@ ibuf_get_volume_buffered_hash(
fold = ut_fold_binary(data, len);
hash += (fold / (CHAR_BIT * sizeof *hash)) % size;
- bitmask = static_cast<ulint>(
- 1 << (fold % (CHAR_BIT * sizeof(*hash))));
+ bitmask = static_cast<ulint>(1) << (fold % (CHAR_BIT * sizeof(*hash)));
if (*hash & bitmask) {
diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic
index 308fcfe9b03..bd4f2a40267 100644
--- a/storage/innobase/include/btr0btr.ic
+++ b/storage/innobase/include/btr0btr.ic
@@ -63,7 +63,7 @@ btr_block_get_func(
if (err == DB_DECRYPTION_FAILED) {
if (index && index->table) {
- index->table->is_encrypted = true;
+ index->table->file_unreadable = true;
}
}
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index e00af130479..fab934ca0ee 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -99,7 +99,7 @@ btr_pcur_free(
Initializes and opens a persistent cursor to an index tree. It should be
closed with btr_pcur_close. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_low(
/*==============*/
dict_index_t* index, /*!< in: index */
diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic
index 425593631d3..4490942a2bb 100644
--- a/storage/innobase/include/btr0pcur.ic
+++ b/storage/innobase/include/btr0pcur.ic
@@ -418,7 +418,7 @@ btr_pcur_free(
Initializes and opens a persistent cursor to an index tree. It should be
closed with btr_pcur_close. */
UNIV_INLINE
-void
+dberr_t
btr_pcur_open_low(
/*==============*/
dict_index_t* index, /*!< in: index */
@@ -471,6 +471,8 @@ btr_pcur_open_low(
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
cursor->trx_if_known = NULL;
+
+ return(err);
}
/**************************************************************//**
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 7dee52d8f74..928521e789e 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -812,9 +812,8 @@ buf_page_is_zeroes(
const byte* read_buf,
const page_size_t& page_size);
-/** Checks if a page is corrupt.
-@param[in] check_lsn true if we need to check and complain about
-the LSN
+/** Check if a page is corrupt.
+@param[in] check_lsn whether the LSN should be checked
@param[in] read_buf database page
@param[in] page_size page size
@param[in] space tablespace
@@ -824,8 +823,8 @@ buf_page_is_corrupted(
bool check_lsn,
const byte* read_buf,
const page_size_t& page_size,
- const fil_space_t* space = NULL
-) MY_ATTRIBUTE((warn_unused_result));
+ const fil_space_t* space = NULL)
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_INNOCHECKSUM
/**********************************************************************//**
Gets the space id, page offset, and byte offset within page of a
@@ -1249,7 +1248,7 @@ buf_pointer_is_block_field(
#define buf_pool_is_block_lock(l) \
buf_pointer_is_block_field((const void*)(l))
-/** Inits a page for read to the buffer buf_pool. If the page is
+/** Initialize a page for read to the buffer buf_pool. If the page is
(1) already in buf_pool, or
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
(3) if the space is deleted or being deleted,
@@ -1260,27 +1259,34 @@ and the lock released later.
@param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED
@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...
@param[in] page_id page id
-@param[in] unzip TRUE=request uncompressed page
-@return pointer to the block or NULL */
+@param[in] unzip whether the uncompressed page is
+ requested (for ROW_FORMAT=COMPRESSED)
+@return pointer to the block
+@retval NULL in case of an error */
buf_page_t*
buf_page_init_for_read(
dberr_t* err,
ulint mode,
const page_id_t& page_id,
const page_size_t& page_size,
- ibool unzip);
+ bool unzip);
+
+/** Complete a read or write request of a file page to or from the buffer pool.
+@param[in,out] bpage Page to complete
+@param[in] evict whether or not to evict the page
+ from LRU list.
+@return whether the operation succeeded
+@retval DB_SUCCESS always when writing, or if a read page was OK
+@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+ after decryption normal page checksum does
+ not match */
+UNIV_INTERN
+dberr_t
+buf_page_io_complete(buf_page_t* bpage, bool evict = false)
+ MY_ATTRIBUTE((nonnull));
/********************************************************************//**
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool.
-@return true if successful */
-bool
-buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage, /*!< in: pointer to the block in question */
- bool evict = false);/*!< in: whether or not to evict
- the page from LRU list. */
-/********************************************************************//**
Calculates the index of a buffer pool to the buf_pool[] array.
@return the position of the buffer pool in buf_pool[] */
UNIV_INLINE
@@ -1586,7 +1592,6 @@ public:
if written again we check is TRIM
operation needed. */
- unsigned key_version; /*!< key version for this block */
bool encrypted; /*!< page is still encrypted */
ulint real_size; /*!< Real size of the page
diff --git a/storage/innobase/include/buf0checksum.h b/storage/innobase/include/buf0checksum.h
index 9405251dc74..20955a5b2e6 100644
--- a/storage/innobase/include/buf0checksum.h
+++ b/storage/innobase/include/buf0checksum.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, 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
@@ -30,7 +31,7 @@ Created Aug 11, 2011 Vasil Dimov
#include "buf0types.h"
-/** Calculates the CRC32 checksum of a page. The value is stored to the page
+/** Calculate the CRC32 checksum of a page. The value is stored to the page
when it is written to a file and also checked for a match when reading from
the file. When reading we allow both normal CRC32 and CRC-legacy-big-endian
variants. Note that we must be careful to calculate the same value on 32-bit
@@ -44,37 +45,30 @@ buf_calc_page_crc32(
const byte* page,
bool use_legacy_big_endian = false);
-/********************************************************************//**
-Calculates a page checksum which is stored to the page when it is written
+/** Calculate a checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
32-bit and 64-bit architectures.
+@param[in] page file page (srv_page_size bytes)
@return checksum */
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
- const byte* page); /*!< in: buffer page */
-
-/********************************************************************//**
-In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
-looked at the first few bytes of the page. This calculates that old
-checksum.
+uint32_t
+buf_calc_page_new_checksum(const byte* page);
+
+/** In MySQL before 4.0.14 or 4.1.1 there was an InnoDB bug that
+the checksum only looked at the first few bytes of the page.
+This calculates that old checksum.
NOTE: we must first store the new formula checksum to
FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
because this takes that field as an input!
+@param[in] page file page (srv_page_size bytes)
@return checksum */
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
- const byte* page); /*!< in: buffer page */
-
+uint32_t
+buf_calc_page_old_checksum(const byte* page);
-/********************************************************************//**
-Return a printable string describing the checksum algorithm.
+/** Return a printable string describing the checksum algorithm.
+@param[in] algo algorithm
@return algorithm name */
const char*
-buf_checksum_algorithm_name(
-/*========================*/
- srv_checksum_algorithm_t algo); /*!< in: algorithm */
+buf_checksum_algorithm_name(srv_checksum_algorithm_t algo);
extern ulong srv_checksum_algorithm;
extern bool legacy_big_endian_checksum;
diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h
index 9c97a5147c1..5c766b9412a 100644
--- a/storage/innobase/include/buf0rea.h
+++ b/storage/innobase/include/buf0rea.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 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
@@ -37,12 +37,15 @@ an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@param[in] page_id page id
@param[in] page_size page size
-@return TRUE if page has been read in, FALSE in case of failure */
-ibool
+@retval DB_SUCCESS if the page was read and is not corrupted,
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */
+dberr_t
buf_read_page(
const page_id_t& page_id,
- const page_size_t& page_size,
- buf_page_t** bpage);
+ const page_size_t& page_size);
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
@@ -51,9 +54,8 @@ an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@param[in] page_id page id
@param[in] page_size page size
-@param[in] sync true if synchronous aio is desired
-@return TRUE if page has been read in, FALSE in case of failure */
-ibool
+@param[in] sync true if synchronous aio is desired */
+void
buf_read_page_background(
const page_id_t& page_id,
const page_size_t& page_size,
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index b0609991f61..ef6f8b39abb 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 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
@@ -163,6 +163,8 @@ enum dberr_t {
DB_IO_NO_PUNCH_HOLE, /*!< Punch hole not supported by
file system. */
+ DB_PAGE_CORRUPTED, /* Page read from tablespace is
+ corrupted. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
index f53ea74717d..76eb48d1e7e 100644
--- a/storage/innobase/include/dict0crea.h
+++ b/storage/innobase/include/dict0crea.h
@@ -45,7 +45,7 @@ tab_create_graph_create(
a memory data structure */
mem_heap_t* heap, /*!< in: heap where created */
fil_encryption_t mode, /*!< in: encryption mode */
- ulint key_id); /*!< in: encryption key_id */
+ uint32_t key_id); /*!< in: encryption key_id */
/** Creates an index create graph.
@param[in] index index to create, built as a memory data structure
@@ -305,7 +305,7 @@ struct tab_node_t{
/* Local storage for this graph node */
ulint state; /*!< node execution state */
ulint col_no; /*!< next column definition to insert */
- ulint key_id; /*!< encryption key_id */
+ uint key_id; /*!< encryption key_id */
fil_encryption_t mode; /*!< encryption mode */
ulint base_col_no; /*!< next base column to insert */
mem_heap_t* heap; /*!< memory heap used as auxiliary
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 18578388723..f80047f29a9 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -1889,6 +1889,14 @@ dict_set_corrupted_by_space(
/*========================*/
ulint space_id); /*!< in: space ID */
+/** Flag a table with specified space_id encrypted in the data dictionary
+cache
+@param[in] space_id Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(
+ ulint space_id);
+
/** Sets merge_threshold in the SYS_INDEXES
@param[in,out] index index
@param[in] merge_threshold value to set */
diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
index 8849be1206d..e9507302e66 100644
--- a/storage/innobase/include/dict0dict.ic
+++ b/storage/innobase/include/dict0dict.ic
@@ -1680,7 +1680,7 @@ dict_index_is_corrupted(
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
return((index->type & DICT_CORRUPT)
- || (index->table && index->table->corrupted));
+ || (index->table && index->table->corrupted));
}
/********************************************************************//**
diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
index fb443caf770..22fd27c2484 100644
--- a/storage/innobase/include/dict0load.h
+++ b/storage/innobase/include/dict0load.h
@@ -119,7 +119,7 @@ a foreign key references columns in this table.
@param[in] ignore_err Error to be ignored when loading
table and its index definition
@return table, NULL if does not exist; if the table is stored in an
-.ibd file, but the file does not exist, then we set the ibd_file_missing
+.ibd file, but the file does not exist, then we set the file_unreadable
flag in the table object we return. */
dict_table_t*
dict_load_table(
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 9b87e654b21..f35a7810736 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1018,6 +1018,13 @@ struct dict_index_t{
ut_ad(committed || !(type & DICT_CLUSTERED));
uncommitted = !committed;
}
+
+ /** @return whether this index is readable
+ @retval true normally
+ @retval false if this is a single-table tablespace
+ and the .ibd file is missing, or a
+ page cannot be read or decrypted */
+ inline bool is_readable() const;
};
/** The status of online index creation */
@@ -1367,6 +1374,15 @@ struct dict_table_t {
bool no_rollback() const
{
return flags & (1U << DICT_TF_POS_NO_ROLLBACK);
+ }
+ /** @return whether this table is readable
+ @retval true normally
+ @retval false if this is a single-table tablespace
+ and the .ibd file is missing, or a
+ page cannot be read or decrypted */
+ bool is_readable() const
+ {
+ return(UNIV_LIKELY(!file_unreadable));
}
/** Id of the table. */
@@ -1415,10 +1431,9 @@ struct dict_table_t {
Use DICT_TF2_FLAG_IS_SET() to parse this flag. */
unsigned flags2:DICT_TF2_BITS;
- /** TRUE if this is in a single-table tablespace and the .ibd file is
- missing. Then we must return in ha_innodb.cc an error if the user
- tries to query such an orphaned table. */
- unsigned ibd_file_missing:1;
+ /*!< whether this is in a single-table tablespace and the .ibd
+ file is missing or page decryption failed and page is corrupted */
+ unsigned file_unreadable:1;
/** TRUE if the table object has been added to the dictionary cache. */
unsigned cached:1;
@@ -1739,8 +1754,6 @@ public:
/** Timestamp of the last modification of this table. */
time_t update_time;
- bool is_encrypted;
-
#ifdef UNIV_DEBUG
/** Value of 'magic_n'. */
#define DICT_TABLE_MAGIC_N 76333786
@@ -1753,6 +1766,11 @@ public:
dict_vcol_templ_t* vc_templ;
};
+inline bool dict_index_t::is_readable() const
+{
+ return(UNIV_LIKELY(!table->file_unreadable));
+}
+
/*******************************************************************//**
Initialise the table lock list. */
void
diff --git a/storage/innobase/include/dict0stats.h b/storage/innobase/include/dict0stats.h
index f02b8eb8eed..752c197f8c3 100644
--- a/storage/innobase/include/dict0stats.h
+++ b/storage/innobase/include/dict0stats.h
@@ -252,6 +252,17 @@ dict_stats_save_index_stat(
const char* stat_description,
trx_t* trx);
+/** Report an error if updating table statistics failed because
+.ibd file is missing, table decryption failed or table is corrupted.
+@param[in,out] table Table
+@param[in] defragment true if statistics is for defragment
+@retval DB_DECRYPTION_FAILED if decryption of the table failed
+@retval DB_TABLESPACE_DELETED if .ibd file is missing
+@retval DB_CORRUPTION if table is marked as corrupted */
+dberr_t
+dict_stats_report_error(dict_table_t* table, bool defragment = false)
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
+
#include "dict0stats.ic"
#ifdef UNIV_ENABLE_UNIT_TEST_DICT_STATS
diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h
index ca65df21402..06785430c25 100644
--- a/storage/innobase/include/fil0crypt.h
+++ b/storage/innobase/include/fil0crypt.h
@@ -116,8 +116,7 @@ struct fil_space_crypt_t : st_encryption_scheme
min_key_version(new_min_key_version),
page0_offset(0),
encryption(new_encryption),
- mutex(),
- key_found(new_min_key_version),
+ key_found(0),
rotate_state()
{
key_id = new_key_id;
@@ -134,6 +133,8 @@ struct fil_space_crypt_t : st_encryption_scheme
type = CRYPT_SCHEME_1;
min_key_version = key_get_latest_version();
}
+
+ key_found = min_key_version;
}
/** Destructor */
@@ -205,7 +206,7 @@ struct fil_space_crypt_status_t {
uint min_key_version; /*!< min key version */
uint current_key_version;/*!< current key version */
uint keyserver_requests;/*!< no of key requests to key server */
- ulint key_id; /*!< current key_id */
+ uint key_id; /*!< current key_id */
bool rotating; /*!< is key rotation ongoing */
bool flushing; /*!< is flush at end of rotation ongoing */
ulint rotate_next_page_number; /*!< next page if key rotating */
@@ -293,13 +294,15 @@ Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
@param[in] ptr Log entry start
@param[in] end_ptr Log entry end
@param[in] block buffer block
+@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED
@return position on log buffer */
UNIV_INTERN
-const byte*
+byte*
fil_parse_write_crypt_data(
- const byte* ptr,
+ byte* ptr,
const byte* end_ptr,
- const buf_block_t* block)
+ const buf_block_t* block,
+ dberr_t* err)
MY_ATTRIBUTE((warn_unused_result));
/** Encrypt a buffer.
@@ -382,7 +385,7 @@ Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC
not needed. */
UNIV_INTERN
-ulint
+uint32_t
fil_crypt_calculate_checksum(
const page_size_t& page_size,
const byte* dst_frame)
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index cef5b578a4a..d8b6cf33675 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -733,21 +733,39 @@ MY_ATTRIBUTE((warn_unused_result));
Used by background threads that do not necessarily hold proper locks
for concurrency control.
@param[in] id tablespace ID
+@param[in] silent whether to silently ignore missing tablespaces
@return the tablespace
@retval NULL if missing or being deleted or truncated */
+UNIV_INTERN
fil_space_t*
-fil_space_acquire(ulint id)
+fil_space_acquire_low(ulint id, bool silent)
MY_ATTRIBUTE((warn_unused_result));
+/** Acquire a tablespace when it could be dropped concurrently.
+Used by background threads that do not necessarily hold proper locks
+for concurrency control.
+@param[in] id tablespace ID
+@return the tablespace
+@retval NULL if missing or being deleted or truncated */
+inline
+fil_space_t*
+fil_space_acquire(ulint id)
+{
+ return (fil_space_acquire_low(id, false));
+}
+
/** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks
for concurrency control.
@param[in] id tablespace ID
@return the tablespace
@retval NULL if missing or being deleted */
+inline
fil_space_t*
fil_space_acquire_silent(ulint id)
- MY_ATTRIBUTE((warn_unused_result));
+{
+ return (fil_space_acquire_low(id, true));
+}
/** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */
@@ -803,9 +821,10 @@ public:
/** Constructor: Look up the tablespace and increment the
reference count if found.
- @param[in] space_id tablespace ID */
- explicit FilSpace(ulint space_id)
- : m_space(fil_space_acquire(space_id)) {}
+ @param[in] space_id tablespace ID
+ @param[in] silent whether not to display errors */
+ explicit FilSpace(ulint space_id, bool silent = false)
+ : m_space(fil_space_acquire_low(space_id, silent)) {}
/** Assignment operator: This assumes that fil_space_acquire()
has already been done for the fil_space_t. The caller must
@@ -1044,7 +1063,7 @@ fil_ibd_create(
ulint flags,
ulint size,
fil_encryption_t mode,
- ulint key_id)
+ uint32_t key_id)
MY_ATTRIBUTE((warn_unused_result));
/** Try to adjust FSP_SPACE_FLAGS if they differ from the expectations.
@@ -1510,13 +1529,6 @@ fil_mtr_rename_log(
/*******************************************************************//**
Returns the table space by a given id, NULL if not found. */
fil_space_t*
-fil_space_found_by_id(
-/*==================*/
- ulint id); /*!< in: space id */
-
-/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
-fil_space_t*
fil_space_get_by_id(
/*================*/
ulint id); /*!< in: space id */
diff --git a/storage/innobase/include/fil0fil.ic b/storage/innobase/include/fil0fil.ic
index e3d4fd4d88b..9505cc0bd69 100644
--- a/storage/innobase/include/fil0fil.ic
+++ b/storage/innobase/include/fil0fil.ic
@@ -75,19 +75,6 @@ fil_get_page_type_name(
}
/****************************************************************//**
-Get block size from fil node
-@return block size*/
-UNIV_INLINE
-ulint
-fil_node_get_block_size(
-/*====================*/
- fil_node_t* node) /*!< in: Node where to get block
- size */
-{
- return (node->block_size);
-}
-
-/****************************************************************//**
Validate page type.
@return true if valid, false if not */
UNIV_INLINE
diff --git a/storage/innobase/include/fil0pagecompress.h b/storage/innobase/include/fil0pagecompress.h
index cd754151d80..67ff7895b02 100644
--- a/storage/innobase/include/fil0pagecompress.h
+++ b/storage/innobase/include/fil0pagecompress.h
@@ -67,23 +67,4 @@ fil_decompress_page(
/*!< in: true if only an error should
be produced when decompression fails.
By default this parameter is false. */
-
-/****************************************************************//**
-Get space id from fil node
-@return space id*/
-UNIV_INTERN
-ulint
-fil_node_get_space_id(
-/*==================*/
- fil_node_t* node); /*!< in: Node where to get space id*/
-
-/****************************************************************//**
-Get block size from fil node
-@return block size*/
-UNIV_INLINE
-ulint
-fil_node_get_block_size(
-/*====================*/
- fil_node_t* node); /*!< in: Node where to get block
- size */
#endif
diff --git a/storage/innobase/include/fsp0space.h b/storage/innobase/include/fsp0space.h
index 0b66827ab49..3928f8362b9 100644
--- a/storage/innobase/include/fsp0space.h
+++ b/storage/innobase/include/fsp0space.h
@@ -140,7 +140,7 @@ public:
/** Get the tablespace encryption key_id
@return m_key_id tablespace encryption key_id */
- ulint key_id() const
+ uint32_t key_id() const
{
return (m_key_id);
}
@@ -226,7 +226,7 @@ private:
/** Encryption mode and key_id */
fil_encryption_t m_mode;
- ulint m_key_id;
+ uint32_t m_key_id;
protected:
/** Ignore server read only configuration for this tablespace. */
diff --git a/storage/innobase/include/mtr0log.ic b/storage/innobase/include/mtr0log.ic
index 972fdc81518..dd68ea25613 100644
--- a/storage/innobase/include/mtr0log.ic
+++ b/storage/innobase/include/mtr0log.ic
@@ -76,10 +76,10 @@ mlog_catenate_ulint(
ulint val, /*!< in: value to write */
mlog_id_t type) /*!< in: type of value to write */
{
- ut_ad(MLOG_1BYTE == 1);
- ut_ad(MLOG_2BYTES == 2);
- ut_ad(MLOG_4BYTES == 4);
- ut_ad(MLOG_8BYTES == 8);
+ compile_time_assert(MLOG_1BYTE == 1);
+ compile_time_assert(MLOG_2BYTES == 2);
+ compile_time_assert(MLOG_4BYTES == 4);
+ compile_time_assert(MLOG_8BYTES == 8);
byte* ptr = mtr_buf->push<byte*>(type);
@@ -182,6 +182,14 @@ mlog_write_initial_log_record_low(
mtr_t* mtr)
{
ut_ad(type <= MLOG_BIGGEST_TYPE || EXTRA_CHECK_MLOG_NUMBER(type));
+ ut_ad(type == MLOG_FILE_NAME
+ || type == MLOG_FILE_DELETE
+ || type == MLOG_FILE_CREATE2
+ || type == MLOG_FILE_RENAME2
+ || type == MLOG_INDEX_LOAD
+ || type == MLOG_TRUNCATE
+ || type == MLOG_FILE_WRITE_CRYPT_DATA
+ || mtr->is_named_space(space_id));
mach_write_to_1(log_ptr, type);
log_ptr++;
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 0557b585ae1..7507c96ea5f 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -365,7 +365,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 */
MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
@@ -474,7 +474,7 @@ row_drop_table_for_mysql(
/*********************************************************************//**
Discards the tablespace of a table which stored in an .ibd file. Discarding
means that this function deletes the .ibd file and assigns a new table id for
-the table. Also the flag table->ibd_file_missing is set TRUE.
+the table. Also the file_unreadable flag is set.
@return error code or DB_SUCCESS */
dberr_t
row_discard_tablespace_for_mysql(
diff --git a/storage/innobase/include/row0trunc.h b/storage/innobase/include/row0trunc.h
index b6c7810d522..56302a0e570 100644
--- a/storage/innobase/include/row0trunc.h
+++ b/storage/innobase/include/row0trunc.h
@@ -359,7 +359,7 @@ private:
/** Encryption information of the table */
fil_encryption_t m_encryption;
- uint m_key_id;
+ uint32_t m_key_id;
/** Vector of tables to truncate. */
typedef std::vector<truncate_t*, ut_allocator<truncate_t*> >
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 230d7b7effe..9d8e736beb1 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -57,15 +57,13 @@ Created 10/10/1995 Heikki Tuuri
#include "ut0counter.h"
#include "fil0fil.h"
-struct fil_space_t;
-
-/* Global counters used inside InnoDB. */
-struct srv_stats_t {
+/** Global counters used inside InnoDB. */
+struct srv_stats_t
+{
typedef ib_counter_t<ulint, 64> ulint_ctr_64_t;
- typedef ib_counter_t<lsn_t, 1, single_indexer_t> lsn_ctr_1_t;
- typedef ib_counter_t<ulint, 1, single_indexer_t> ulint_ctr_1_t;
- typedef ib_counter_t<lint, 1, single_indexer_t> lint_ctr_1_t;
- typedef ib_counter_t<int64_t, 1, single_indexer_t> int64_ctr_1_t;
+ typedef simple_counter<lsn_t> lsn_ctr_1_t;
+ typedef simple_counter<ulint> ulint_ctr_1_t;
+ typedef simple_counter<int64_t> int64_ctr_1_t;
/** Count the amount of data written in total (in bytes) */
ulint_ctr_1_t data_written;
@@ -82,8 +80,9 @@ struct srv_stats_t {
/** Amount of data written to the log files in bytes */
lsn_ctr_1_t os_log_written;
- /** Number of writes being done to the log files */
- lint_ctr_1_t os_log_pending_writes;
+ /** Number of writes being done to the log files.
+ Protected by log_sys->write_mutex. */
+ ulint_ctr_1_t os_log_pending_writes;
/** We increase this counter, when we don't have enough
space in the log buffer and have to flush it */
@@ -141,7 +140,7 @@ struct srv_stats_t {
ulint_ctr_1_t n_lock_wait_count;
/** Number of threads currently waiting on database locks */
- lint_ctr_1_t n_lock_wait_current_count;
+ simple_counter<ulint, true> n_lock_wait_current_count;
/** Number of rows read. */
ulint_ctr_64_t n_rows_read;
diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h
index 1d11bfa7811..c3d413e71df 100644
--- a/storage/innobase/include/sync0types.h
+++ b/storage/innobase/include/sync0types.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation. 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
@@ -1266,4 +1266,48 @@ enum rw_lock_flag_t {
#define my_atomic_caslint my_atomic_caslong
#endif
+/** Simple counter aligned to CACHE_LINE_SIZE
+@tparam Type the integer type of the counter
+@tparam atomic whether to use atomic memory access */
+template <typename Type = ulint, bool atomic = false>
+struct MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) simple_counter
+{
+ /** Increment the counter */
+ Type inc() { return add(1); }
+ /** Decrement the counter */
+ Type dec() { return sub(1); }
+
+ /** Add to the counter
+ @param[in] i amount to be added
+ @return the value of the counter after adding */
+ Type add(Type i)
+ {
+ compile_time_assert(!atomic || sizeof(Type) == sizeof(lint));
+ if (atomic) {
+ return Type(my_atomic_addlint(&m_counter, i));
+ } else {
+ return m_counter += i;
+ }
+ }
+ /** Subtract from the counter
+ @param[in] i amount to be subtracted
+ @return the value of the counter after adding */
+ Type sub(Type i)
+ {
+ compile_time_assert(!atomic || sizeof(Type) == sizeof(lint));
+ if (atomic) {
+ return Type(my_atomic_addlint(&m_counter, -lint(i)));
+ } else {
+ return m_counter -= i;
+ }
+ }
+
+ /** @return the value of the counter (non-atomic access)! */
+ operator Type() const { return m_counter; }
+
+private:
+ /** The counter */
+ Type m_counter;
+};
+
#endif /* sync0types_h */
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 446e619abb9..75753b53467 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -1508,17 +1508,15 @@ private:
}
/* Avoid excessive mutex acquire/release */
- ++trx->in_depth;
-
- /* If trx->in_depth is greater than 1 then
- transaction is already in InnoDB. */
- if (trx->in_depth > 1) {
-
+ if (++trx->in_depth > 1) {
+ /* The transaction is already inside InnoDB. */
+ ut_ad(trx->in_depth > 1);
return;
}
/* Only the owning thread should release the latch. */
+ ut_ad(trx->in_depth == 1);
trx_assert_no_search_latch(trx);
trx_mutex_enter(trx);
@@ -1545,15 +1543,14 @@ private:
ut_ad(trx->in_depth > 0);
- --trx->in_depth;
-
- if (trx->in_depth > 0) {
-
+ if (--trx->in_depth > 0) {
+ ut_ad(trx->in_depth);
return;
}
/* Only the owning thread should release the latch. */
+ ut_ad(trx->in_depth == 0);
trx_assert_no_search_latch(trx);
trx_mutex_enter(trx);
diff --git a/storage/innobase/include/ut0counter.h b/storage/innobase/include/ut0counter.h
index 70381f26a84..f1a9384667e 100644
--- a/storage/innobase/include/ut0counter.h
+++ b/storage/innobase/include/ut0counter.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2015, 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
@@ -44,8 +45,6 @@ Created 2012/04/12 by Sunny Bains
/** Get the offset into the counter array. */
template <typename Type, int N>
struct generic_indexer_t {
- /** Default constructor/destructor should be OK. */
-
/** @return offset within m_counter */
static size_t offset(size_t index) UNIV_NOTHROW
{
@@ -57,11 +56,6 @@ struct generic_indexer_t {
to index into the counter array. See the comments for my_timer_cycles() */
template <typename Type=ulint, int N=1>
struct counter_indexer_t : public generic_indexer_t<Type, N> {
-
- /** Default constructor/destructor should be OK. */
-
- enum { fast = 1 };
-
/** @return result from RDTSC or similar functions. */
static size_t get_rnd_index() UNIV_NOTHROW
{
@@ -82,27 +76,11 @@ struct counter_indexer_t : public generic_indexer_t<Type, N> {
#endif /* !_WIN32 */
}
}
-};
-/** For counters where N=1 */
-template <typename Type=ulint, int N=1>
-struct single_indexer_t {
- /** Default constructor/destructor should are OK. */
-
- enum { fast = 0 };
-
- /** @return offset within m_counter */
- static size_t offset(size_t index) UNIV_NOTHROW
+ /** @return a random offset to the array */
+ static size_t get_rnd_offset() UNIV_NOTHROW
{
- ut_ad(N == 1);
- return((CACHE_LINE_SIZE / sizeof(Type)));
- }
-
- /** @return 1 */
- static size_t get_rnd_index() UNIV_NOTHROW
- {
- ut_ad(N == 1);
- return(1);
+ return(generic_indexer_t<Type, N>::offset(get_rnd_index()));
}
};
@@ -116,19 +94,11 @@ template <
typename Type,
int N = IB_N_SLOTS,
template<typename, int> class Indexer = default_indexer_t>
-class ib_counter_t {
-public:
- ib_counter_t() { memset(m_counter, 0x0, sizeof(m_counter)); }
-
+struct MY_ALIGNED(CACHE_LINE_SIZE) ib_counter_t
+{
+#ifdef UNIV_DEBUG
~ib_counter_t()
{
- ut_ad(validate());
- }
-
- static bool is_fast() { return(Indexer<Type, N>::fast); }
-
- bool validate() UNIV_NOTHROW {
-#ifdef UNIV_DEBUG
size_t n = (CACHE_LINE_SIZE / sizeof(Type));
/* Check that we aren't writing outside our defined bounds. */
@@ -137,27 +107,23 @@ public:
ut_ad(m_counter[i + j] == 0);
}
}
-#endif /* UNIV_DEBUG */
- return(true);
}
+#endif /* UNIV_DEBUG */
- /** If you can't use a good index id. Increment by 1. */
+ /** Increment the counter by 1. */
void inc() UNIV_NOTHROW { add(1); }
- /** If you can't use a good index id.
- @param n is the amount to increment */
- void add(Type n) UNIV_NOTHROW {
- size_t i = m_policy.offset(m_policy.get_rnd_index());
-
- ut_ad(i < UT_ARR_SIZE(m_counter));
+ /** Increment the counter by 1.
+ @param[in] index a reasonably thread-unique identifier */
+ void inc(size_t index) UNIV_NOTHROW { add(index, 1); }
- m_counter[i] += n;
- }
+ /** Add to the counter.
+ @param[in] n amount to be added */
+ void add(Type n) UNIV_NOTHROW { add(m_policy.get_rnd_offset(), n); }
- /** Use this if you can use a unique identifier, saves a
- call to get_rnd_index().
- @param i index into a slot
- @param n amount to increment */
+ /** Add to the counter.
+ @param[in] index a reasonably thread-unique identifier
+ @param[in] n amount to be added */
void add(size_t index, Type n) UNIV_NOTHROW {
size_t i = m_policy.offset(index);
@@ -166,31 +132,6 @@ public:
m_counter[i] += n;
}
- /** If you can't use a good index id. Decrement by 1. */
- void dec() UNIV_NOTHROW { sub(1); }
-
- /** If you can't use a good index id.
- @param n the amount to decrement */
- void sub(Type n) UNIV_NOTHROW {
- size_t i = m_policy.offset(m_policy.get_rnd_index());
-
- ut_ad(i < UT_ARR_SIZE(m_counter));
-
- m_counter[i] -= n;
- }
-
- /** Use this if you can use a unique identifier, saves a
- call to get_rnd_index().
- @param i index into a slot
- @param n amount to decrement */
- void sub(size_t index, Type n) UNIV_NOTHROW {
- size_t i = m_policy.offset(index);
-
- ut_ad(i < UT_ARR_SIZE(m_counter));
-
- m_counter[i] -= n;
- }
-
/* @return total value - not 100% accurate, since it is not atomic. */
operator Type() const UNIV_NOTHROW {
Type total = 0;
diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h
index 3027004dbaf..7082d18da53 100644
--- a/storage/innobase/include/ut0ut.h
+++ b/storage/innobase/include/ut0ut.h
@@ -313,7 +313,7 @@ ut_sprintf_timestamp(
Runs an idle loop on CPU. The argument gives the desired delay
in microseconds on 100 MHz Pentium + Visual C++.
@return dummy value */
-ulint
+void
ut_delay(
/*=====*/
ulint delay); /*!< in: delay in microseconds on 100 MHz Pentium */
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 1860cd51362..01ffad772dc 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -2653,7 +2653,7 @@ lock_rec_has_to_wait_in_queue(
heap_no = lock_rec_find_set_bit(wait_lock);
bit_offset = heap_no / 8;
- bit_mask = static_cast<ulint>(1 << (heap_no % 8));
+ bit_mask = static_cast<ulint>(1) << (heap_no % 8);
hash = lock_hash_get(wait_lock->type_mode);
diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc
index 867e596bca2..0954ad9430a 100644
--- a/storage/innobase/lock/lock0wait.cc
+++ b/storage/innobase/lock/lock0wait.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2014, 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
@@ -263,6 +263,9 @@ lock_wait_suspend_thread(
slot = lock_wait_table_reserve_slot(thr, lock_wait_timeout);
+ lock_wait_mutex_exit();
+ trx_mutex_exit(trx);
+
if (thr->lock_state == QUE_THR_LOCK_ROW) {
srv_stats.n_lock_wait_count.inc();
srv_stats.n_lock_wait_current_count.inc();
@@ -274,23 +277,21 @@ lock_wait_suspend_thread(
}
}
- /* Wake the lock timeout monitor thread, if it is suspended */
-
- os_event_set(lock_sys->timeout_event);
-
- lock_wait_mutex_exit();
- trx_mutex_exit(trx);
-
ulint lock_type = ULINT_UNDEFINED;
- lock_mutex_enter();
-
+ /* The wait_lock can be cleared by another thread when the
+ lock is released. But the wait can only be initiated by the
+ current thread which owns the transaction. Only acquire the
+ mutex if the wait_lock is still active. */
if (const lock_t* wait_lock = trx->lock.wait_lock) {
- lock_type = lock_get_type_low(wait_lock);
+ lock_mutex_enter();
+ wait_lock = trx->lock.wait_lock;
+ if (wait_lock) {
+ lock_type = lock_get_type_low(wait_lock);
+ }
+ lock_mutex_exit();
}
- lock_mutex_exit();
-
ulint had_dict_lock = trx->dict_operation_lock_mode;
switch (had_dict_lock) {
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index dbfda8ab7c4..79301254a0a 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -26,7 +26,7 @@ MDEV-11782: Rewritten for MariaDB 10.2 by Marko Mäkelä, MariaDB Corporation.
*******************************************************/
#include "m_string.h"
#include "log0crypt.h"
-#include "my_crypt.h"
+#include <mysql/service_my_crypt.h>
#include "log0crypt.h"
#include "srv0start.h" // for srv_start_lsn
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 0b46c92f00a..f3a00e7b5e6 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -1497,7 +1497,12 @@ parse_log:
}
break;
case MLOG_FILE_WRITE_CRYPT_DATA:
- ptr = const_cast<byte*>(fil_parse_write_crypt_data(ptr, end_ptr, block));
+ dberr_t err;
+ ptr = const_cast<byte*>(fil_parse_write_crypt_data(ptr, end_ptr, block, &err));
+
+ if (err != DB_SUCCESS) {
+ recv_sys->found_corrupt_log = TRUE;
+ }
break;
default:
ptr = NULL;
@@ -1993,6 +1998,11 @@ recv_apply_hashed_log_recs(bool last_batch)
break;
}
+ if (recv_sys->found_corrupt_log) {
+ mutex_exit(&recv_sys->mutex);
+ return;
+ }
+
mutex_exit(&recv_sys->mutex);
os_thread_sleep(500000);
}
@@ -2076,6 +2086,10 @@ recv_apply_hashed_log_recs(bool last_batch)
mutex_exit(&(recv_sys->mutex));
+ if (recv_sys->found_corrupt_log) {
+ return;
+ }
+
os_thread_sleep(500000);
mutex_enter(&(recv_sys->mutex));
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index 110ac6f40f1..93e8caf9301 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -362,7 +362,7 @@ public:
void print(FILE* file);
/** @return the number of slots per segment */
- unsigned slots_per_segment() const
+ ulint slots_per_segment() const
MY_ATTRIBUTE((warn_unused_result))
{
return(m_slots.size() / m_n_segments);
@@ -5778,7 +5778,7 @@ AIO::init_linux_native_aio()
}
io_context** ctx = m_aio_ctx;
- unsigned max_events = slots_per_segment();
+ ulint max_events = slots_per_segment();
for (ulint i = 0; i < m_n_segments; ++i, ++ctx) {
diff --git a/storage/innobase/os/os0proc.cc b/storage/innobase/os/os0proc.cc
index 9309c1f2c97..22966690ab0 100644
--- a/storage/innobase/os/os0proc.cc
+++ b/storage/innobase/os/os0proc.cc
@@ -182,7 +182,7 @@ os_mem_free_large(
<< ") failed; Windows error " << GetLastError();
} else {
my_atomic_addlint(
- &os_total_large_mem_allocated, -size);
+ &os_total_large_mem_allocated, -lint(size));
UNIV_MEM_FREE(ptr, size);
}
#elif !defined OS_MAP_ANON
diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc
index df7d26c63e8..e5c903935f1 100644
--- a/storage/innobase/page/page0cur.cc
+++ b/storage/innobase/page/page0cur.cc
@@ -2060,14 +2060,10 @@ page_copy_rec_list_end_to_created_page(
/* Individual inserts are logged in a shorter form */
- mtr_log_t log_mode;
-
- if (dict_table_is_temporary(index->table)
- || index->table->ibd_file_missing /* IMPORT TABLESPACE */) {
- log_mode = mtr_get_log_mode(mtr);
- } else {
- log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
- }
+ const mtr_log_t log_mode = dict_table_is_temporary(index->table)
+ || !index->is_readable() /* IMPORT TABLESPACE */
+ ? mtr_get_log_mode(mtr)
+ : mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
prev_rec = page_get_infimum_rec(new_page);
if (page_is_comp(new_page)) {
diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc
index e718081ed63..59022dbe301 100644
--- a/storage/innobase/page/page0zip.cc
+++ b/storage/innobase/page/page0zip.cc
@@ -4634,6 +4634,7 @@ page_zip_write_header_log(
#if PAGE_DATA > 255
# error "PAGE_DATA > 255"
#endif
+ ut_ad(length > 0);
ut_ad(length < 256);
/* If no logging is requested, we may return now */
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;
}
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 6d153ff1bc6..e451fcb04b0 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -2210,6 +2210,11 @@ files_checked:
recv_group_scan_log_recs(). */
recv_apply_hashed_log_recs(true);
+
+ if (recv_sys->found_corrupt_log) {
+ return (DB_CORRUPTION);
+ }
+
DBUG_PRINT("ib_log", ("apply completed"));
if (recv_needed_recovery) {
@@ -2470,14 +2475,6 @@ files_checked:
ut_ad(err == DB_SUCCESS);
ut_a(sum_of_new_sizes != ULINT_UNDEFINED);
- /* Open temp-tablespace and keep it open until shutdown. */
-
- err = srv_open_tmp_tablespace(create_new_db);
-
- if (err != DB_SUCCESS) {
- return(srv_init_abort(err));
- }
-
/* Create the doublewrite buffer to a new tablespace */
if (!srv_read_only_mode && srv_force_recovery < SRV_FORCE_NO_TRX_UNDO
&& !buf_dblwr_create()) {
@@ -2552,6 +2549,18 @@ files_checked:
return(srv_init_abort(err));
}
+ if (!srv_read_only_mode) {
+ /* Initialize the innodb_temporary tablespace and keep
+ it open until shutdown. */
+ err = srv_open_tmp_tablespace(create_new_db);
+
+ if (err != DB_SUCCESS) {
+ return(srv_init_abort(err));
+ }
+
+ trx_temp_rseg_create();
+ }
+
srv_is_being_started = false;
ut_a(trx_purge_state() == PURGE_STATE_INIT);
diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc
index c748bad1417..6322b14335f 100644
--- a/storage/innobase/sync/sync0rw.cc
+++ b/storage/innobase/sync/sync0rw.cc
@@ -277,6 +277,9 @@ rw_lock_free_func(
/* We did an in-place new in rw_lock_create_func() */
ut_d(lock->~rw_lock_t());
+ /* Sometimes (maybe when compiled with GCC -O3) the above call
+ to rw_lock_t::~rw_lock_t() will not actually assign magic_n=0. */
+ ut_d(lock->magic_n = 0);
}
/******************************************************************//**
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index 47f30138ceb..d511aae48ec 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -887,9 +887,6 @@ trx_sys_create_rsegs()
return(true);
}
- /* Create temporary rollback segments. */
- trx_temp_rseg_create();
-
/* This is executed in single-threaded mode therefore it is not
necessary to use the same mtr in trx_rseg_create(). n_used cannot
change while the function is executing. */
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index a6cfcf0910b..315697403c4 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -773,7 +773,7 @@ trx_resurrect_table_locks(
i != tables.end(); i++) {
if (dict_table_t* table = dict_table_open_on_id(
*i, FALSE, DICT_TABLE_OP_LOAD_TABLESPACE)) {
- if (table->ibd_file_missing
+ if (!table->is_readable()
|| dict_table_is_temporary(table)) {
mutex_enter(&dict_sys->mutex);
dict_table_close(table, TRUE, FALSE);
diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc
index 2cae865cff2..e7489861473 100644
--- a/storage/innobase/ut/ut0ut.cc
+++ b/storage/innobase/ut/ut0ut.cc
@@ -285,26 +285,21 @@ ut_sprintf_timestamp(
Runs an idle loop on CPU. The argument gives the desired delay
in microseconds on 100 MHz Pentium + Visual C++.
@return dummy value */
-ulint
+void
ut_delay(
/*=====*/
ulint delay) /*!< in: delay in microseconds on 100 MHz Pentium */
{
- ulint i, j;
+ ulint i;
UT_LOW_PRIORITY_CPU();
- j = 0;
-
for (i = 0; i < delay * 50; i++) {
- j += i;
UT_RELAX_CPU();
UT_COMPILER_BARRIER();
}
UT_RESUME_PRIORITY_CPU();
-
- return(j);
}
/*************************************************************//**
@@ -757,6 +752,8 @@ ut_strerr(
"of stored column");
case DB_IO_NO_PUNCH_HOLE:
return ("File system does not support punch hole (trim) operation.");
+ case DB_PAGE_CORRUPTED:
+ return("Page read from tablespace is corrupted.");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
index afb5fb8bdff..1eebfac03f8 100644
--- a/storage/maria/ma_pagecache.c
+++ b/storage/maria/ma_pagecache.c
@@ -493,7 +493,8 @@ error:
#define FLUSH_CACHE 2000 /* sort this many blocks at once */
-static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block);
+static my_bool free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
+ my_bool abort_if_pinned);
static void unlink_hash(PAGECACHE *pagecache, PAGECACHE_HASH_LINK *hash_link);
#ifndef DBUG_OFF
static void test_key_cache(PAGECACHE *pagecache,
@@ -1945,7 +1946,7 @@ restart:
removed from the cache as we set the PCBLOCK_REASSIGNED
flag (see the code below that handles reading requests).
*/
- free_block(pagecache, block);
+ free_block(pagecache, block, 0);
return 0;
}
/* Wait until the page is flushed on disk */
@@ -1956,7 +1957,7 @@ restart:
/* Invalidate page in the block if it has not been done yet */
DBUG_ASSERT(block->status); /* Should always be true */
if (block->status)
- free_block(pagecache, block);
+ free_block(pagecache, block, 0);
return 0;
}
@@ -1981,8 +1982,13 @@ restart:
}
else
{
- DBUG_ASSERT(hash_link->requests > 0);
- hash_link->requests--;
+ /*
+ When we come here either PCBLOCK_REASSIGNED or PCBLOCK_IN_SWITCH are
+ active. In both cases wqueue_release_queue() is called when the
+ state changes.
+ */
+ DBUG_ASSERT(block->hash_link == hash_link);
+ remove_reader(block);
KEYCACHE_DBUG_PRINT("find_block",
("request waiting for old page to be saved"));
{
@@ -3638,7 +3644,7 @@ static my_bool pagecache_delete_internal(PAGECACHE *pagecache,
DBUG_ASSERT(block->hash_link->requests > 0);
page_link->requests--;
/* See NOTE for pagecache_unlock() about registering requests. */
- free_block(pagecache, block);
+ free_block(pagecache, block, 0);
dec_counter_for_resize_op(pagecache);
return 0;
@@ -4219,7 +4225,8 @@ end:
and add it to the free list.
*/
-static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
+static my_bool free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
+ my_bool abort_if_pinned)
{
uint status= block->status;
KEYCACHE_THREAD_TRACE("free block");
@@ -4233,11 +4240,27 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
/*
While waiting for readers to finish, new readers might request the
block. But since we set block->status|= PCBLOCK_REASSIGNED, they
- will wait on block->wqueue[COND_FOR_SAVED]. They must be signalled
+ will wait on block->wqueue[COND_FOR_SAVED]. They must be signaled
later.
*/
block->status|= PCBLOCK_REASSIGNED;
wait_for_readers(pagecache, block);
+ if (unlikely(abort_if_pinned) && unlikely(block->pins))
+ {
+ /*
+ Block got pinned while waiting for readers.
+ This can only happens when called from flush_pagecache_blocks_int()
+ when flushing blocks as part of prepare for maria_close() or from
+ flush_cached_blocks()
+ */
+ block->status&= ~PCBLOCK_REASSIGNED;
+ unreg_request(pagecache, block, 0);
+
+ /* All pending requests for this page must be resubmitted. */
+ if (block->wqueue[COND_FOR_SAVED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
+ return 1;
+ }
unlink_hash(pagecache, block->hash_link);
}
@@ -4288,6 +4311,8 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
/* All pending requests for this page must be resubmitted. */
if (block->wqueue[COND_FOR_SAVED].last_thread)
wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
+
+ return 0;
}
@@ -4423,9 +4448,16 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
if (! (type == FLUSH_KEEP || type == FLUSH_KEEP_LAZY ||
type == FLUSH_FORCE_WRITE))
{
- pagecache->blocks_changed--;
- pagecache->global_blocks_changed--;
- free_block(pagecache, block);
+ if (!free_block(pagecache, block, 1))
+ {
+ pagecache->blocks_changed--;
+ pagecache->global_blocks_changed--;
+ }
+ else
+ {
+ block->status&= ~PCBLOCK_IN_FLUSH;
+ link_to_file_list(pagecache, block, file, 1);
+ }
}
else
{
@@ -4663,7 +4695,7 @@ restart:
/* It's a temporary file */
pagecache->blocks_changed--;
pagecache->global_blocks_changed--;
- free_block(pagecache, block);
+ free_block(pagecache, block, 0);
}
}
else if (type != FLUSH_KEEP_LAZY)
@@ -4733,11 +4765,12 @@ restart:
#endif
next= block->next_changed;
if (block->hash_link->file.file == file->file &&
+ !block->pins &&
(! (block->status & PCBLOCK_CHANGED)
|| type == FLUSH_IGNORE_CHANGED))
{
reg_requests(pagecache, block, 1);
- free_block(pagecache, block);
+ free_block(pagecache, block, 1);
}
}
}
diff --git a/storage/myisam/mi_delete_table.c b/storage/myisam/mi_delete_table.c
index d766fb2547f..5ad63a5cc87 100644
--- a/storage/myisam/mi_delete_table.c
+++ b/storage/myisam/mi_delete_table.c
@@ -38,11 +38,9 @@ int mi_delete_table(const char *name)
mysql_file_delete_with_symlink(mi_key_file_dfile, name, MI_NAME_DEXT, MYF(MY_WME)))
DBUG_RETURN(my_errno);
-
// optionally present:
mysql_file_delete_with_symlink(mi_key_file_dfile, name, ".OLD", MYF(0));
mysql_file_delete_with_symlink(mi_key_file_dfile, name, ".TMD", MYF(0));
DBUG_RETURN(0);
}
-
diff --git a/storage/rocksdb/build_rocksdb.cmake b/storage/rocksdb/build_rocksdb.cmake
index 8b7e64a8e08..7ed47940c6d 100644
--- a/storage/rocksdb/build_rocksdb.cmake
+++ b/storage/rocksdb/build_rocksdb.cmake
@@ -143,7 +143,9 @@ set(LIBS ${ROCKSDB_LIBS} ${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
# Main library source code
set(ROCKSDB_SOURCES
- db/auto_roll_logger.cc
+ cache/clock_cache.cc
+ cache/lru_cache.cc
+ cache/sharded_cache.cc
db/builder.cc
db/c.cc
db/column_family.cc
@@ -152,19 +154,23 @@ set(ROCKSDB_SOURCES
db/compaction_iterator.cc
db/compaction_job.cc
db/compaction_picker.cc
+ db/compaction_picker_universal.cc
db/convenience.cc
- db/dbformat.cc
db/db_filesnapshot.cc
db/db_impl.cc
+ db/db_impl_write.cc
+ db/db_impl_compaction_flush.cc
+ db/db_impl_files.cc
+ db/db_impl_open.cc
db/db_impl_debug.cc
db/db_impl_experimental.cc
db/db_impl_readonly.cc
db/db_info_dumper.cc
db/db_iter.cc
+ db/dbformat.cc
db/event_helpers.cc
- db/external_sst_file_ingestion_job.cc
db/experimental.cc
- db/filename.cc
+ db/external_sst_file_ingestion_job.cc
db/file_indexer.cc
db/flush_job.cc
db/flush_scheduler.cc
@@ -174,7 +180,6 @@ set(ROCKSDB_SOURCES
db/log_writer.cc
db/managed_iterator.cc
db/memtable.cc
- db/memtable_allocator.cc
db/memtable_list.cc
db/merge_helper.cc
db/merge_operator.cc
@@ -192,11 +197,33 @@ set(ROCKSDB_SOURCES
db/write_batch_base.cc
db/write_controller.cc
db/write_thread.cc
+ env/env.cc
+ env/env_chroot.cc
+ env/env_hdfs.cc
+ env/memenv.cc
memtable/hash_cuckoo_rep.cc
memtable/hash_linklist_rep.cc
memtable/hash_skiplist_rep.cc
+ memtable/memtable_allocator.cc
memtable/skiplistrep.cc
memtable/vectorrep.cc
+ monitoring/histogram.cc
+ monitoring/histogram_windowing.cc
+ monitoring/instrumented_mutex.cc
+ monitoring/iostats_context.cc
+ monitoring/perf_context.cc
+ monitoring/perf_level.cc
+ monitoring/statistics.cc
+ monitoring/thread_status_impl.cc
+ monitoring/thread_status_updater.cc
+ monitoring/thread_status_util.cc
+ monitoring/thread_status_util_debug.cc
+ options/cf_options.cc
+ options/db_options.cc
+ options/options.cc
+ options/options_helper.cc
+ options/options_parser.cc
+ options/options_sanity_check.cc
port/stack_trace.cc
table/adaptive_table_factory.cc
table/block.cc
@@ -214,65 +241,47 @@ set(ROCKSDB_SOURCES
table/format.cc
table/full_filter_block.cc
table/get_context.cc
+ table/index_builder.cc
table/iterator.cc
table/merging_iterator.cc
- table/sst_file_writer.cc
table/meta_blocks.cc
+ table/partitioned_filter_block.cc
+ table/persistent_cache_helper.cc
table/plain_table_builder.cc
table/plain_table_factory.cc
table/plain_table_index.cc
table/plain_table_key_coding.cc
table/plain_table_reader.cc
- table/persistent_cache_helper.cc
+ table/sst_file_writer.cc
table/table_properties.cc
table/two_level_iterator.cc
- tools/sst_dump_tool.cc
tools/db_bench_tool.cc
tools/dump/db_dump_tool.cc
+ tools/ldb_cmd.cc
+ tools/ldb_tool.cc
+ tools/sst_dump_tool.cc
util/arena.cc
+ util/auto_roll_logger.cc
util/bloom.cc
- util/cf_options.cc
- util/clock_cache.cc
util/coding.cc
util/compaction_job_stats_impl.cc
util/comparator.cc
util/concurrent_arena.cc
util/crc32c.cc
- util/db_options.cc
util/delete_scheduler.cc
util/dynamic_bloom.cc
- util/env.cc
- util/env_chroot.cc
- util/env_hdfs.cc
util/event_logger.cc
- util/file_util.cc
util/file_reader_writer.cc
- util/sst_file_manager_impl.cc
+ util/file_util.cc
+ util/filename.cc
util/filter_policy.cc
util/hash.cc
- util/histogram.cc
- util/histogram_windowing.cc
- util/instrumented_mutex.cc
- util/iostats_context.cc
-
- util/lru_cache.cc
- tools/ldb_cmd.cc
- tools/ldb_tool.cc
- util/logging.cc
util/log_buffer.cc
- util/memenv.cc
util/murmurhash.cc
- util/options.cc
- util/options_helper.cc
- util/options_parser.cc
- util/options_sanity_check.cc
- util/perf_context.cc
- util/perf_level.cc
util/random.cc
util/rate_limiter.cc
- util/sharded_cache.cc
util/slice.cc
- util/statistics.cc
+ util/sst_file_manager_impl.cc
util/status.cc
util/status_message.cc
util/string_util.cc
@@ -280,29 +289,29 @@ set(ROCKSDB_SOURCES
util/testutil.cc
util/thread_local.cc
util/threadpool_imp.cc
- util/thread_status_impl.cc
- util/thread_status_updater.cc
- util/thread_status_util.cc
- util/thread_status_util_debug.cc
util/transaction_test_util.cc
util/xxhash.cc
utilities/backupable/backupable_db.cc
utilities/blob_db/blob_db.cc
- utilities/checkpoint/checkpoint.cc
+ utilities/checkpoint/checkpoint_impl.cc
+ utilities/col_buf_decoder.cc
+ utilities/col_buf_encoder.cc
+ utilities/column_aware_encoding_util.cc
utilities/compaction_filters/remove_emptyvalue_compactionfilter.cc
utilities/date_tiered/date_tiered_db_impl.cc
utilities/document/document_db.cc
utilities/document/json_document.cc
utilities/document/json_document_builder.cc
utilities/env_mirror.cc
+ utilities/env_timed.cc
utilities/geodb/geodb_impl.cc
utilities/leveldb_options/leveldb_options.cc
utilities/lua/rocks_lua_compaction_filter.cc
utilities/memory/memory_util.cc
+ utilities/merge_operators/max.cc
+ utilities/merge_operators/put.cc
utilities/merge_operators/string_append/stringappend.cc
utilities/merge_operators/string_append/stringappend2.cc
- utilities/merge_operators/put.cc
- utilities/merge_operators/max.cc
utilities/merge_operators/uint64add.cc
utilities/option_change_migration/option_change_migration.cc
utilities/options/options_util.cc
@@ -315,20 +324,17 @@ set(ROCKSDB_SOURCES
utilities/simulator_cache/sim_cache.cc
utilities/spatialdb/spatial_db.cc
utilities/table_properties_collectors/compact_on_deletion_collector.cc
- utilities/transactions/optimistic_transaction_impl.cc
utilities/transactions/optimistic_transaction_db_impl.cc
+ utilities/transactions/optimistic_transaction_impl.cc
utilities/transactions/transaction_base.cc
- utilities/transactions/transaction_impl.cc
utilities/transactions/transaction_db_impl.cc
utilities/transactions/transaction_db_mutex_impl.cc
+ utilities/transactions/transaction_impl.cc
utilities/transactions/transaction_lock_mgr.cc
utilities/transactions/transaction_util.cc
utilities/ttl/db_ttl_impl.cc
utilities/write_batch_with_index/write_batch_with_index.cc
utilities/write_batch_with_index/write_batch_with_index_internal.cc
- utilities/col_buf_encoder.cc
- utilities/col_buf_decoder.cc
- utilities/column_aware_encoding_util.cc
)
if(WIN32)
@@ -343,8 +349,8 @@ if(WIN32)
else()
list(APPEND ROCKSDB_SOURCES
port/port_posix.cc
- util/env_posix.cc
- util/io_posix.cc)
+ env/env_posix.cc
+ env/io_posix.cc)
endif()
SET(SOURCES)
FOREACH(s ${ROCKSDB_SOURCES})
diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc
index c280e14daf1..ce4aaa2f61c 100644
--- a/storage/rocksdb/ha_rocksdb.cc
+++ b/storage/rocksdb/ha_rocksdb.cc
@@ -797,11 +797,11 @@ static MYSQL_SYSVAR_BOOL(
rocksdb_db_options.use_direct_reads);
static MYSQL_SYSVAR_BOOL(
- use_direct_writes,
- *reinterpret_cast<my_bool *>(&rocksdb_db_options.use_direct_writes),
+ use_direct_io_for_flush_and_compaction,
+ *reinterpret_cast<my_bool *>(&rocksdb_db_options.use_direct_io_for_flush_and_compaction),
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "DBOptions::use_direct_writes for RocksDB", nullptr, nullptr,
- rocksdb_db_options.use_direct_writes);
+ "DBOptions::use_direct_io_for_flush_and_compaction for RocksDB", nullptr, nullptr,
+ rocksdb_db_options.use_direct_io_for_flush_and_compaction);
static MYSQL_SYSVAR_BOOL(
allow_mmap_reads,
@@ -1234,7 +1234,7 @@ static struct st_mysql_sys_var *rocksdb_system_variables[] = {
MYSQL_SYSVAR(wal_size_limit_mb),
MYSQL_SYSVAR(manifest_preallocation_size),
MYSQL_SYSVAR(use_direct_reads),
- MYSQL_SYSVAR(use_direct_writes),
+ MYSQL_SYSVAR(use_direct_io_for_flush_and_compaction),
MYSQL_SYSVAR(allow_mmap_reads),
MYSQL_SYSVAR(allow_mmap_writes),
MYSQL_SYSVAR(is_fd_close_on_exec),
@@ -3361,9 +3361,9 @@ static int rocksdb_init_func(void *const p) {
}
if (rocksdb_db_options.allow_mmap_writes &&
- rocksdb_db_options.use_direct_writes) {
+ rocksdb_db_options.use_direct_io_for_flush_and_compaction) {
// See above comment for allow_mmap_reads. (NO_LINT_DEBUG)
- sql_print_error("RocksDB: Can't enable both use_direct_writes "
+ sql_print_error("RocksDB: Can't enable both use_direct_io_for_flush_and_compaction "
"and allow_mmap_writes\n");
DBUG_RETURN(HA_EXIT_FAILURE);
}
diff --git a/storage/rocksdb/mysql-test/rocksdb/r/use_direct_reads_writes.result b/storage/rocksdb/mysql-test/rocksdb/r/use_direct_reads_writes.result
index 59fb1e41bdd..414e6279ab3 100644
--- a/storage/rocksdb/mysql-test/rocksdb/r/use_direct_reads_writes.result
+++ b/storage/rocksdb/mysql-test/rocksdb/r/use_direct_reads_writes.result
@@ -1,4 +1,4 @@
call mtr.add_suppression("rocksdb");
call mtr.add_suppression("Aborting");
FOUND 1 /enable both use_direct_reads/ in mysqld.1.err
-FOUND 1 /enable both use_direct_writes/ in mysqld.1.err
+FOUND 1 /enable both use_direct_io_for_flush_and_compaction/ in mysqld.1.err
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def
index cff53e6370e..37a6ee15e30 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def
+++ b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def
@@ -63,3 +63,11 @@ autoinc_vars_thread : MDEV-12474 Regularly fails on buildbot
validate_datadic : MDEV-12474 Regularly fails on buildbot
unique_check : MDEV-12474 Regularly fails on buildbot
bloomfilter : MDEV-12474 Regularly fails on buildbot
+
+compact_deletes: MDEV-12663 : rocksdb.compact_deletes times out and causes other tests to fail
+
+col_opt_not_null : MDEV-12474 - Fails in fulltest
+col_opt_null : : MDEV-12474 - Fails in fulltest
+col_opt_unsigned : MDEV-12474 - Fails in fulltest
+col_opt_zerofill : MDEV-12474 - Fails in fulltest
+type_float : MDEV-12474 - Fails in fulltest
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/use_direct_reads_writes.test b/storage/rocksdb/mysql-test/rocksdb/t/use_direct_reads_writes.test
index 87d31d2e2d9..071dbece7b0 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/use_direct_reads_writes.test
+++ b/storage/rocksdb/mysql-test/rocksdb/t/use_direct_reads_writes.test
@@ -36,7 +36,7 @@ source include/search_pattern_in_file.inc;
--exec echo "wait" >$_expect_file_name
shutdown_server 10;
---exec echo "restart:--rocksdb_use_direct_writes=1 --rocksdb_allow_mmap_writes=1" >$_expect_file_name
+--exec echo "restart:--rocksdb_use_direct_io_for_flush_and_compaction=1 --rocksdb_allow_mmap_writes=1" >$_expect_file_name
--sleep 0.1
--exec echo "restart:" >$_expect_file_name
@@ -44,5 +44,5 @@ shutdown_server 10;
--source include/wait_until_connected_again.inc
--disable_reconnect
-let SEARCH_PATTERN=enable both use_direct_writes;
+let SEARCH_PATTERN=enable both use_direct_io_for_flush_and_compaction;
source include/search_pattern_in_file.inc;
diff --git a/storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_io_for_flush_and_compaction_basic.result b/storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_io_for_flush_and_compaction_basic.result
new file mode 100644
index 00000000000..219cdb7319c
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_io_for_flush_and_compaction_basic.result
@@ -0,0 +1,7 @@
+SET @start_global_value = @@global.ROCKSDB_USE_DIRECT_IO_FOR_FLUSH_AND_COMPACTION;
+SELECT @start_global_value;
+@start_global_value
+0
+"Trying to set variable @@global.ROCKSDB_USE_DIRECT_IO_FOR_FLUSH_AND_COMPACTION to 444. It should fail because it is readonly."
+SET @@global.ROCKSDB_USE_DIRECT_IO_FOR_FLUSH_AND_COMPACTION = 444;
+ERROR HY000: Variable 'rocksdb_use_direct_io_for_flush_and_compaction' is a read only variable
diff --git a/storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_writes_basic.result b/storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_writes_basic.result
deleted file mode 100644
index 4cc787e4586..00000000000
--- a/storage/rocksdb/mysql-test/rocksdb_sys_vars/r/rocksdb_use_direct_writes_basic.result
+++ /dev/null
@@ -1,7 +0,0 @@
-SET @start_global_value = @@global.ROCKSDB_USE_DIRECT_WRITES;
-SELECT @start_global_value;
-@start_global_value
-0
-"Trying to set variable @@global.ROCKSDB_USE_DIRECT_WRITES to 444. It should fail because it is readonly."
-SET @@global.ROCKSDB_USE_DIRECT_WRITES = 444;
-ERROR HY000: Variable 'rocksdb_use_direct_writes' is a read only variable
diff --git a/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_use_direct_writes_basic.test b/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_use_direct_io_for_flush_and_compaction_basic.test
index 14e6de24652..91af65377ad 100644
--- a/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_use_direct_writes_basic.test
+++ b/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_use_direct_io_for_flush_and_compaction_basic.test
@@ -1,6 +1,6 @@
--source include/have_rocksdb.inc
---let $sys_var=ROCKSDB_USE_DIRECT_WRITES
+--let $sys_var=ROCKSDB_USE_DIRECT_IO_FOR_FLUSH_AND_COMPACTION
--let $read_only=1
--let $session=0
--source include/rocksdb_sys_var.inc
diff --git a/storage/rocksdb/rocksdb b/storage/rocksdb/rocksdb
-Subproject ba4c77bd6b16ea493c555561ed2e59bdc4c15fc
+Subproject d616ebea23fa88cb9c2c8588533526a566d9cfa
diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt
index ba0797dd422..4f9d2bd2cbb 100644
--- a/storage/xtradb/CMakeLists.txt
+++ b/storage/xtradb/CMakeLists.txt
@@ -510,3 +510,6 @@ MYSQL_ADD_PLUGIN(xtradb ${INNOBASE_SOURCES} STORAGE_ENGINE
IF(TARGET xtradb AND NOT XTRADB_OK)
MESSAGE(FATAL_ERROR "Percona XtraDB is not supported on this platform")
ENDIF()
+
+ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/extra/mariabackup ${CMAKE_BINARY_DIR}/extra/mariabackup)
+
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc
index a6dfad40150..2a46dd4b4c1 100644
--- a/storage/xtradb/api/api0api.cc
+++ b/storage/xtradb/api/api0api.cc
@@ -247,7 +247,7 @@ ib_open_table_by_id(
table = dict_table_open_on_id(table_id, TRUE, DICT_TABLE_OP_NORMAL);
- if (table != NULL && table->ibd_file_missing) {
+ if (table != NULL && table->file_unreadable) {
table = NULL;
}
@@ -272,7 +272,7 @@ ib_open_table_by_name(
table = dict_table_open_on_name(name, FALSE, FALSE,
DICT_ERR_IGNORE_NONE);
- if (table != NULL && table->ibd_file_missing) {
+ if (table != NULL && table->file_unreadable) {
table = NULL;
}
@@ -292,7 +292,7 @@ ib_lookup_table_by_name(
table = dict_table_get_low(name);
- if (table != NULL && table->ibd_file_missing) {
+ if (table != NULL && table->file_unreadable) {
table = NULL;
}
diff --git a/storage/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc
index 48411b6ff6a..d84c93f8b3e 100644
--- a/storage/xtradb/btr/btr0btr.cc
+++ b/storage/xtradb/btr/btr0btr.cc
@@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2014, 2016, MariaDB Corporation
+Copyright (c) 2014, 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
@@ -722,7 +722,6 @@ btr_root_fseg_validate(
/**************************************************************//**
Gets the root node of a tree and x- or s-latches it.
@return root page, x- or s-latched */
-static
buf_block_t*
btr_root_block_get(
/*===============*/
@@ -744,8 +743,7 @@ btr_root_block_get(
if (!block) {
if (index && index->table) {
- index->table->is_encrypted = TRUE;
- index->table->corrupted = FALSE;
+ index->table->file_unreadable = true;
ib_push_warning(index->table->thd, DB_DECRYPTION_FAILED,
"Table %s in tablespace %lu is encrypted but encryption service or"
@@ -760,6 +758,7 @@ btr_root_block_get(
SRV_CORRUPT_TABLE_CHECK(block, return(0););
btr_assert_not_corrupted(block, index);
+
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
@@ -1531,7 +1530,6 @@ btr_node_ptr_set_child_page_no(
/************************************************************//**
Returns the child page of a node pointer and x-latches it.
@return child page, x-latched */
-static
buf_block_t*
btr_node_ptr_get_child(
/*===================*/
@@ -5211,7 +5209,7 @@ btr_validate_index(
page_t* root = btr_root_get(index, &mtr);
- if (root == NULL && index->table->is_encrypted) {
+ if (root == NULL && index->table->file_unreadable) {
err = DB_DECRYPTION_FAILED;
mtr_commit(&mtr);
return err;
diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index 78683f35028..1ea1ec0696b 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -3,7 +3,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2015, MariaDB Corporation.
+Copyright (c) 2015, 2017, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -658,7 +658,10 @@ retry_page_get:
space, zip_size, page_no, rw_latch, guess, buf_mode,
file, line, mtr, &err);
+ /* Note that block==NULL signifies either an error or change
+ buffering. */
if (err != DB_SUCCESS) {
+ ut_ad(block == NULL);
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
@@ -666,7 +669,7 @@ retry_page_get:
" 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;
@@ -944,7 +947,7 @@ btr_cur_open_at_index_side_func(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
dberr_t err = DB_SUCCESS;
-
+
rec_offs_init(offsets_);
estimate = latch_mode & BTR_ESTIMATE;
@@ -988,6 +991,9 @@ btr_cur_open_at_index_side_func(
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr, &err);
+
+ ut_ad((block != NULL) == (err == DB_SUCCESS));
+
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
@@ -996,7 +1002,7 @@ btr_cur_open_at_index_side_func(
" 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 exit_loop;
@@ -1161,6 +1167,8 @@ btr_cur_open_at_rnd_pos_func(
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr, &err);
+ ut_ad((block != NULL) == (err == DB_SUCCESS));
+
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
@@ -1169,8 +1177,9 @@ btr_cur_open_at_rnd_pos_func(
" 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 exit_loop;
}
@@ -3853,6 +3862,8 @@ btr_estimate_n_rows_in_range_on_level(
NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err);
+ ut_ad((block != NULL) == (err == DB_SUCCESS));
+
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
@@ -3861,14 +3872,13 @@ btr_estimate_n_rows_in_range_on_level(
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
- index->table->is_encrypted = true;
+ index->table->file_unreadable = true;
}
mtr_commit(&mtr);
goto inexact;
}
-
page = buf_block_get_frame(block);
/* It is possible that the tree has been reorganized in the
@@ -4010,6 +4020,10 @@ btr_estimate_n_rows_in_range_low(
mtr_commit(&mtr);
+ if (index->table->file_unreadable) {
+ return (0);
+ }
+
mtr_start_trx(&mtr, trx);
#ifdef UNIV_DEBUG
@@ -4360,6 +4374,11 @@ btr_estimate_number_of_different_key_vals(
because otherwise our algorithm would give a wrong estimate
for an index where there is just one key value. */
+ if (index->table->file_unreadable) {
+ mtr_commit(&mtr);
+ goto exit_loop;
+ }
+
page = btr_cur_get_page(&cursor);
SRV_CORRUPT_TABLE_CHECK(page, goto exit_loop;);
diff --git a/storage/xtradb/btr/btr0defragment.cc b/storage/xtradb/btr/btr0defragment.cc
index 3f4185341a6..64dc077d582 100644
--- a/storage/xtradb/btr/btr0defragment.cc
+++ b/storage/xtradb/btr/btr0defragment.cc
@@ -227,7 +227,7 @@ btr_defragment_add_index(
page = buf_block_get_frame(block);
}
- if (page == NULL && index->table->is_encrypted) {
+ if (page == NULL && index->table->file_unreadable) {
mtr_commit(&mtr);
*err = DB_DECRYPTION_FAILED;
return NULL;
diff --git a/storage/xtradb/btr/btr0pcur.cc b/storage/xtradb/btr/btr0pcur.cc
index dd6ef484fc3..0b970e1cf49 100644
--- a/storage/xtradb/btr/btr0pcur.cc
+++ b/storage/xtradb/btr/btr0pcur.cc
@@ -420,6 +420,11 @@ btr_pcur_move_to_next_page(
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
page = btr_pcur_get_page(cursor);
+
+ if (UNIV_UNLIKELY(!page)) {
+ return;
+ }
+
next_page_no = btr_page_get_next(page, mtr);
space = buf_block_get_space(btr_pcur_get_block(cursor));
zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
@@ -429,6 +434,11 @@ btr_pcur_move_to_next_page(
next_block = btr_block_get(space, zip_size, next_page_no,
cursor->latch_mode,
btr_pcur_get_btr_cur(cursor)->index, mtr);
+
+ if (UNIV_UNLIKELY(!next_block)) {
+ return;
+ }
+
next_page = buf_block_get_frame(next_block);
SRV_CORRUPT_TABLE_CHECK(next_page,
diff --git a/storage/xtradb/btr/btr0scrub.cc b/storage/xtradb/btr/btr0scrub.cc
index e9434c9f778..24c84ed301b 100644
--- a/storage/xtradb/btr/btr0scrub.cc
+++ b/storage/xtradb/btr/btr0scrub.cc
@@ -139,6 +139,7 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table,
} else {
return false;
}
+
os_thread_sleep(250000);
time_t now = time(0);
@@ -577,7 +578,7 @@ btr_scrub_table_needs_scrubbing(
return false;
}
- if (table->corrupted) {
+ if (!table->is_readable()) {
return false;
}
diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index 78ebbb7902b..c57dab79ef7 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -65,6 +65,15 @@ Created 11/5/1995 Heikki Tuuri
#include "fil0pagecompress.h"
#include "ha_prototypes.h"
+/** Decrypt a page.
+@param[in,out] bpage Page control block
+@param[in,out] space tablespace
+@return whether the operation was successful */
+static
+bool
+buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
+ MY_ATTRIBUTE((nonnull));
+
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
@@ -548,16 +557,13 @@ buf_block_alloc(
}
#endif /* !UNIV_HOTBACKUP */
-/********************************************************************//**
-Checks if a page is all zeroes.
-@return TRUE if the page is all zeroes */
+/** Check if a page is all zeroes.
+@param[in] read_buf database page
+@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
+@return whether the page is all zeroes */
UNIV_INTERN
bool
-buf_page_is_zeroes(
-/*===============*/
- const byte* read_buf, /*!< in: a database page */
- const ulint zip_size) /*!< in: size of compressed page;
- 0 for uncompressed pages */
+buf_page_is_zeroes(const byte* read_buf, ulint zip_size)
{
const ulint page_size = zip_size ? zip_size : UNIV_PAGE_SIZE;
@@ -673,8 +679,7 @@ buf_page_is_checksum_valid_none(
&& checksum_field1 == BUF_NO_CHECKSUM_MAGIC);
}
-/********************************************************************//**
-Checks if a page is corrupt.
+/** Check if a page is corrupt.
@param[in] check_lsn true if LSN should be checked
@param[in] read_buf Page to be checked
@param[in] zip_size compressed size or 0
@@ -1181,7 +1186,6 @@ buf_block_init(
block->page.buf_fix_count = 0;
block->page.io_fix = BUF_IO_NONE;
block->page.encrypted = false;
- block->page.key_version = 0;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
@@ -2354,7 +2358,17 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(space, zip_size, offset, trx, NULL);
+ dberr_t err = buf_read_page(space, zip_size, offset, trx);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reading compressed page " ULINTPF
+ ":" ULINTPF
+ " failed with error: %s.",
+ space, offset, ut_strerr(err));
+
+ goto err_exit;
+ }
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2960,7 +2974,6 @@ loop:
}
if (block == NULL) {
- buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
@@ -2996,7 +3009,18 @@ loop:
return(NULL);
}
- if (buf_read_page(space, zip_size, offset, trx, &bpage)) {
+ /* Call path is buf_read_page() -> buf_read_page_low()
+ (_fil_io()) -> buf_page_io_complete() ->
+ buf_decrypt_after_read() here fil_space_t* is used
+ and we decrypt -> buf_page_check_corrupt() where
+ page checksums are compared. Decryption/decompression
+ is handled lower level, error handling is handled on lower
+ level, here we need only to know is page really corrupted
+ or encrypted page with correct checksum. */
+
+ dberr_t local_err = buf_read_page(space, zip_size, offset, trx);
+
+ if (local_err == DB_SUCCESS) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr), trx);
@@ -3004,89 +3028,47 @@ loop:
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
- }
-
- /* Do not try again for encrypted pages */
- if (corrupted && bpage->encrypted) {
- ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
- mutex_enter(&buf_pool->LRU_list_mutex);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
-
- if (!buf_LRU_free_page(bpage, true)) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- }
-
- mutex_exit(pmutex);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
-
- return (NULL);
- }
-
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
+ if (err) {
+ *err = local_err;
}
- if (corrupted && !bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR, "Unable"
- " to read tablespace %lu page no"
- " %lu into the buffer pool after"
- " %lu attempts\n"
- "InnoDB: The most probable cause"
- " of this error may be that the"
- " table has been corrupted.\n"
- "InnoDB: You can try to fix this"
- " problem by using"
- " innodb_force_recovery.\n"
- "InnoDB: Please see reference manual"
- " for more details.\n"
- "InnoDB: Aborting...\n",
- space, offset,
- BUF_PAGE_READ_MAX_RETRIES);
-
- ut_error;
- } else {
- ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
- mutex_enter(&buf_pool->LRU_list_mutex);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
-
- if (!buf_LRU_free_page(bpage, true)) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- }
-
- mutex_exit(pmutex);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
+ /* Pages whose encryption key is unavailable or used
+ key, encryption algorithm or encryption method is
+ incorrect are marked as encrypted in
+ buf_page_check_corrupt(). Unencrypted page could be
+ corrupted in a way where the key_id field is
+ nonzero. There is no checksum on field
+ FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION. */
+ if (local_err == DB_DECRYPTION_FAILED) {
+ return (NULL);
+ }
+ /* Try to set table as corrupted instead of
+ asserting. */
+ if (space > TRX_SYS_SPACE &&
+ dict_set_corrupted_by_space(space)) {
return (NULL);
}
+
+ ib_logf(IB_LOG_LEVEL_FATAL, "Unable"
+ " to read tablespace %lu page no"
+ " %lu into the buffer pool after"
+ " %lu attempts"
+ " The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted."
+ " You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery."
+ " Please see " REFMAN " for more"
+ " details. Aborting...",
+ space, offset,
+ BUF_PAGE_READ_MAX_RETRIES);
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -3859,7 +3841,6 @@ buf_page_init_low(
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->encrypted = false;
- bpage->key_version = 0;
bpage->real_size = 0;
HASH_INVALIDATE(bpage, hash);
@@ -4502,86 +4483,81 @@ buf_page_monitor(
/********************************************************************//**
Mark a table with the specified space pointed by bpage->space corrupted.
Also remove the bpage from LRU list.
-@return TRUE if successful */
+@param[in,out] bpage Block */
static
-ibool
+void
buf_mark_space_corrupt(
-/*===================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+ buf_page_t* bpage)
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
ulint space = bpage->space;
- ibool ret = TRUE;
const ulint fold = buf_page_address_fold(bpage->space,
bpage->offset);
prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
+ ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
/* First unfix and release lock on the bpage */
ut_ad(!mutex_own(&buf_pool->LRU_list_mutex));
- if (!bpage->encrypted) {
- mutex_enter(&buf_pool->LRU_list_mutex);
- rw_lock_x_lock(hash_lock);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
+ mutex_enter(&buf_pool->LRU_list_mutex);
+ rw_lock_x_lock(hash_lock);
+ mutex_enter(block_mutex);
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
}
- /* Find the table with specified space id, and mark it corrupted */
- if (dict_set_corrupted_by_space(space)) {
- if (!bpage->encrypted) {
- buf_LRU_free_one_page(bpage);
- }
+ /* If block is not encrypted find the table with specified
+ space id, and mark it corrupted. Encrypted tables
+ are marked unusable later e.g. in ::open(). */
+ if (!bpage->encrypted) {
+ dict_set_corrupted_by_space(space);
} else {
- if (!bpage->encrypted) {
- mutex_exit(buf_page_get_mutex(bpage));
- }
- ret = FALSE;
+ dict_set_encrypted_by_space(space);
}
- if(!bpage->encrypted) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- }
+ /* After this point bpage can't be referenced. This
+ function will release the hash_lock acquired above. */
+ buf_LRU_free_one_page(bpage);
- return(ret);
+ ut_ad(buf_pool->n_pend_reads > 0);
+ os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
+ mutex_exit(&buf_pool->LRU_list_mutex);
}
-/********************************************************************//**
-Check if page is maybe compressed, encrypted or both when we encounter
+/** Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
-@param[in,out] bpage Page
-@return true if page corrupted, false if not */
-UNIV_INTERN
-bool
-buf_page_check_corrupt(
- buf_page_t* bpage)
+@param[in,out] bpage page
+@param[in,out] space tablespace from fil_space_acquire_for_io()
+@return whether the operation succeeded
+@retval DB_SUCCESS if page has been read and is not corrupted
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if accessed tablespace is not found */
+static
+dberr_t
+buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space)
{
+ ut_ad(space->n_pending_ios > 0);
+
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
- ulint space_id = bpage->space;
- fil_space_t* space = fil_space_acquire_silent(space_id);
bool still_encrypted = false;
+ dberr_t err = DB_SUCCESS;
bool corrupted = false;
- ulint page_type = mach_read_from_2(dst_frame + FIL_PAGE_TYPE);
- fil_space_crypt_t* crypt_data = NULL;
-
- ut_ad(space);
- crypt_data = space->crypt_data;
+ fil_space_crypt_t* crypt_data = space->crypt_data;
/* In buf_decrypt_after_read we have either decrypted the page if
page post encryption checksum matches and used key_id is found
@@ -4593,71 +4569,71 @@ buf_page_check_corrupt(
crypt_data->type != CRYPT_SCHEME_UNENCRYPTED &&
!bpage->encrypted &&
fil_space_verify_crypt_checksum(dst_frame, zip_size,
- space, bpage->offset));
-
+ space, bpage->offset));
if (!still_encrypted) {
/* If traditional checksums match, we assume that page is
not anymore encrypted. */
- corrupted = buf_page_is_corrupted(true, dst_frame, zip_size, space);
+ corrupted = buf_page_is_corrupted(true, dst_frame, zip_size,
+ space);
if (!corrupted) {
bpage->encrypted = false;
+ } else {
+ err = DB_PAGE_CORRUPTED;
}
}
/* Pages that we think are unencrypted but do not match the checksum
checks could be corrupted or encrypted or both. */
if (corrupted && !bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "%s: Block in space_id " ULINTPF " in file %s corrupted.",
- page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED ? "Maybe corruption" : "Corruption",
- space_id, (space && space->name) ? space->name : "NULL");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Based on page type %s (" ULINTPF ")",
- fil_get_page_type_name(page_type), page_type);
+ /* An error will be reported by
+ buf_page_io_complete(). */
} else if (still_encrypted || (bpage->encrypted && corrupted)) {
bpage->encrypted = true;
- corrupted = true;
+ err = DB_DECRYPTION_FAILED;
ib_logf(IB_LOG_LEVEL_ERROR,
- "Block in space_id " ULINTPF " in file %s encrypted.",
- space_id, (space && space->name) ? space->name : "NULL");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "However key management plugin or used key_version %u is not found or"
- " used encryption algorithm or method does not match.",
- bpage->key_version);
- if (space_id > TRX_SYS_SPACE) {
- ib_logf(IB_LOG_LEVEL_ERROR,
+ "The page [page id: space=%u"
+ ", page number=%u]"
+ " in file %s cannot be decrypted.",
+ bpage->space, bpage->offset,
+ space->name);
+
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "However key management plugin or used key_version " ULINTPF
+ " is not found or"
+ " used encryption algorithm or method does not match.",
+ mach_read_from_4(dst_frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION));
+
+ if (bpage->space > TRX_SYS_SPACE) {
+ ib_logf(IB_LOG_LEVEL_INFO,
"Marking tablespace as missing. You may drop this table or"
" install correct key management plugin and key file.");
}
}
- if (space) {
- fil_space_release(space);
- }
-
- return corrupted;
+ return (err);
}
-/********************************************************************//**
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool.
-@return true if successful */
+/** Complete a read or write request of a file page to or from the buffer pool.
+@param[in,out] bpage Page to complete
+@return whether the operation succeeded
+@retval DB_SUCCESS always when writing, or if a read page was OK
+@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+ after decryption normal page checksum does
+ not match */
UNIV_INTERN
-bool
-buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+dberr_t
+buf_page_io_complete(buf_page_t* bpage)
{
enum buf_io_fix io_type;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
bool have_LRU_mutex = false;
- fil_space_t* space = NULL;
- byte* frame = NULL;
- bool corrupted = false;
+ byte* frame = NULL;
+ dberr_t err = DB_SUCCESS;
ut_a(buf_page_in_file(bpage));
@@ -4671,10 +4647,17 @@ buf_page_io_complete(
ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
if (io_type == BUF_IO_READ) {
- ulint read_page_no;
- ulint read_space_id;
+ ulint read_page_no = 0;
+ ulint read_space_id = 0;
+ uint key_version = 0;
+
+ ut_ad(bpage->zip.data || ((buf_block_t*)bpage)->frame);
+ fil_space_t* space = fil_space_acquire_for_io(bpage->space);
+ if (!space) {
+ return(DB_TABLESPACE_DELETED);
+ }
- buf_page_decrypt_after_read(bpage);
+ buf_page_decrypt_after_read(bpage, space);
if (buf_page_get_zip_size(bpage)) {
frame = bpage->zip.data;
@@ -4696,10 +4679,11 @@ buf_page_io_complete(
"Page %u in tablespace %u zip_decompress failure.",
bpage->offset, bpage->space);
- corrupted = true;
+ err = DB_PAGE_CORRUPTED;
goto database_corrupted;
}
+
os_atomic_decrement_ulint(&buf_pool->n_pend_unzip, 1);
} else {
ut_a(uncompressed);
@@ -4712,6 +4696,8 @@ buf_page_io_complete(
read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
read_space_id = mach_read_from_4(
frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ key_version = mach_read_from_4(
+ frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
if (bpage->space == TRX_SYS_SPACE
&& buf_dblwr_page_inside(bpage->offset)) {
@@ -4732,12 +4718,11 @@ buf_page_io_complete(
page may contain garbage in MySQL < 4.1.1,
which only supported bpage->space == 0. */
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: space id and page n:o"
- " stored in the page\n"
- "InnoDB: read in are " ULINTPF ":" ULINTPF ","
- " should be %u:%u!\n",
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Space id and page n:o"
+ " stored in the page"
+ " read in are " ULINTPF ":" ULINTPF ","
+ " should be %u:%u!",
read_space_id,
read_page_no,
bpage->space,
@@ -4746,81 +4731,64 @@ buf_page_io_complete(
if (UNIV_LIKELY(!bpage->is_corrupt ||
!srv_pass_corrupt_table)) {
- corrupted = buf_page_check_corrupt(bpage);
-
+ err = buf_page_check_corrupt(bpage, space);
}
database_corrupted:
- if (corrupted) {
+ if (err != DB_SUCCESS) {
/* Not a real corruption if it was triggered by
error injection */
-
DBUG_EXECUTE_IF("buf_page_is_corrupt_failure",
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
+ if (bpage->space > TRX_SYS_SPACE) {
+ buf_mark_space_corrupt(bpage);
ib_logf(IB_LOG_LEVEL_INFO,
"Simulated page corruption");
- return(true);
+ fil_space_release_for_io(space);
+ return(err);
}
+ err = DB_SUCCESS;
goto page_not_corrupt;
);
- if (!bpage->encrypted) {
- fil_system_enter();
- space = fil_space_get_by_id(bpage->space);
- fil_system_exit();
+ if (err == DB_PAGE_CORRUPTED) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Database page corruption on disk"
- " or a failed");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Space %u file %s read of page %u.",
- bpage->space,
- space->name ? space->name : "NULL",
- bpage->offset);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "You may have to recover"
- " from a backup.");
+ " or a failed file read of tablespace %s"
+ " page [page id: space=%u"
+ ", page number=%u]"
+ ". You may have to recover from "
+ "a backup.",
+ space->name,
+ bpage->space, bpage->offset);
buf_page_print(frame, buf_page_get_zip_size(bpage),
BUF_PAGE_PRINT_NO_CRASH);
- ib_logf(IB_LOG_LEVEL_ERROR,
- "It is also possible that your operating"
- "system has corrupted its own file cache.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "and rebooting your computer removes the error.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "If the corrupt page is an index page you can also try to");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "fix the corruption by dumping, dropping, and reimporting");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "the corrupt table. You can use CHECK");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "TABLE to scan your table for corruption.");
- ib_logf(IB_LOG_LEVEL_ERROR,
- "See also "
- REFMAN "forcing-innodb-recovery.html"
- " about forcing recovery.");
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "It is also possible that your"
+ " operating system has corrupted"
+ " its own file cache and rebooting"
+ " your computer removes the error."
+ " If the corrupt page is an index page."
+ " You can also try to fix the"
+ " corruption by dumping, dropping,"
+ " and reimporting the corrupt table."
+ " You can use CHECK TABLE to scan"
+ " your table for corruption. "
+ "Please refer to " REFMAN "forcing-innodb-recovery.html"
+ " for information about forcing recovery.");
}
if (srv_pass_corrupt_table && bpage->space != 0
&& bpage->space < SRV_LOG_SPACE_FIRST_ID) {
- trx_t* trx;
- fprintf(stderr,
- "InnoDB: space %u will be treated as corrupt.\n",
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "InnoDB: space %u will be treated as corrupt.",
bpage->space);
fil_space_set_corrupt(bpage->space);
- trx = innobase_get_trx();
-
- if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) {
- dict_table_set_corrupt_by_space(bpage->space, FALSE);
- } else {
- dict_table_set_corrupt_by_space(bpage->space, TRUE);
- }
-
+ dict_set_corrupted_by_space(bpage->space);
bpage->is_corrupt = TRUE;
}
@@ -4828,31 +4796,13 @@ database_corrupted:
/* If page space id is larger than TRX_SYS_SPACE
(0), we will attempt to mark the corresponding
table as corrupted instead of crashing server */
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
- return(false);
+ if (bpage->space > TRX_SYS_SPACE) {
+ buf_mark_space_corrupt(bpage);
+ fil_space_release_for_io(space);
+ return(err);
} else {
- if (!bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Ending processing because of a corrupt database page.");
-
- ut_error;
- }
-
- ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
- "Table in tablespace %lu encrypted."
- "However key management plugin or used key_id %lu is not found or"
- " used encryption algorithm or method does not match."
- " Can't continue opening the table.",
- bpage->space, bpage->key_version);
-
- if (bpage->encrypted && bpage->space > TRX_SYS_SPACE) {
- buf_mark_space_corrupt(bpage);
- } else {
- ut_error;
- }
-
- return(false);
+ ib_logf(IB_LOG_LEVEL_FATAL,
+ "Ending processing because of a corrupt database page.");
}
}
}
@@ -4872,11 +4822,12 @@ database_corrupted:
if (bpage && bpage->encrypted) {
ib_logf(IB_LOG_LEVEL_WARN,
- "Table in tablespace %lu encrypted."
- "However key management plugin or used key_version %u is not found or"
+ "Table in tablespace " ULINTPF " encrypted."
+ "However key management plugin or used "
+ " key_version %u is not found or"
" used encryption algorithm or method does not match."
- " Can't continue opening the table.\n",
- (ulint)bpage->space, bpage->key_version);
+ " Can't continue opening the table.",
+ read_space_id, key_version);
} else {
ibuf_merge_or_delete_for_page(
@@ -4886,6 +4837,8 @@ database_corrupted:
}
}
+
+ fil_space_release_for_io(space);
} else {
/* io_type == BUF_IO_WRITE */
if (bpage->slot) {
@@ -4998,7 +4951,7 @@ retry_mutex:
mutex_exit(block_mutex);
- return(true);
+ return(err);
}
/*********************************************************************//**
@@ -5026,7 +4979,7 @@ buf_all_freed_instance(
mutex_exit(&buf_pool->LRU_list_mutex);
- if (UNIV_LIKELY_NULL(block) && block->page.key_version == 0) {
+ if (UNIV_LIKELY_NULL(block)) {
fil_space_t* space = fil_space_get(block->page.space);
ib_logf(IB_LOG_LEVEL_ERROR,
"Page %u %u still fixed or dirty.",
@@ -6266,32 +6219,29 @@ buf_page_encrypt_before_write(
switch (bpage->offset) {
case 0:
/* Page 0 of a tablespace is not encrypted/compressed */
- ut_ad(bpage->key_version == 0);
return src_frame;
case TRX_SYS_PAGE_NO:
if (bpage->space == TRX_SYS_SPACE) {
/* don't encrypt/compress page as it contains
address to dblwr buffer */
- bpage->key_version = 0;
return src_frame;
}
}
fil_space_crypt_t* crypt_data = space->crypt_data;
+
const bool encrypted = crypt_data
&& !crypt_data->not_encrypted()
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
|| srv_encrypt_tables);
- if (!encrypted) {
- bpage->key_version = 0;
- }
-
bool page_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags);
if (!encrypted && !page_compressed) {
- /* No need to encrypt or page compress the page */
+ /* No need to encrypt or page compress the page.
+ Clear key-version & crypt-checksum. */
+ memset(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
return src_frame;
}
@@ -6313,9 +6263,6 @@ buf_page_encrypt_before_write(
src_frame,
dst_frame);
- ulint key_version = mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
- ut_ad(key_version == 0 || key_version >= bpage->key_version);
- bpage->key_version = key_version;
bpage->real_size = page_size;
slot->out_buf = dst_frame = tmp;
@@ -6362,16 +6309,17 @@ buf_page_encrypt_before_write(
return dst_frame;
}
-/********************************************************************//**
-Decrypt page after it has been read from disk
-@param[in,out] bpage Page control block
-@return true if successfull, false if something went wrong
-*/
-UNIV_INTERN
+/** Decrypt a page.
+@param[in,out] bpage Page control block
+@param[in,out] space tablespace
+@return whether the operation was successful */
+static
bool
-buf_page_decrypt_after_read(
- buf_page_t* bpage)
+buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
{
+ ut_ad(space->n_pending_ios > 0);
+ ut_ad(space->id == bpage->space);
+
ulint zip_size = buf_page_get_zip_size(bpage);
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
@@ -6384,19 +6332,15 @@ buf_page_decrypt_after_read(
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
bool success = true;
- bpage->key_version = key_version;
-
if (bpage->offset == 0) {
/* File header pages are not encrypted/compressed */
return (true);
}
- fil_space_t* space = fil_space_acquire(bpage->space, true);
-
/* Page is encrypted if encryption information is found from
tablespace and page contains used key_version. This is true
also for pages first compressed and then encrypted. */
- if (!space || !space->crypt_data) {
+ if (!space->crypt_data) {
key_version = 0;
}
@@ -6430,6 +6374,14 @@ buf_page_decrypt_after_read(
decrypt. */
if (!fil_space_verify_crypt_checksum(dst_frame,
zip_size, NULL, bpage->offset)) {
+
+ /* Mark page encrypted in case it should
+ be. */
+ if (space->crypt_data->type
+ != CRYPT_SCHEME_UNENCRYPTED) {
+ bpage->encrypted = true;
+ }
+
return (false);
}
@@ -6441,12 +6393,8 @@ buf_page_decrypt_after_read(
#endif
/* decrypt using crypt_buf to dst_frame */
- byte* res = fil_space_decrypt(space,
- slot->crypt_buf,
- dst_frame,
- &bpage->encrypted);
-
- if (!res) {
+ if (!fil_space_decrypt(space, slot->crypt_buf,
+ dst_frame, &bpage->encrypted)) {
success = false;
}
@@ -6477,8 +6425,6 @@ buf_page_decrypt_after_read(
}
}
- if (space != NULL) {
- fil_space_release(space);
- }
+ ut_ad(space->n_pending_ios > 0);
return (success);
}
diff --git a/storage/xtradb/buf/buf0dblwr.cc b/storage/xtradb/buf/buf0dblwr.cc
index 55c5e4d543a..1c9646c0bd6 100644
--- a/storage/xtradb/buf/buf0dblwr.cc
+++ b/storage/xtradb/buf/buf0dblwr.cc
@@ -493,7 +493,9 @@ buf_dblwr_process()
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
- if (!fil_tablespace_exists_in_mem(space_id)) {
+ FilSpace space(space_id, true);
+
+ if (!space()) {
/* Maybe we have dropped the single-table tablespace
and this page once belonged to it: do nothing */
continue;
@@ -508,8 +510,7 @@ buf_dblwr_process()
continue;
}
- fil_space_t* space = fil_space_found_by_id(space_id);
- ulint zip_size = fil_space_get_zip_size(space_id);
+ ulint zip_size = fsp_flags_get_zip_size(space()->flags);
ut_ad(!buf_page_is_zeroes(page, zip_size));
/* Read in the actual page from the file */
@@ -545,7 +546,7 @@ buf_dblwr_process()
if (fil_space_verify_crypt_checksum(
read_buf, zip_size, NULL, page_no)
|| !buf_page_is_corrupted(
- true, read_buf, zip_size, space)) {
+ true, read_buf, zip_size, space())) {
/* The page is good; there is no need
to consult the doublewrite buffer. */
continue;
diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc
index ffd40157c30..1f5c3993be7 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -873,7 +873,7 @@ buf_flush_write_block_low(
buf_flush_t flush_type, /*!< in: type of flush */
bool sync) /*!< in: true if sync IO request */
{
- fil_space_t* space = fil_space_acquire(bpage->space, true);
+ fil_space_t* space = fil_space_acquire_for_io(bpage->space);
if (!space) {
return;
}
@@ -994,10 +994,23 @@ buf_flush_write_block_low(
if (sync) {
ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE);
fil_flush(space);
+
+ /* The tablespace could already have been dropped,
+ because fil_io(request, sync) would already have
+ decremented the node->n_pending. However,
+ buf_page_io_complete() only needs to look up the
+ tablespace during read requests, not during writes. */
+ ut_ad(buf_page_get_io_fix_unlocked(bpage) == BUF_IO_WRITE);
+
+#ifdef UNIV_DEBUG
+ dberr_t err =
+#endif
buf_page_io_complete(bpage);
+
+ ut_ad(err == DB_SUCCESS);
}
- fil_space_release(space);
+ fil_space_release_for_io(space);
/* Increment the counter of I/O operations used
for selecting LRU policy. */
@@ -2858,7 +2871,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
success = buf_flush_list(PCT_IO(100), LSN_MAX, &n_flushed);
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
- } while (!success || n_flushed > 0);
+ } while (!success || n_flushed > 0 || (IS_XTRABACKUP() && buf_get_n_pending_read_ios() > 0));
/* Some sanity checks */
ut_a(srv_get_active_thread_type() == SRV_NONE);
diff --git a/storage/xtradb/buf/buf0lru.cc b/storage/xtradb/buf/buf0lru.cc
index dff67c0fad6..d979eb44a96 100644
--- a/storage/xtradb/buf/buf0lru.cc
+++ b/storage/xtradb/buf/buf0lru.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, 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
@@ -1501,7 +1502,7 @@ loop:
n_iterations++;
- srv_stats.buf_pool_wait_free.add(n_iterations, 1);
+ srv_stats.buf_pool_wait_free.inc();
/* In case of backoff, do not ever attempt single page flushes
and wait for the cleaner to free some pages instead. */
@@ -1595,7 +1596,7 @@ loop:
++flush_failures;
}
- srv_stats.buf_pool_wait_free.add(n_iterations, 1);
+ srv_stats.buf_pool_wait_free.inc();
n_iterations++;
diff --git a/storage/xtradb/buf/buf0rea.cc b/storage/xtradb/buf/buf0rea.cc
index be2ee56504b..b2b737b8d40 100644
--- a/storage/xtradb/buf/buf0rea.cc
+++ b/storage/xtradb/buf/buf0rea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2013, 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
@@ -103,36 +103,46 @@ flag is cleared and the x-lock released by an i/o-handler thread.
in buf_pool, or if the page is in the doublewrite buffer blocks in
which case it is never read into the pool, or if the tablespace does
not exist or is being dropped
-@return 1 if read request is issued. 0 if it is not */
-UNIV_INTERN
-ulint
-buf_read_page_low(
-/*==============*/
- dberr_t* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
- trying to read from a non-existent tablespace, or a
- tablespace which is just now being dropped */
- bool sync, /*!< in: true if synchronous aio is desired */
- ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
- ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
- at read-ahead functions) */
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size, or 0 */
- ibool unzip, /*!< in: TRUE=request uncompressed page */
- ib_int64_t tablespace_version, /*!< in: if the space memory object has
+
+@param[out] err DB_SUCCESS, DB_TABLESPACE_DELETED if we are
+ trying to read from a non-existent tablespace, or a
+ tablespace which is just now being dropped,
+ DB_PAGE_CORRUPTED if page based on checksum
+ check is corrupted, or DB_DECRYPTION_FAILED
+ if page post encryption checksum matches but
+ after decryption normal page checksum does not match.
+@param[in] sync true if synchronous aio is desired
+@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...,
+ ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
+ at read-ahead functions)
+@param[in] space space id
+@param[in] zip_size compressed page size, or 0
+@param[in] unzip TRUE=request uncompressed page
+@param[in] tablespace_version if the space memory object has
this timestamp different from what we are giving here,
treat the tablespace as dropped; this is a timestamp we
use to stop dangling page reads from a tablespace
- which we have DISCARDed + IMPORTed back */
- ulint offset, /*!< in: page number */
- trx_t* trx, /*!< in: trx */
- buf_page_t** rbpage) /*!< out: page */
+ which we have DISCARDed + IMPORTed back
+@param[in] offset page number
+@param[in] trx transaction
+@return 1 if read request is issued. 0 if it is not */
+static
+ulint
+buf_read_page_low(
+ dberr_t* err,
+ bool sync,
+ ulint mode,
+ ulint space,
+ ulint zip_size,
+ ibool unzip,
+ ib_int64_t tablespace_version,
+ ulint offset,
+ trx_t* trx = NULL)
{
buf_page_t* bpage;
ulint wake_later;
ibool ignore_nonexistent_pages;
- *err = DB_SUCCESS;
-
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
@@ -259,18 +269,13 @@ not_to_recover:
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
- if (!buf_page_io_complete(bpage)) {
- if (rbpage) {
- *rbpage = bpage;
- }
+ *err = buf_page_io_complete(bpage);
+
+ if (*err != DB_SUCCESS) {
return(0);
}
}
- if (rbpage) {
- *rbpage = bpage;
- }
-
return(1);
}
@@ -307,7 +312,7 @@ buf_read_ahead_random(
ulint ibuf_mode;
ulint count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_random_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -402,20 +407,34 @@ read_ahead:
mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(zip_size, i)) {
+
count += buf_read_page_low(
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
- tablespace_version, i, trx, NULL);
- if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Warning: in random"
- " readahead trying to access\n"
- "InnoDB: tablespace %lu page %lu,\n"
- "InnoDB: but the tablespace does not"
- " exist or is just being dropped.\n",
- (ulong) space, (ulong) i);
+ tablespace_version, i, trx);
+
+ switch(err) {
+ case DB_SUCCESS:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "In random"
+ " readahead trying to access"
+ " tablespace " ULINTPF ":" ULINTPF
+ " but the tablespace does not"
+ " exist or is just being dropped.",
+ space, i);
+ break;
+ case DB_DECRYPTION_FAILED:
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Random readahead failed to decrypt page "
+ ULINTPF ":" ULINTPF ".",
+ i, space);
+ break;
+ default:
+ ut_error;
}
}
}
@@ -449,44 +468,60 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space_id space_id
+@param[in] zip_size compressed page size in bytes, or 0
+@param[in] offset page number
+@param[in] trx transaction
+@param[out] encrypted true if page encrypted
+@return DB_SUCCESS if page has been read and is not corrupted,
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */
UNIV_INTERN
-ibool
+dberr_t
buf_read_page(
-/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- trx_t* trx, /*!< in: trx */
- buf_page_t** bpage) /*!< out: page */
+ ulint space_id,
+ ulint zip_size,
+ ulint offset,
+ trx_t* trx)
{
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
- tablespace_version = fil_space_get_version(space);
+ tablespace_version = fil_space_get_version(space_id);
- /* We do the i/o in the synchronous aio mode to save thread
- switches: hence TRUE */
+ FilSpace space(space_id, true);
- count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
+ if (space()) {
+
+ /* We do the i/o in the synchronous aio mode to save thread
+ switches: hence TRUE */
+ count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space_id,
zip_size, FALSE,
- tablespace_version, offset, trx, bpage);
- srv_stats.buf_pool_reads.add(count);
- if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: trying to access"
- " tablespace %lu page no. %lu,\n"
- "InnoDB: but the tablespace does not exist"
- " or is just being dropped.\n",
- (ulong) space, (ulong) offset);
+ tablespace_version, offset, trx);
+
+ srv_stats.buf_pool_reads.add(count);
+ }
+
+ /* Page corruption and decryption failures are already reported
+ in above function. */
+ if (!space() || err == DB_TABLESPACE_DELETED) {
+ err = DB_TABLESPACE_DELETED;
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Trying to access"
+ " tablespace [space=" ULINTPF ": page=" ULINTPF
+ "] but the tablespace does not exist"
+ " or is just being dropped.",
+ space_id, offset);
}
/* Increment number of I/O operations used for LRU policy. */
buf_LRU_stat_inc_io();
- return(count > 0);
+ return(err);
}
/********************************************************************//**
@@ -494,23 +529,23 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+@param[in] space Tablespace id
+@param[in] offset Page no */
UNIV_INTERN
-ibool
+void
buf_read_page_async(
-/*================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
+ ulint space,
+ ulint offset)
{
ulint zip_size;
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
zip_size = fil_space_get_zip_size(space);
if (zip_size == ULINT_UNDEFINED) {
- return(FALSE);
+ return;
}
tablespace_version = fil_space_get_version(space);
@@ -519,7 +554,31 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
- tablespace_version, offset, NULL,NULL);
+ tablespace_version, offset);
+
+ switch(err) {
+ case DB_SUCCESS:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In async page read "
+ "trying to access "
+ "page " ULINTPF ":" ULINTPF
+ " in nonexisting or being-dropped tablespace",
+ space, offset);
+ break;
+
+ case DB_DECRYPTION_FAILED:
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Async page read failed to decrypt page "
+ ULINTPF ":" ULINTPF ".",
+ space, offset);
+ break;
+ default:
+ ut_error;
+ }
+
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -528,8 +587,6 @@ buf_read_page_async(
buffer pool. Since this function is called from buffer pool load
these IOs are deliberate and are not part of normal workload we can
ignore these in our heuristics. */
-
- return(count > 0);
}
/********************************************************************//**
@@ -580,7 +637,7 @@ buf_read_ahead_linear(
ulint fail_count;
ulint ibuf_mode;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_linear_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -784,19 +841,35 @@ buf_read_ahead_linear(
aio mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(zip_size, i)) {
+
count += buf_read_page_low(
&err, false,
ibuf_mode,
- space, zip_size, FALSE, tablespace_version, i, trx, NULL);
- if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Warning: in"
- " linear readahead trying to access\n"
- "InnoDB: tablespace %lu page %lu,\n"
- "InnoDB: but the tablespace does not"
- " exist or is just being dropped.\n",
- (ulong) space, (ulong) i);
+ space, zip_size, FALSE, tablespace_version,
+ i, trx);
+
+ switch(err) {
+ case DB_SUCCESS:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "In linear"
+ " readahead trying to access"
+ " tablespace " ULINTPF ":" ULINTPF
+ " but the tablespace does not"
+ " exist or is just being dropped.",
+ space, i);
+ break;
+
+ case DB_DECRYPTION_FAILED:
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Linear readahead failed to decrypt page "
+ ULINTPF ":" ULINTPF ".",
+ i, space);
+ break;
+ default:
+ ut_error;
}
}
}
@@ -858,9 +931,9 @@ buf_read_ibuf_merge_pages(
#endif
for (i = 0; i < n_stored; i++) {
- dberr_t err;
buf_pool_t* buf_pool;
ulint zip_size = fil_space_get_zip_size(space_ids[i]);
+ dberr_t err = DB_SUCCESS;
buf_pool = buf_pool_get(space_ids[i], page_nos[i]);
@@ -870,23 +943,33 @@ buf_read_ibuf_merge_pages(
}
if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
-
goto tablespace_deleted;
}
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
- page_nos[i], NULL, NULL);
+ page_nos[i], NULL);
+
+ switch(err) {
+ case DB_SUCCESS:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
- if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
/* We have deleted or are deleting the single-table
- tablespace: remove the entries for that page */
-
- ibuf_merge_or_delete_for_page(NULL, space_ids[i],
- page_nos[i],
- zip_size, FALSE);
+ tablespace: remove the entries for tablespace. */
+ ibuf_delete_for_discarded_space(space_ids[i]);
+ break;
+ case DB_DECRYPTION_FAILED:
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Failed to decrypt insert buffer page "
+ ULINTPF ":" ULINTPF ".",
+ space_ids[i], page_nos[i]);
+ break;
+ default:
+ ut_error;
}
}
@@ -924,7 +1007,7 @@ buf_read_recv_pages(
{
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
zip_size = fil_space_get_zip_size(space);
@@ -1013,12 +1096,20 @@ not_to_recover:
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
- page_nos[i], NULL, NULL);
+ page_nos[i], NULL);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
- tablespace_version, page_nos[i], NULL, NULL);
+ tablespace_version, page_nos[i],
+ NULL);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Recovery failed to decrypt read page "
+ ULINTPF ":" ULINTPF ".",
+ space, page_nos[i]);
}
}
diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc
index 1ada35a89a2..6d5b12474eb 100644
--- a/storage/xtradb/dict/dict0crea.cc
+++ b/storage/xtradb/dict/dict0crea.cc
@@ -692,7 +692,7 @@ dict_create_index_tree_step(
dberr_t err = DB_SUCCESS;
ulint zip_size = dict_table_zip_size(index->table);
- if (node->index->table->ibd_file_missing
+ if (node->index->table->file_unreadable
|| dict_table_is_discarded(node->index->table)) {
node->page_no = FIL_NULL;
diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index 49de1cf7ef8..bc46bcab63b 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -1185,47 +1185,42 @@ dict_table_open_on_name(
if (table != NULL) {
- /* If table is encrypted return table */
+ /* If table is encrypted or corrupted */
if (ignore_err == DICT_ERR_IGNORE_NONE
- && table->is_encrypted) {
+ && !table->is_readable()) {
/* Make life easy for drop table. */
if (table->can_be_evicted) {
dict_table_move_from_lru_to_non_lru(table);
}
- if (table->can_be_evicted) {
- dict_move_to_mru(table);
- }
+ if (table->corrupted) {
- ++table->n_ref_count;
+ if (!dict_locked) {
+ mutex_exit(&dict_sys->mutex);
+ }
- if (!dict_locked) {
- mutex_exit(&dict_sys->mutex);
- }
+ char buf[MAX_FULL_NAME_LEN];
+ ut_format_name(table->name, TRUE, buf, sizeof(buf));
- return (table);
- }
- /* If table is corrupted, return NULL */
- else if (ignore_err == DICT_ERR_IGNORE_NONE
- && table->corrupted) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Table %s is corrupted. Please "
+ "drop the table and recreate.",
+ buf);
+
+ return(NULL);
+ }
- /* Make life easy for drop table. */
if (table->can_be_evicted) {
- dict_table_move_from_lru_to_non_lru(table);
+ dict_move_to_mru(table);
}
+ ++table->n_ref_count;
+
if (!dict_locked) {
mutex_exit(&dict_sys->mutex);
}
- ut_print_timestamp(stderr);
-
- fprintf(stderr, " InnoDB: table ");
- ut_print_name(stderr, NULL, TRUE, table->name);
- fprintf(stderr, "is corrupted. Please drop the table "
- "and recreate\n");
-
- return(NULL);
+ return (table);
}
if (table->can_be_evicted) {
@@ -6183,11 +6178,29 @@ dict_set_corrupted_by_space(
/* mark the table->corrupted bit only, since the caller
could be too deep in the stack for SYS_INDEXES update */
- table->corrupted = TRUE;
+ table->corrupted = true;
+ table->file_unreadable = true;
return(TRUE);
}
+
+/** Flags a table with specified space_id encrypted in the data dictionary
+cache
+@param[in] space_id Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(ulint space_id)
+{
+ dict_table_t* table;
+
+ table = dict_find_table_by_space(space_id);
+
+ if (table) {
+ table->file_unreadable = true;
+ }
+}
+
/**********************************************************************//**
Flags an index corrupted both in the data dictionary cache
and in the SYS_INDEXES */
@@ -6325,43 +6338,6 @@ dict_set_corrupted_index_cache_only(
index->type |= DICT_CORRUPT;
}
-/*************************************************************************
-set is_corrupt flag by space_id*/
-
-void
-dict_table_set_corrupt_by_space(
-/*============================*/
- ulint space_id,
- ibool need_mutex)
-{
- dict_table_t* table;
- ibool found = FALSE;
-
- ut_a(space_id != 0 && space_id < SRV_LOG_SPACE_FIRST_ID);
-
- if (need_mutex)
- mutex_enter(&(dict_sys->mutex));
-
- table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
-
- while (table) {
- if (table->space == space_id) {
- table->is_corrupt = TRUE;
- found = TRUE;
- }
-
- table = UT_LIST_GET_NEXT(table_LRU, table);
- }
-
- if (need_mutex)
- mutex_exit(&(dict_sys->mutex));
-
- if (!found) {
- fprintf(stderr, "InnoDB: space to be marked as "
- "crashed was not found for id " ULINTPF ".\n",
- space_id);
- }
-}
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
@@ -6683,7 +6659,8 @@ dict_table_schema_check(
}
}
- if (table->ibd_file_missing) {
+ if (!table->is_readable() &&
+ fil_space_get(table->space) == NULL) {
/* missing tablespace */
ut_snprintf(errstr, errstr_sz,
diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc
index b843891f16c..4991c4f3fcc 100644
--- a/storage/xtradb/dict/dict0load.cc
+++ b/storage/xtradb/dict/dict0load.cc
@@ -945,6 +945,10 @@ dict_insert_tablespace_and_filepath(
return(err);
}
+/* Set by Xtrabackup */
+my_bool (*dict_check_if_skip_table)(const char* name) = 0;
+
+
/********************************************************************//**
This function looks at each table defined in SYS_TABLES. It checks the
tablespace for any table with a space_id > 0. It looks up the tablespace
@@ -1064,6 +1068,9 @@ loop:
bool is_temp = false;
bool discarded = false;
+ bool print_error_if_does_not_exist;
+ bool remove_from_data_dict_if_does_not_exist;
+
ib_uint32_t flags2 = static_cast<ib_uint32_t>(
mach_read_from_4(field));
@@ -1089,6 +1096,19 @@ loop:
goto loop;
}
+
+ ut_a(!IS_XTRABACKUP() || dict_check_if_skip_table);
+
+ if (is_temp || discarded ||
+ (IS_XTRABACKUP() && dict_check_if_skip_table(name))) {
+ print_error_if_does_not_exist = false;
+ }
+ else {
+ print_error_if_does_not_exist = true;
+ }
+
+ remove_from_data_dict_if_does_not_exist = IS_XTRABACKUP() && !(is_temp || discarded);
+
mtr_commit(&mtr);
switch (dict_check) {
@@ -1096,8 +1116,8 @@ loop:
/* All tablespaces should have been found in
fil_load_single_table_tablespaces(). */
if (fil_space_for_table_exists_in_mem(
- space_id, name, !(is_temp || discarded),
- false, NULL, 0, flags)
+ space_id, name, print_error_if_does_not_exist,
+ remove_from_data_dict_if_does_not_exist , false, NULL, 0, flags)
&& !(is_temp || discarded)) {
/* If user changes the path of .ibd files in
*.isl files before doing crash recovery ,
@@ -1130,7 +1150,7 @@ loop:
trx_resurrect_table_locks(). */
if (fil_space_for_table_exists_in_mem(
space_id, name, false,
- false, NULL, 0, flags)) {
+ false, false, NULL, 0, flags)) {
break;
}
/* fall through */
@@ -1964,7 +1984,7 @@ dict_load_indexes(
dict_mem_index_free(index);
goto func_exit;
} else if (index->page == FIL_NULL
- && !table->ibd_file_missing
+ && !table->file_unreadable
&& (!(index->type & DICT_FTS))) {
fprintf(stderr,
@@ -2193,7 +2213,7 @@ err_len:
(*table)->id = mach_read_from_8(field);
- (*table)->ibd_file_missing = FALSE;
+ (*table)->file_unreadable = false;
return(NULL);
}
@@ -2380,15 +2400,15 @@ err_exit:
"Table '%s' tablespace is set as discarded.",
table_name);
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
} else if (!fil_space_for_table_exists_in_mem(
- table->space, name, false, true, heap,
+ table->space, name, false, IS_XTRABACKUP(), true, heap,
table->id, table->flags)) {
if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) {
/* Do not bother to retry opening temporary tables. */
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
} else {
if (!(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)) {
@@ -2423,8 +2443,9 @@ err_exit:
/* We failed to find a sensible
tablespace file */
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
}
+
if (filepath) {
mem_free(filepath);
}
@@ -2448,9 +2469,10 @@ err_exit:
were not allowed while the table is being locked by a transaction. */
dict_err_ignore_t index_load_err =
!(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)
- && table->ibd_file_missing
+ && table->file_unreadable
? DICT_ERR_IGNORE_ALL
: ignore_err;
+
err = dict_load_indexes(table, heap, index_load_err);
if (err == DB_INDEX_CORRUPT) {
@@ -2485,7 +2507,7 @@ err_exit:
of the error condition, since the user may want to dump data from the
clustered index. However we load the foreign key information only if
all indexes were loaded. */
- if (!cached || table->ibd_file_missing) {
+ if (!cached || table->file_unreadable) {
/* Don't attempt to load the indexes from disk. */
} else if (err == DB_SUCCESS) {
err = dict_load_foreigns(table->name, NULL, true, true,
@@ -2518,12 +2540,12 @@ err_exit:
table = NULL;
} else if (dict_index_is_corrupted(index)
- && !table->ibd_file_missing) {
+ && !table->file_unreadable) {
/* It is possible we force to load a corrupted
clustered index if srv_load_corrupted is set.
Mark the table as corrupted in this case */
- table->corrupted = TRUE;
+ table->corrupted = true;
}
}
@@ -2532,7 +2554,7 @@ func_exit:
ut_ad(!table
|| ignore_err != DICT_ERR_IGNORE_NONE
- || table->ibd_file_missing
+ || table->file_unreadable
|| !table->corrupted);
if (table && table->fts) {
diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc
index bde72b83c54..fa7177c5137 100644
--- a/storage/xtradb/dict/dict0mem.cc
+++ b/storage/xtradb/dict/dict0mem.cc
@@ -2,6 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2013, 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
@@ -137,8 +138,6 @@ dict_mem_table_create(
table->fts = NULL;
}
- table->is_corrupt = FALSE;
-
#endif /* !UNIV_HOTBACKUP */
new(&table->foreign_set) dict_foreign_set();
diff --git a/storage/xtradb/dict/dict0stats.cc b/storage/xtradb/dict/dict0stats.cc
index 33b6c2e23e0..d2e9a2618c0 100644
--- a/storage/xtradb/dict/dict0stats.cc
+++ b/storage/xtradb/dict/dict0stats.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved.
+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
@@ -920,7 +921,11 @@ dict_stats_update_transient_for_index(
index->stat_n_leaf_pages = size;
- btr_estimate_number_of_different_key_vals(index);
+ /* Do not continue if table decryption has failed or
+ table is already marked as corrupted. */
+ if (index->is_readable()) {
+ btr_estimate_number_of_different_key_vals(index);
+ }
}
}
@@ -974,8 +979,9 @@ dict_stats_update_transient(
continue;
}
- /* Do not continue if table decryption has failed. */
- if (index->table->is_encrypted) {
+ /* Do not continue if table decryption has failed or
+ table is already marked as corrupted. */
+ if (!index->is_readable()) {
break;
}
@@ -2437,6 +2443,61 @@ dict_stats_save_index_stat(
return(ret);
}
+/** Report error if statistic update for a table failed because
+.ibd file is missing, table decryption failed or table is corrupted.
+@param[in,out] table Table
+@param[in] defragment true if statistics is for defragment
+@return DB_DECRYPTION_FAILED, DB_TABLESPACE_DELETED or DB_CORRUPTION
+@retval DB_DECRYPTION_FAILED if decryption of the table failed
+@retval DB_TABLESPACE_DELETED if .ibd file is missing
+@retval DB_CORRUPTION if table is marked as corrupted */
+static
+dberr_t
+dict_stats_report_error(
+ dict_table_t* table,
+ bool defragment = false)
+{
+ char buf[3 * NAME_LEN];
+ dberr_t err;
+
+ innobase_format_name(buf, sizeof buf,
+ table->name,
+ true);
+
+ FilSpace space(table->space);
+
+ if (space()) {
+ if (table->corrupted) {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Cannot save%s statistics because "
+ " table %s in file %s is corrupted.",
+ defragment ? " defragment" : " ",
+ buf, space()->chain.start->name);
+ err = DB_CORRUPTION;
+ } else {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Cannot save%s statistics because "
+ " table %s in file %s can't be decrypted.",
+ defragment ? " defragment" : " ",
+ buf, space()->chain.start->name);
+ err = DB_DECRYPTION_FAILED;
+ }
+ } else {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Cannot save%s statistics for "
+ " table %s because .ibd file is missing."
+ " For help, please "
+ "refer to " REFMAN "innodb-troubleshooting.html.",
+ defragment ? " defragment" : " ",
+ buf);
+ err = DB_TABLESPACE_DELETED;
+ }
+
+ dict_stats_empty_table(table, defragment);
+
+ return (err);
+}
+
/** Save the table's statistics into the persistent statistics storage.
@param[in] table_orig table whose stats to save
@param[in] only_for_index if this is non-NULL, then stats for indexes
@@ -2457,6 +2518,11 @@ dict_stats_save(
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
+ if (table_orig->is_readable()) {
+ } else {
+ return (dict_stats_report_error(table_orig));
+ }
+
table = dict_stats_snapshot_create(table_orig);
dict_fs2utf8(table->name, db_utf8, sizeof(db_utf8),
@@ -3192,15 +3258,8 @@ dict_stats_update(
ut_ad(!mutex_own(&dict_sys->mutex));
- if (table->ibd_file_missing) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: cannot calculate statistics for table %s "
- "because the .ibd file is missing. For help, please "
- "refer to " REFMAN "innodb-troubleshooting.html\n",
- ut_format_name(table->name, TRUE, buf, sizeof(buf)));
- dict_stats_empty_table(table, true);
- return(DB_TABLESPACE_DELETED);
+ if (!table->is_readable()) {
+ return (dict_stats_report_error(table));
} else if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
/* If we have set a high innodb_force_recovery level, do
not calculate statistics, as a badly corrupted index can
@@ -3946,19 +4005,10 @@ dict_stats_save_defrag_stats(
{
dberr_t ret;
- if (index->table->ibd_file_missing) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save defragment stats because "
- ".ibd file is missing.\n");
- return (DB_TABLESPACE_DELETED);
- }
- if (dict_index_is_corrupted(index)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save defragment stats because "
- "index is corrupted.\n");
- return(DB_CORRUPTION);
+
+ if (index->is_readable()) {
+ } else {
+ return (dict_stats_report_error(index->table, true));
}
if (dict_index_is_univ(index)) {
diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc
index f37d5e19ad6..e27e93244ae 100644
--- a/storage/xtradb/fil/fil0crypt.cc
+++ b/storage/xtradb/fil/fil0crypt.cc
@@ -479,11 +479,12 @@ Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
@param[in] block buffer block
@return position on log buffer */
UNIV_INTERN
-const byte*
+byte*
fil_parse_write_crypt_data(
- const byte* ptr,
+ byte* ptr,
const byte* end_ptr,
- const buf_block_t* block)
+ const buf_block_t* block,
+ dberr_t* err)
{
/* check that redo log entry is complete */
size_t entry_size =
@@ -495,6 +496,8 @@ fil_parse_write_crypt_data(
4 + // size of key_id
1; // fil_encryption_t
+ *err = DB_SUCCESS;
+
if (ptr + entry_size > end_ptr) {
return NULL;
}
@@ -534,11 +537,16 @@ fil_parse_write_crypt_data(
ptr += len;
/* update fil_space memory cache with crypt_data */
- fil_space_t* space = fil_space_acquire_silent(space_id);
-
- if (space) {
+ if (fil_space_t* space = fil_space_acquire_silent(space_id)) {
crypt_data = fil_space_set_crypt_data(space, crypt_data);
fil_space_release(space);
+ /* Check is used key found from encryption plugin */
+ if (crypt_data->should_encrypt()
+ && !crypt_data->is_key_found()) {
+ *err = DB_DECRYPTION_FAILED;
+ }
+ } else {
+ fil_space_destroy_crypt_data(&crypt_data);
}
return ptr;
@@ -675,7 +683,7 @@ fil_space_encrypt(
}
fil_space_crypt_t* crypt_data = space->crypt_data;
- ut_ad(space->n_pending_ops);
+ ut_ad(space->n_pending_ios > 0);
ulint zip_size = fsp_flags_get_zip_size(space->flags);
byte* tmp = fil_encrypt_buf(crypt_data, space->id, offset, lsn, src_frame, zip_size, dst_frame);
@@ -710,10 +718,12 @@ fil_space_encrypt(
}
bool corrupted = buf_page_is_corrupted(true, tmp_mem, zip_size, space);
+ memcpy(tmp_mem+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, src+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 8);
bool different = memcmp(src, tmp_mem, size);
if (!ok || corrupted || corrupted1 || err != DB_SUCCESS || different) {
- fprintf(stderr, "ok %d corrupted %d corrupted1 %d err %d different %d\n", ok , corrupted, corrupted1, err, different);
+ fprintf(stderr, "ok %d corrupted %d corrupted1 %d err %d different %d\n",
+ ok , corrupted, corrupted1, err, different);
fprintf(stderr, "src_frame\n");
buf_page_print(src_frame, zip_size, BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr, "encrypted_frame\n");
@@ -768,25 +778,6 @@ fil_space_decrypt(
return false;
}
- if (crypt_data == NULL) {
- if (!(space == 0 && offset == 0) && key_version != 0) {
- /* FIL_PAGE_FILE_FLUSH_LSN field i.e.
- FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
- should be only defined for the
- first page in a system tablespace
- data file (ibdata*, not *.ibd), if not
- clear it. */
-
- DBUG_PRINT("ib_crypt",
- ("Page on space %lu offset %lu has key_version %u"
- " when it shoud be undefined.",
- space, offset, key_version));
-
- mach_write_to_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0);
- }
- return false;
- }
-
ut_a(crypt_data != NULL && crypt_data->is_encrypted());
/* read space & lsn */
@@ -838,9 +829,6 @@ fil_space_decrypt(
memcpy(tmp_frame + page_size - FIL_PAGE_DATA_END,
src_frame + page_size - FIL_PAGE_DATA_END,
FIL_PAGE_DATA_END);
-
- // clear key-version & crypt-checksum from dst
- memset(tmp_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
}
srv_stats.pages_decrypted.inc();
@@ -872,7 +860,7 @@ fil_space_decrypt(
*decrypted = false;
ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted());
- ut_ad(space->n_pending_ops > 0);
+ ut_ad(space->n_pending_ios > 0);
bool encrypted = fil_space_decrypt(
space->crypt_data,
@@ -962,11 +950,12 @@ fil_space_verify_crypt_checksum(
/* If page is not encrypted, return false */
if (key_version == 0) {
- return false;
+ return(false);
}
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
+
/* If no checksum is used, can't continue checking. */
if (algorithm == SRV_CHECKSUM_ALGORITHM_NONE) {
return(true);
@@ -990,28 +979,31 @@ fil_space_verify_crypt_checksum(
return (true);
}
- /* Compressed pages use different checksum method. We first store
- the post encryption checksum on checksum location and after function
- restore the original. */
- if (zip_size) {
- ib_uint32_t old = static_cast<ib_uint32_t>(mach_read_from_4(
- page + FIL_PAGE_SPACE_OR_CHKSUM));
-
- mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, checksum);
+ ib_uint32_t cchecksum1 = 0;
+ ib_uint32_t cchecksum2 = 0;
- bool valid = page_zip_verify_checksum(page, zip_size);
+ /* Calculate checksums */
+ if (zip_size) {
+ cchecksum1 = page_zip_calc_checksum(
+ page, zip_size, SRV_CHECKSUM_ALGORITHM_CRC32);
- mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, old);
+ if(cchecksum1 != checksum) {
+ cchecksum2 = page_zip_calc_checksum(
+ page, zip_size,
+ SRV_CHECKSUM_ALGORITHM_INNODB);
+ }
+ } else {
+ cchecksum1 = buf_calc_page_crc32(page);
- return (valid);
+ if (cchecksum1 != checksum) {
+ cchecksum2 = (ib_uint32_t) buf_calc_page_new_checksum(
+ page);
+ }
}
/* If stored checksum matches one of the calculated checksums
page is not corrupted. */
- ib_uint32_t cchecksum1 = buf_calc_page_crc32(page);
- ib_uint32_t cchecksum2 = (ib_uint32_t) buf_calc_page_new_checksum(
- page);
bool encrypted = (checksum == cchecksum1 || checksum == cchecksum2
|| checksum == BUF_NO_CHECKSUM_MAGIC);
@@ -1042,13 +1034,19 @@ fil_space_verify_crypt_checksum(
ulint checksum1 = mach_read_from_4(
page + FIL_PAGE_SPACE_OR_CHKSUM);
- ulint checksum2 = mach_read_from_4(
- page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
+ ulint checksum2 = checksum1;
+ bool valid;
- bool valid = (buf_page_is_checksum_valid_crc32(page,checksum1,checksum2)
+ if (zip_size) {
+ valid = (checksum1 == cchecksum1);
+ } else {
+ checksum1 = mach_read_from_4(
+ page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
+ valid = (buf_page_is_checksum_valid_crc32(page,checksum1,checksum2)
|| buf_page_is_checksum_valid_none(page,checksum1,checksum2)
|| buf_page_is_checksum_valid_innodb(page,checksum1, checksum2));
+ }
if (encrypted && valid) {
/* If page is encrypted and traditional checksums match,
@@ -1964,11 +1962,11 @@ fil_crypt_rotate_page(
bool modified = false;
int needs_scrubbing = BTR_SCRUB_SKIP_PAGE;
lsn_t block_lsn = block->page.newest_modification;
- uint kv = block->page.key_version;
+ byte* frame = buf_block_get_frame(block);
+ uint kv = mach_read_from_4(frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
/* check if tablespace is closing after reading page */
- if (space->is_stopping()) {
- byte* frame = buf_block_get_frame(block);
+ if (!space->is_stopping()) {
if (kv == 0 &&
fil_crypt_is_page_uninitialized(frame, zip_size)) {
@@ -1978,11 +1976,6 @@ fil_crypt_rotate_page(
kv, key_state->key_version,
key_state->rotate_key_age)) {
- /* page can be "fresh" i.e never written in case
- * kv == 0 or it should have a key version at least
- * as big as the space minimum key version*/
- ut_a(kv == 0 || kv >= crypt_data->min_key_version);
-
modified = true;
/* force rotation by dummy updating page */
@@ -1990,16 +1983,10 @@ fil_crypt_rotate_page(
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
space_id, MLOG_4BYTES, &mtr);
- /* update block */
- block->page.key_version = key_state->key_version;
-
/* statistics */
state->crypt_stat.pages_modified++;
} else {
if (crypt_data->is_encrypted()) {
- ut_a(kv >= crypt_data->min_key_version ||
- (kv == 0 && key_state->key_version == 0));
-
if (kv < state->min_key_version_found) {
state->min_key_version_found = kv;
}
@@ -2083,6 +2070,11 @@ fil_crypt_rotate_page(
state->end_lsn = block_lsn;
}
}
+ } else {
+ /* If block read failed mtr memo and log should be empty. */
+ ut_ad(dyn_array_get_data_size(&mtr.memo) == 0);
+ ut_ad(dyn_array_get_data_size(&mtr.log) == 0);
+ mtr_commit(&mtr);
}
if (sleeptime_ms) {
@@ -2266,6 +2258,11 @@ fil_crypt_complete_rotate_space(
crypt_data->rotate_state.flushing = false;
mutex_exit(&crypt_data->mutex);
}
+ } else {
+ mutex_enter(&crypt_data->mutex);
+ ut_a(crypt_data->rotate_state.active_threads > 0);
+ crypt_data->rotate_state.active_threads--;
+ mutex_exit(&crypt_data->mutex);
}
}
@@ -2551,8 +2548,9 @@ fil_space_crypt_close_tablespace(
if (now >= last + 30) {
ib_logf(IB_LOG_LEVEL_WARN,
- "Waited %ld seconds to drop space: %s(" ULINTPF ").",
- now - start, space->name, space->id);
+ "Waited %ld seconds to drop space: %s (" ULINTPF
+ ") active threads %u flushing=%d.",
+ now - start, space->name, space->id, cnt, flushing);
last = now;
}
}
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index e504ab3947e..e39be46840c 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2014, 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
@@ -67,9 +67,11 @@ static ulint srv_data_read, srv_data_written;
#include <fcntl.h>
#endif
#include "row0mysql.h"
+#include "trx0purge.h"
MYSQL_PLUGIN_IMPORT extern my_bool lower_case_file_system;
+
/*
IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
=============================================
@@ -247,18 +249,16 @@ fil_node_complete_io(
ulint type); /*!< in: OS_FILE_WRITE or OS_FILE_READ; marks
the node as modified if
type == OS_FILE_WRITE */
-/*******************************************************************//**
-Frees a space object from the tablespace memory cache. Closes the files in
-the chain but does not delete them. There must not be any pending i/o's or
+/** Free a space object from the tablespace memory cache. Close the files in
+the chain but do not delete them. There must not be any pending i/o's or
flushes on the files.
-@return TRUE on success */
+The fil_system->mutex will be released.
+@param[in] id tablespace ID
+@param[in] x_latched whether the caller holds exclusive space->latch
+@return whether the tablespace existed */
static
-ibool
-fil_space_free(
-/*===========*/
- ulint id, /* in: space id */
- ibool x_latched); /* in: TRUE if caller has space->latch
- in X mode */
+bool
+fil_space_free_and_mutex_exit(ulint id, bool x_latched);
/********************************************************************//**
Reads data from a space to a buffer. Remember that the possible incomplete
blocks at the end of file are ignored: they are not taken into account when
@@ -330,7 +330,11 @@ fil_write(
}
/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
+Returns the table space by a given id, NULL if not found.
+It is unsafe to dereference the returned pointer. It is fine to check
+for NULL.
+@param[in] id Tablespace id
+@return table space or NULL */
fil_space_t*
fil_space_get_by_id(
/*================*/
@@ -350,26 +354,6 @@ fil_space_get_by_id(
return(space);
}
-/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
-fil_space_t*
-fil_space_found_by_id(
-/*==================*/
- ulint id) /*!< in: space id */
-{
- fil_space_t* space = NULL;
- mutex_enter(&fil_system->mutex);
- space = fil_space_get_by_id(id);
-
- /* Not found if space is being deleted */
- if (space && space->stop_new_ops) {
- space = NULL;
- }
-
- mutex_exit(&fil_system->mutex);
- return space;
-}
-
/****************************************************************//**
Get space id from fil node */
ulint
@@ -385,7 +369,6 @@ fil_node_get_space_id(
/*******************************************************************//**
Returns the table space by a given name, NULL if not found. */
-UNIV_INLINE
fil_space_t*
fil_space_get_by_name(
/*==================*/
@@ -1384,18 +1367,14 @@ retry:
}
}
-/*******************************************************************//**
-Frees a file node object from a tablespace memory cache. */
+/** Prepare a data file object for freeing.
+@param[in,out] space tablespace
+@param[in,out] node data file */
static
void
-fil_node_free(
-/*==========*/
- fil_node_t* node, /*!< in, own: file node */
- fil_system_t* system, /*!< in: tablespace memory cache */
- fil_space_t* space) /*!< in: space where the file node is chained */
+fil_node_free_part1(fil_space_t* space, fil_node_t* node)
{
- ut_ad(node && system && space);
- ut_ad(mutex_own(&(system->mutex)));
+ ut_ad(mutex_own(&fil_system->mutex));
ut_a(node->magic_n == FIL_NODE_MAGIC_N);
ut_a(node->n_pending == 0);
ut_a(!node->being_extended);
@@ -1418,12 +1397,22 @@ fil_node_free(
space->is_in_unflushed_spaces = false;
UT_LIST_REMOVE(unflushed_spaces,
- system->unflushed_spaces,
+ fil_system->unflushed_spaces,
space);
}
- fil_node_close_file(node, system);
+ fil_node_close_file(node, fil_system);
}
+}
+
+/** Free a data file object.
+@param[in,out] space tablespace
+@param[in] node data file */
+static
+void
+fil_node_free_part2(fil_space_t* space, fil_node_t* node)
+{
+ ut_ad(!node->open);
space->size -= node->size;
@@ -1463,7 +1452,8 @@ fil_space_truncate_start(
trunc_len -= node->size * UNIV_PAGE_SIZE;
- fil_node_free(node, fil_system, space);
+ fil_node_free_part1(space, node);
+ fil_node_free_part2(space, node);
}
mutex_exit(&fil_system->mutex);
@@ -1555,10 +1545,9 @@ fil_space_create(
"from the cache with id %lu",
name, (ulong) id);
- ibool success = fil_space_free(space->id, FALSE);
+ bool success = fil_space_free_and_mutex_exit(
+ space->id, false);
ut_a(success);
-
- mutex_exit(&fil_system->mutex);
}
} while (space != 0);
@@ -1590,12 +1579,13 @@ fil_space_create(
if (!fil_system->space_id_reuse_warned) {
fil_system->space_id_reuse_warned = TRUE;
-
- ib_logf(IB_LOG_LEVEL_WARN,
- "Allocated tablespace %lu, old maximum "
- "was %lu",
- (ulong) id,
- (ulong) fil_system->max_assigned_id);
+ if (!IS_XTRABACKUP()) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Allocated tablespace %lu, old maximum "
+ "was %lu",
+ (ulong)id,
+ (ulong)fil_system->max_assigned_id);
+ }
}
fil_system->max_assigned_id = id;
@@ -1712,19 +1702,16 @@ fil_assign_new_space_id(
return(success);
}
-/*******************************************************************//**
-Frees a space object from the tablespace memory cache. Closes the files in
-the chain but does not delete them. There must not be any pending i/o's or
+/** Free a space object from the tablespace memory cache. Close the files in
+the chain but do not delete them. There must not be any pending i/o's or
flushes on the files.
-@return TRUE if success */
+The fil_system->mutex will be released.
+@param[in] id tablespace ID
+@param[in] x_latched whether the caller holds exclusive space->latch
+@return whether the tablespace existed */
static
-ibool
-fil_space_free(
-/*===========*/
- /* out: TRUE if success */
- ulint id, /* in: space id */
- ibool x_latched) /* in: TRUE if caller has space->latch
- in X mode */
+bool
+fil_space_free_and_mutex_exit(ulint id, bool x_latched)
{
fil_space_t* space;
fil_space_t* fnamespace;
@@ -1734,13 +1721,11 @@ fil_space_free(
space = fil_space_get_by_id(id);
if (!space) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: trying to remove tablespace %lu"
- " from the cache but\n"
- "InnoDB: it is not there.\n", (ulong) id);
-
- return(FALSE);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "trying to remove non-existing tablespace " ULINTPF,
+ id);
+ mutex_exit(&fil_system->mutex);
+ return(false);
}
HASH_DELETE(fil_space_t, hash, fil_system->spaces, id, space);
@@ -1772,11 +1757,25 @@ fil_space_free(
ut_a(space->magic_n == FIL_SPACE_MAGIC_N);
ut_a(0 == space->n_pending_flushes);
+ for (fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
+ node != NULL;
+ node = UT_LIST_GET_NEXT(chain, node)) {
+ fil_node_free_part1(space, node);
+ }
+
+ mutex_exit(&fil_system->mutex);
+
+ /* Wait for fil_space_release_for_io(); after
+ fil_space_detach(), the tablespace cannot be found, so
+ fil_space_acquire_for_io() would return NULL */
+ while (space->n_pending_ios) {
+ os_thread_sleep(100);
+ }
+
for (fil_node_t* fil_node = UT_LIST_GET_FIRST(space->chain);
fil_node != NULL;
fil_node = UT_LIST_GET_FIRST(space->chain)) {
-
- fil_node_free(fil_node, fil_system, space);
+ fil_node_free_part2(space, fil_node);
}
ut_a(0 == UT_LIST_GET_LEN(space->chain));
@@ -2176,7 +2175,11 @@ fil_close_all_files(void)
space = UT_LIST_GET_NEXT(space_list, space);
- fil_space_free(prev_space->id, FALSE);
+ /* This is executed during shutdown. No other thread
+ can create or remove tablespaces while we are not
+ holding fil_system->mutex. */
+ fil_space_free_and_mutex_exit(prev_space->id, false);
+ mutex_enter(&fil_system->mutex);
}
mutex_exit(&fil_system->mutex);
@@ -2224,7 +2227,11 @@ fil_close_log_files(
space = UT_LIST_GET_NEXT(space_list, space);
if (free) {
- fil_space_free(prev_space->id, FALSE);
+ /* This is executed during startup. No other thread
+ can create or remove tablespaces while we are not
+ holding fil_system->mutex. */
+ fil_space_free_and_mutex_exit(prev_space->id, false);
+ mutex_enter(&fil_system->mutex);
}
}
@@ -2429,6 +2436,19 @@ fil_read_first_page(
const char* check_msg = NULL;
fil_space_crypt_t* cdata;
+ if (IS_XTRABACKUP() && srv_backup_mode) {
+ /* Files smaller than page size may occur
+ in xtrabackup, when server creates new file
+ but has not yet written into it, or wrote only
+ partially. Checks size here, to avoid exit in os_file_read.
+ This file will be skipped by xtrabackup if it is too small.
+ */
+ os_offset_t file_size;
+ file_size = os_file_get_size(data_file);
+ if (file_size < FIL_IBD_FILE_INITIAL_SIZE*UNIV_PAGE_SIZE) {
+ return "File size is less than minimum";
+ }
+ }
buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
/* Align the memory for a possible read from a raw device */
@@ -2459,7 +2479,9 @@ fil_read_first_page(
}
}
- check_msg = fil_check_first_page(page, *space_id, *flags);
+ if (!(IS_XTRABACKUP() && srv_backup_mode)) {
+ check_msg = fil_check_first_page(page, *space_id, *flags);
+ }
}
flushed_lsn = mach_read_from_8(page +
@@ -2516,74 +2538,6 @@ fil_read_first_page(
/*================ SINGLE-TABLE TABLESPACES ==========================*/
-#ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Increments the count of pending operation, if space is not being deleted.
-@return TRUE if being deleted, and operation should be skipped */
-UNIV_INTERN
-ibool
-fil_inc_pending_ops(
-/*================*/
- ulint id, /*!< in: space id */
- ibool print_err) /*!< in: need to print error or not */
-{
- fil_space_t* space;
-
- mutex_enter(&fil_system->mutex);
-
- space = fil_space_get_by_id(id);
-
- if (space == NULL) {
- if (print_err) {
- fprintf(stderr,
- "InnoDB: Error: trying to do an operation on a"
- " dropped tablespace %lu\n",
- (ulong) id);
- }
- }
-
- if (space == NULL || space->stop_new_ops) {
- mutex_exit(&fil_system->mutex);
-
- return(TRUE);
- }
-
- space->n_pending_ops++;
-
- mutex_exit(&fil_system->mutex);
-
- return(FALSE);
-}
-
-/*******************************************************************//**
-Decrements the count of pending operations. */
-UNIV_INTERN
-void
-fil_decr_pending_ops(
-/*=================*/
- ulint id) /*!< in: space id */
-{
- fil_space_t* space;
-
- mutex_enter(&fil_system->mutex);
-
- space = fil_space_get_by_id(id);
-
- if (space == NULL) {
- fprintf(stderr,
- "InnoDB: Error: decrementing pending operation"
- " of a dropped tablespace %lu\n",
- (ulong) id);
- }
-
- if (space != NULL) {
- space->n_pending_ops--;
- }
-
- mutex_exit(&fil_system->mutex);
-}
-#endif /* !UNIV_HOTBACKUP */
-
/********************************************************//**
Creates the database directory for a table if it does not exist yet. */
static
@@ -2975,7 +2929,7 @@ fil_check_pending_operations(
fil_space_t* sp = fil_space_get_by_id(id);
if (sp) {
- sp->stop_new_ops = TRUE;
+ sp->stop_new_ops = true;
/* space could be freed by other threads as soon
as n_pending_ops reaches 0, thus increment pending
ops here. */
@@ -3087,15 +3041,13 @@ fil_close_tablespace(
/* If the free is successful, the X lock will be released before
the space memory data structure is freed. */
- if (!fil_space_free(id, TRUE)) {
+ if (!fil_space_free_and_mutex_exit(id, TRUE)) {
rw_lock_x_unlock(&space->latch);
err = DB_TABLESPACE_NOT_FOUND;
} else {
err = DB_SUCCESS;
}
- mutex_exit(&fil_system->mutex);
-
/* If it is a delete then also delete any generated files, otherwise
when we drop the database the remove directory will fail. */
@@ -3204,12 +3156,10 @@ fil_delete_tablespace(
ut_a(node->n_pending == 0);
}
- if (!fil_space_free(id, TRUE)) {
+ if (!fil_space_free_and_mutex_exit(id, true)) {
err = DB_TABLESPACE_NOT_FOUND;
}
- mutex_exit(&fil_system->mutex);
-
if (err != DB_SUCCESS) {
rw_lock_x_unlock(&space->latch);
} else if (!os_file_delete(innodb_file_data_key, path)
@@ -3221,7 +3171,7 @@ fil_delete_tablespace(
err = DB_IO_ERROR;
}
- if (err == DB_SUCCESS) {
+ if (err == DB_SUCCESS && !IS_XTRABACKUP()) {
#ifndef UNIV_HOTBACKUP
/* Write a log record about the deletion of the .ibd
file, so that mysqlbackup can replay it in the
@@ -3620,7 +3570,7 @@ skip_second_rename:
mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
- if (success && !recv_recovery_on) {
+ if (success && !recv_recovery_on && !IS_XTRABACKUP()) {
mtr_t mtr;
mtr_start(&mtr);
@@ -3866,7 +3816,18 @@ fil_create_new_single_table_tablespace(
ibool success;
/* TRUE if a table is created with CREATE TEMPORARY TABLE */
bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY);
- bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags) != 0;
+
+
+ /* For XtraBackup recovery we force remote tablespaces to be local,
+ i.e. never execute the code path corresponding to has_data_dir == true.
+ We don't create .isl files either, because we rely on innobackupex to
+ copy them under a global lock, and use them to copy remote tablespaces
+ to their proper locations on --copy-back.
+
+ See also MySQL bug #72022: dir_path is always NULL for remote
+ tablespaces when a MLOG_FILE_CREATE* log record is replayed (the remote
+ directory is not available from MLOG_FILE_CREATE*). */
+ bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags) != 0 && !IS_XTRABACKUP();
ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
fil_space_crypt_t *crypt_data = NULL;
@@ -4048,6 +4009,7 @@ fil_create_new_single_table_tablespace(
}
#ifndef UNIV_HOTBACKUP
+ if (!IS_XTRABACKUP())
{
mtr_t mtr;
ulint mlog_file_flag = 0;
@@ -4088,6 +4050,138 @@ error_exit_3:
return(err);
}
+#include "pars0pars.h"
+#include "que0que.h"
+#include "dict0priv.h"
+static
+void
+fil_remove_invalid_table_from_data_dict(const char *name)
+{
+ trx_t* trx;
+ pars_info_t* info = NULL;
+
+ trx = trx_allocate_for_mysql();
+ trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
+
+ ut_ad(mutex_own(&dict_sys->mutex));
+
+ trx->op_info = "removing invalid table from data dictionary";
+
+ info = pars_info_create();
+
+ pars_info_add_str_literal(info, "table_name", name);
+
+ que_eval_sql(info,
+ "PROCEDURE DROP_TABLE_PROC () IS\n"
+ "sys_foreign_id CHAR;\n"
+ "table_id CHAR;\n"
+ "index_id CHAR;\n"
+ "foreign_id CHAR;\n"
+ "found INT;\n"
+
+ "DECLARE CURSOR cur_fk IS\n"
+ "SELECT ID FROM SYS_FOREIGN\n"
+ "WHERE FOR_NAME = :table_name\n"
+ "AND TO_BINARY(FOR_NAME)\n"
+ " = TO_BINARY(:table_name)\n"
+ "LOCK IN SHARE MODE;\n"
+
+ "DECLARE CURSOR cur_idx IS\n"
+ "SELECT ID FROM SYS_INDEXES\n"
+ "WHERE TABLE_ID = table_id\n"
+ "LOCK IN SHARE MODE;\n"
+
+ "BEGIN\n"
+ "SELECT ID INTO table_id\n"
+ "FROM SYS_TABLES\n"
+ "WHERE NAME = :table_name\n"
+ "LOCK IN SHARE MODE;\n"
+ "IF (SQL % NOTFOUND) THEN\n"
+ " RETURN;\n"
+ "END IF;\n"
+ "found := 1;\n"
+ "SELECT ID INTO sys_foreign_id\n"
+ "FROM SYS_TABLES\n"
+ "WHERE NAME = 'SYS_FOREIGN'\n"
+ "LOCK IN SHARE MODE;\n"
+ "IF (SQL % NOTFOUND) THEN\n"
+ " found := 0;\n"
+ "END IF;\n"
+ "IF (:table_name = 'SYS_FOREIGN') THEN\n"
+ " found := 0;\n"
+ "END IF;\n"
+ "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
+ " found := 0;\n"
+ "END IF;\n"
+ "OPEN cur_fk;\n"
+ "WHILE found = 1 LOOP\n"
+ " FETCH cur_fk INTO foreign_id;\n"
+ " IF (SQL % NOTFOUND) THEN\n"
+ " found := 0;\n"
+ " ELSE\n"
+ " DELETE FROM SYS_FOREIGN_COLS\n"
+ " WHERE ID = foreign_id;\n"
+ " DELETE FROM SYS_FOREIGN\n"
+ " WHERE ID = foreign_id;\n"
+ " END IF;\n"
+ "END LOOP;\n"
+ "CLOSE cur_fk;\n"
+ "found := 1;\n"
+ "OPEN cur_idx;\n"
+ "WHILE found = 1 LOOP\n"
+ " FETCH cur_idx INTO index_id;\n"
+ " IF (SQL % NOTFOUND) THEN\n"
+ " found := 0;\n"
+ " ELSE\n"
+ " DELETE FROM SYS_FIELDS\n"
+ " WHERE INDEX_ID = index_id;\n"
+ " DELETE FROM SYS_INDEXES\n"
+ " WHERE ID = index_id\n"
+ " AND TABLE_ID = table_id;\n"
+ " END IF;\n"
+ "END LOOP;\n"
+ "CLOSE cur_idx;\n"
+ "DELETE FROM SYS_COLUMNS\n"
+ "WHERE TABLE_ID = table_id;\n"
+ "DELETE FROM SYS_TABLES\n"
+ "WHERE NAME = :table_name;\n"
+ "END;\n"
+ , FALSE, trx);
+
+ /* SYS_DATAFILES and SYS_TABLESPACES do not necessarily exist
+ on XtraBackup recovery. See comments around
+ dict_create_or_check_foreign_constraint_tables() in
+ innobase_start_or_create_for_mysql(). */
+ if (dict_table_get_low("SYS_DATAFILES") != NULL) {
+ info = pars_info_create();
+
+ pars_info_add_str_literal(info, "table_name", name);
+
+ que_eval_sql(info,
+ "PROCEDURE DROP_TABLE_PROC () IS\n"
+ "space_id INT;\n"
+
+ "BEGIN\n"
+ "SELECT SPACE INTO space_id\n"
+ "FROM SYS_TABLES\n"
+ "WHERE NAME = :table_name;\n"
+ "IF (SQL % NOTFOUND) THEN\n"
+ " RETURN;\n"
+ "END IF;\n"
+ "DELETE FROM SYS_TABLESPACES\n"
+ "WHERE SPACE = space_id;\n"
+ "DELETE FROM SYS_DATAFILES\n"
+ "WHERE SPACE = space_id;\n"
+ "END;\n"
+ , FALSE, trx);
+ }
+
+ trx_commit_for_mysql(trx);
+
+ trx_free_for_mysql(trx);
+}
+
+
#ifndef UNIV_HOTBACKUP
/********************************************************************//**
Report information about a bad tablespace. */
@@ -4228,8 +4322,10 @@ fil_open_single_table_tablespace(
in the default location. If it is remote, it should not be here. */
def.filepath = fil_make_ibd_name(tablename, false);
- /* The path_in was read from SYS_DATAFILES. */
- if (path_in) {
+ /* The path_in was read from SYS_DATAFILES.
+ We skip SYS_DATAFILES validation and remote tablespaces discovery for
+ XtraBackup, as all tablespaces are local for XtraBackup recovery. */
+ if (path_in && !IS_XTRABACKUP()) {
if (strcmp(def.filepath, path_in)) {
dict.filepath = mem_strdup(path_in);
/* possibility of multiple files. */
@@ -4371,12 +4467,19 @@ fil_open_single_table_tablespace(
/* The following call prints an error message */
os_file_get_last_error(true);
- ib_logf(IB_LOG_LEVEL_ERROR,
+ ib_logf(IS_XTRABACKUP() ? IB_LOG_LEVEL_WARN : IB_LOG_LEVEL_ERROR,
"Could not find a valid tablespace file for '%s'. "
"See " REFMAN "innodb-troubleshooting-datadict.html "
"for how to resolve the issue.",
tablename);
+ if (IS_XTRABACKUP() && fix_dict) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "It will be removed from the data dictionary.");
+ if (purge_sys) {
+ fil_remove_invalid_table_from_data_dict(tablename);
+ }
+ }
err = DB_CORRUPTION;
goto cleanup_and_exit;
@@ -4801,6 +4904,11 @@ check_first_page:
}
if (!fsp->success) {
+ if (IS_XTRABACKUP()) {
+ /* Do not attempt restore from doublewrite buffer
+ in Xtrabackup, this does not work.*/
+ return;
+ }
if (!restore_attempted) {
if (!fil_user_tablespace_find_space_id(fsp)) {
return;
@@ -4868,6 +4976,10 @@ fil_load_single_table_tablespace(
os_offset_t size;
fil_space_t* space;
+ fsp_open_info* fsp;
+ ulong minimum_size;
+ ibool file_space_create_success;
+
memset(&def, 0, sizeof(def));
memset(&remote, 0, sizeof(remote));
@@ -4923,6 +5035,7 @@ fil_load_single_table_tablespace(
# endif /* !UNIV_HOTBACKUP */
#endif
+
/* Check for a link file which locates a remote tablespace. */
remote.success = fil_open_linked_file(
tablename, &remote.filepath, &remote.file, FALSE);
@@ -4933,6 +5046,17 @@ fil_load_single_table_tablespace(
if (!remote.success) {
os_file_close(remote.file);
mem_free(remote.filepath);
+
+ if (srv_backup_mode && (remote.id == ULINT_UNDEFINED
+ || remote.id == 0)) {
+
+ /* Ignore files that have uninitialized space
+ IDs on the backup stage. This means that a
+ tablespace has just been created and we will
+ replay the corresponding log records on
+ prepare. */
+ goto func_exit_after_close;
+ }
}
}
@@ -4947,6 +5071,18 @@ fil_load_single_table_tablespace(
fil_validate_single_table_tablespace(tablename, &def);
if (!def.success) {
os_file_close(def.file);
+
+ if (IS_XTRABACKUP() && srv_backup_mode && (def.id == ULINT_UNDEFINED
+ || def.id == 0)) {
+
+ /* Ignore files that have uninitialized space
+ IDs on the backup stage. This means that a
+ tablespace has just been created and we will
+ replay the corresponding log records on
+ prepare. */
+
+ goto func_exit_after_close;
+ }
}
}
@@ -5032,7 +5168,7 @@ will_not_choose:
/* At this point, only one tablespace is open */
ut_a(def.success == !remote.success);
- fsp_open_info* fsp = def.success ? &def : &remote;
+ fsp = def.success ? &def : &remote;
/* Get and test the file size. */
size = os_file_get_size(fsp->file);
@@ -5051,19 +5187,14 @@ will_not_choose:
/* Every .ibd file is created >= 4 pages in size. Smaller files
cannot be ok. */
- ulong minimum_size = FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE;
+ minimum_size = FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE;
if (size < minimum_size) {
-#ifndef UNIV_HOTBACKUP
ib_logf(IB_LOG_LEVEL_ERROR,
"The size of single-table tablespace file %s "
"is only " UINT64PF ", should be at least %lu!",
fsp->filepath, size, minimum_size);
os_file_close(fsp->file);
goto no_good_file;
-#else
- fsp->id = ULINT_UNDEFINED;
- fsp->flags = 0;
-#endif /* !UNIV_HOTBACKUP */
}
#ifdef UNIV_HOTBACKUP
@@ -5134,6 +5265,7 @@ will_not_choose:
}
mutex_exit(&fil_system->mutex);
#endif /* UNIV_HOTBACKUP */
+
/* Adjust the memory-based flags that would normally be set by
dict_tf_to_fsp_flags(). In recovery, we have no data dictionary. */
if (FSP_FLAGS_HAS_PAGE_COMPRESSION(fsp->flags)) {
@@ -5144,7 +5276,7 @@ will_not_choose:
/* We will leave atomic_writes at ATOMIC_WRITES_DEFAULT.
That will be adjusted in fil_space_for_table_exists_in_mem(). */
- ibool file_space_create_success = fil_space_create(
+ file_space_create_success = fil_space_create(
tablename, fsp->id, fsp->flags, FIL_TABLESPACE,
fsp->crypt_data, false);
@@ -5172,13 +5304,56 @@ will_not_choose:
}
func_exit:
- os_file_close(fsp->file);
+ /* We reuse file handles on the backup stage in XtraBackup to avoid
+ inconsistencies between the file name and the actual tablespace contents
+ if a DDL occurs between a fil_load_single_table_tablespaces() call and
+ the actual copy operation. */
+ if (IS_XTRABACKUP() && srv_backup_mode && !srv_close_files) {
+
+ fil_node_t* node;
+ fil_space_t* space;
+
+ mutex_enter(&fil_system->mutex);
+
+ space = fil_space_get_by_id(fsp->id);
+
+ if (space) {
+ node = UT_LIST_GET_LAST(space->chain);
+
+ /* The handle will be closed by xtrabackup in
+ xtrabackup_copy_datafile(). We set node->open to TRUE to
+ make sure no one calls fil_node_open_file()
+ (i.e. attempts to reopen the tablespace by name) during
+ the backup stage. */
+
+ node->open = TRUE;
+ node->handle = fsp->file;
+
+ /* The following is copied from fil_node_open_file() to
+ pass fil_system validaty checks. We cannot use
+ fil_node_open_file() directly, as that would re-open the
+ file by name and create another file handle. */
+
+ fil_system->n_open++;
+ fil_n_file_opened++;
+
+ if (fil_space_belongs_in_lru(space)) {
+
+ /* Put the node to the LRU list */
+ UT_LIST_ADD_FIRST(LRU, fil_system->LRU, node);
+ }
+ }
+
+ mutex_exit(&fil_system->mutex);
+ }
+ else {
+ os_file_close(fsp->file);
+ }
+
-#ifdef UNIV_HOTBACKUP
func_exit_after_close:
-#else
ut_ad(!mutex_own(&fil_system->mutex));
-#endif
+
mem_free(tablename);
if (remote.success) {
mem_free(remote.filepath);
@@ -5192,7 +5367,7 @@ directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data.
@return 0 if ok, -1 if error even after the retries, 1 if at the end
of the directory */
-static
+UNIV_INTERN
int
fil_file_readdir_next_file(
/*=======================*/
@@ -5222,6 +5397,9 @@ fil_file_readdir_next_file(
return(-1);
}
+
+my_bool(*fil_check_if_skip_database_by_path)(const char* name);
+
#define CHECK_TIME_EVERY_N_FILES 10
/********************************************************************//**
At the server startup, if we need crash recovery, scans the database
@@ -5233,7 +5411,7 @@ space id is != 0.
@return DB_SUCCESS or error number */
UNIV_INTERN
dberr_t
-fil_load_single_table_tablespaces(void)
+fil_load_single_table_tablespaces(ibool (*pred)(const char*, const char*))
/*===================================*/
{
int ret;
@@ -5292,7 +5470,19 @@ fil_load_single_table_tablespaces(void)
"%s/%s", fil_path_to_mysql_datadir, dbinfo.name);
srv_normalize_path_for_win(dbpath);
- dbdir = os_file_opendir(dbpath, FALSE);
+ if (IS_XTRABACKUP()) {
+ ut_a(fil_check_if_skip_database_by_path);
+ if (fil_check_if_skip_database_by_path(dbpath)) {
+ fprintf(stderr, "Skipping db: %s\n", dbpath);
+ dbdir = NULL;
+ } else {
+ /* We want wrong directory permissions to be a fatal
+ error for XtraBackup. */
+ dbdir = os_file_opendir(dbpath, TRUE);
+ }
+ } else {
+ dbdir = os_file_opendir(dbpath, FALSE);
+ }
if (dbdir != NULL) {
@@ -5308,14 +5498,20 @@ fil_load_single_table_tablespaces(void)
goto next_file_item;
}
- /* We found a symlink or a file */
+ /* We found a symlink or a file
+
+ Ignore .isl files on XtraBackup
+ recovery, all tablespaces must be local. */
if (strlen(fileinfo.name) > 4
&& (0 == strcmp(fileinfo.name
+ strlen(fileinfo.name) - 4,
".ibd")
- || 0 == strcmp(fileinfo.name
- + strlen(fileinfo.name) - 4,
- ".isl"))) {
+ || ((!IS_XTRABACKUP() || srv_backup_mode)
+ && 0 == strcmp(fileinfo.name
+ + strlen(fileinfo.name) - 4,
+ ".isl")))
+ && (!pred ||
+ pred(dbinfo.name, fileinfo.name))) {
/* The name ends in .ibd or .isl;
try opening the file */
fil_load_single_table_tablespace(
@@ -5390,7 +5586,7 @@ fil_tablespace_deleted_or_being_deleted_in_mem(
space = fil_space_get_by_id(id);
- if (space == NULL || space->stop_new_ops) {
+ if (space == NULL || space->is_stopping()) {
mutex_exit(&fil_system->mutex);
return(TRUE);
@@ -5471,6 +5667,9 @@ fil_space_for_table_exists_in_mem(
information to the .err log if a
matching tablespace is not found from
memory */
+ bool remove_from_data_dict_if_does_not_exist,
+ /*!< in: remove from the data dictionary
+ if tablespace does not exist */
bool adjust_space, /*!< in: whether to adjust space id
when find table space mismatch */
mem_heap_t* heap, /*!< in: heap memory */
@@ -5541,6 +5740,11 @@ fil_space_for_table_exists_in_mem(
if (fnamespace == NULL) {
if (print_error_if_does_not_exist) {
fil_report_missing_tablespace(name, id);
+ if (IS_XTRABACKUP() && remove_from_data_dict_if_does_not_exist) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "It will be removed from "
+ "the data dictionary.");
+ }
}
} else {
ut_print_timestamp(stderr);
@@ -6002,7 +6206,7 @@ UNIV_INTERN
ulint
fil_space_get_block_size(const fil_space_t* space, unsigned offset)
{
- ut_ad(space->n_pending_ops > 0);
+ ut_ad(space->n_pending_ios > 0);
ulint block_size = 512;
@@ -6143,15 +6347,19 @@ _fil_io(
/* If we are deleting a tablespace we don't allow async read operations
on that. However, we do allow write and sync read operations */
if (space == 0
- || (type == OS_FILE_READ && !sync && space->stop_new_ops)) {
+ || (type == OS_FILE_READ
+ && !sync
+ && space->stop_new_ops)) {
mutex_exit(&fil_system->mutex);
ib_logf(IB_LOG_LEVEL_ERROR,
"Trying to do i/o to a tablespace which does "
- "not exist. i/o type %lu, space id %lu, "
- "page no. %lu, i/o length %lu bytes",
- (ulong) type, (ulong) space_id, (ulong) block_offset,
- (ulong) len);
+ "not exist. i/o type " ULINTPF
+ ", space id " ULINTPF " , "
+ "page no. " ULINTPF
+ ", i/o length " ULINTPF " bytes",
+ type, space_id, block_offset,
+ len);
return(DB_TABLESPACE_DELETED);
}
@@ -6199,7 +6407,7 @@ _fil_io(
/* Check that at least the start offset is within the bounds of a
single-table tablespace, including rollback tablespaces. */
if (UNIV_UNLIKELY(node->size <= block_offset)
- && space->id != 0 && space->purpose == FIL_TABLESPACE) {
+ && space->id != 0 && space->purpose == FIL_TABLESPACE) {
fil_report_invalid_page_access(
block_offset, space_id, space->name, byte_offset,
@@ -6255,8 +6463,15 @@ _fil_io(
mutex_exit(&fil_system->mutex);
if (mode == OS_AIO_NORMAL) {
ut_a(space->purpose == FIL_TABLESPACE);
- buf_page_io_complete(static_cast<buf_page_t *>
- (message));
+ dberr_t err = buf_page_io_complete(static_cast<buf_page_t *>
+ (message));
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Write operation failed for tablespace %s ("
+ ULINTPF ") offset " ULINTPF " error=%d.",
+ space->name, space->id, byte_offset, err);
+ }
}
}
@@ -6359,6 +6574,8 @@ fil_aio_wait(
mutex_enter(&fil_system->mutex);
fil_node_complete_io(fil_node, fil_system, type);
+ ulint purpose = fil_node->space->purpose;
+ space_id = fil_node->space->id;
mutex_exit(&fil_system->mutex);
@@ -6370,9 +6587,27 @@ fil_aio_wait(
deadlocks in the i/o system. We keep tablespace 0 data files always
open, and use a special i/o thread to serve insert buffer requests. */
- if (fil_node->space->purpose == FIL_TABLESPACE) {
+ if (purpose == FIL_TABLESPACE) {
srv_set_io_thread_op_info(segment, "complete io for buf page");
- buf_page_io_complete(static_cast<buf_page_t*>(message));
+ buf_page_t* bpage = static_cast<buf_page_t*>(message);
+ ulint offset = bpage->offset;
+ dberr_t err = buf_page_io_complete(bpage);
+
+ if (err != DB_SUCCESS) {
+ ut_ad(type == OS_FILE_READ);
+ /* In crash recovery set log corruption on
+ and produce only an error to fail InnoDB startup. */
+ if (recv_recovery_is_on() && !srv_force_recovery) {
+ recv_sys->found_corrupt_log = true;
+ }
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Read operation failed for tablespace %s"
+ " offset " ULINTPF " with error %s",
+ fil_node->name,
+ offset,
+ ut_strerr(err));
+ }
} else {
srv_set_io_thread_op_info(segment, "complete io for log");
log_io_complete(static_cast<log_group_t*>(message));
@@ -6393,7 +6628,8 @@ fil_flush(
mutex_enter(&fil_system->mutex);
if (fil_space_t* space = fil_space_get_by_id(space_id)) {
- if (!space->is_stopping()) {
+ if (!space->stop_new_ops) {
+
fil_flush_low(space);
}
}
@@ -6407,7 +6643,7 @@ UNIV_INTERN
void
fil_flush(fil_space_t* space)
{
- ut_ad(space->n_pending_ops > 0);
+ ut_ad(space->n_pending_ios > 0);
if (!space->is_stopping()) {
mutex_enter(&fil_system->mutex);
@@ -7331,88 +7567,16 @@ fil_space_set_corrupt(
mutex_exit(&fil_system->mutex);
}
-/******************************************************************
-Get id of first tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space()
-/*=================*/
-{
- ulint out_id = ULINT_UNDEFINED;
- fil_space_t* space;
-
- mutex_enter(&fil_system->mutex);
-
- space = UT_LIST_GET_FIRST(fil_system->space_list);
- if (space != NULL) {
- do
- {
- if (!space->stop_new_ops) {
- out_id = space->id;
- break;
- }
- space = UT_LIST_GET_NEXT(space_list, space);
- } while (space != NULL);
- }
-
- mutex_exit(&fil_system->mutex);
-
- return out_id;
-}
-
-/******************************************************************
-Get id of next tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space(
-/*===============*/
- ulint id) /*!< in: previous space id */
-{
- bool found;
- fil_space_t* space;
- ulint out_id = ULINT_UNDEFINED;
-
- mutex_enter(&fil_system->mutex);
-
- space = fil_space_get_by_id(id);
- if (space == NULL) {
- /* we didn't find it...search for space with space->id > id */
- found = false;
- space = UT_LIST_GET_FIRST(fil_system->space_list);
- } else {
- /* we found it, take next available space */
- found = true;
- }
-
- while ((space = UT_LIST_GET_NEXT(space_list, space)) != NULL) {
-
- if (!found && space->id <= id)
- continue;
-
- if (!space->stop_new_ops && UT_LIST_GET_LEN(space->chain) > 0) {
- /* inc reference to prevent drop */
- out_id = space->id;
- break;
- }
- }
-
- mutex_exit(&fil_system->mutex);
-
- return out_id;
-}
-
/** Acquire a tablespace when it could be dropped concurrently.
Used by background threads that do not necessarily hold proper locks
for concurrency control.
@param[in] id tablespace ID
@param[in] silent whether to silently ignore missing tablespaces
-@param[in] for_io whether to look up the tablespace while performing I/O
- (possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
-inline
+UNIV_INTERN
fil_space_t*
-fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
+fil_space_acquire_low(ulint id, bool silent)
{
fil_space_t* space;
@@ -7425,7 +7589,7 @@ fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
ib_logf(IB_LOG_LEVEL_WARN, "Trying to access missing"
" tablespace " ULINTPF ".", id);
}
- } else if (!for_io && space->is_stopping()) {
+ } else if (space->is_stopping()) {
space = NULL;
} else {
space->n_pending_ops++;
@@ -7436,34 +7600,44 @@ fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
return(space);
}
-/** Acquire a tablespace when it could be dropped concurrently.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
+/** Acquire a tablespace for reading or writing a block,
+when it could be dropped concurrently.
@param[in] id tablespace ID
-@param[in] for_io whether to look up the tablespace while performing I/O
- (possibly executing TRUNCATE)
@return the tablespace
-@retval NULL if missing or being deleted or truncated */
+@retval NULL if missing */
+UNIV_INTERN
fil_space_t*
-fil_space_acquire(ulint id, bool for_io)
+fil_space_acquire_for_io(ulint id)
{
- return(fil_space_acquire_low(id, false, for_io));
+ mutex_enter(&fil_system->mutex);
+
+ fil_space_t* space = fil_space_get_by_id(id);
+
+ if (space) {
+ space->n_pending_ios++;
+ }
+
+ mutex_exit(&fil_system->mutex);
+
+ return(space);
}
-/** Acquire a tablespace that may not exist.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@return the tablespace
-@retval NULL if missing or being deleted */
-fil_space_t*
-fil_space_acquire_silent(ulint id)
+/** Release a tablespace acquired with fil_space_acquire_for_io().
+@param[in,out] space tablespace to release */
+UNIV_INTERN
+void
+fil_space_release_for_io(fil_space_t* space)
{
- return(fil_space_acquire_low(id, true));
+ mutex_enter(&fil_system->mutex);
+ ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
+ ut_ad(space->n_pending_ios > 0);
+ space->n_pending_ios--;
+ mutex_exit(&fil_system->mutex);
}
/** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */
+UNIV_INTERN
void
fil_space_release(fil_space_t* space)
{
@@ -7482,6 +7656,7 @@ blocks a concurrent operation from dropping the tablespace.
If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t.
@retval NULL if this was the last*/
+UNIV_INTERN
fil_space_t*
fil_space_next(fil_space_t* prev_space)
{
@@ -7549,6 +7724,7 @@ blocks a concurrent operation from dropping the tablespace.
If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t.
@retval NULL if this was the last*/
+UNIV_INTERN
fil_space_t*
fil_space_keyrotate_next(
fil_space_t* prev_space)
@@ -7590,7 +7766,7 @@ fil_space_keyrotate_next(
space->purpose == FIL_TABLESPACE. */
while (space != NULL
&& (UT_LIST_GET_LEN(space->chain) == 0
- || space->stop_new_ops)) {
+ || space->is_stopping())) {
old = space;
space = UT_LIST_GET_NEXT(rotation_list, space);
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index b89bd419876..49b0fedb3b4 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -32,7 +32,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
-
+
#define MYSQL_SERVER
#include <sql_table.h> // explain_filename, nz2, EXPLAIN_PARTITIONS_AS_COMMENT,
@@ -289,7 +289,8 @@ static TYPELIB innodb_stats_method_typelib = {
/** Possible values for system variables "innodb_checksum_algorithm" and
"innodb_log_checksum_algorithm". */
-static const char* innodb_checksum_algorithm_names[] = {
+UNIV_INTERN
+const char* innodb_checksum_algorithm_names[] = {
"CRC32",
"STRICT_CRC32",
"INNODB",
@@ -301,7 +302,8 @@ static const char* innodb_checksum_algorithm_names[] = {
/** Used to define an enumerate type of the system variables
innodb_checksum_algorithm and innodb_log_checksum_algorithm. */
-static TYPELIB innodb_checksum_algorithm_typelib = {
+UNIV_INTERN
+TYPELIB innodb_checksum_algorithm_typelib = {
array_elements(innodb_checksum_algorithm_names) - 1,
"innodb_checksum_algorithm_typelib",
innodb_checksum_algorithm_names,
@@ -2018,7 +2020,9 @@ thd_supports_xa(
THD* thd) /*!< in: thread handle, or NULL to query
the global innodb_supports_xa */
{
- return(THDVAR(thd, support_xa));
+ /* THDVAR cannot be used in xtrabackup,
+ plugin variables for innodb are not loaded. */
+ return (thd || !IS_XTRABACKUP())? THDVAR(thd, support_xa): FALSE;
}
/** Get the value of innodb_tmpdir.
@@ -2051,7 +2055,9 @@ thd_fake_changes(
THD* thd) /*!< in: thread handle, or NULL to query
the global innodb_supports_xa */
{
- return(THDVAR((THD*) thd, fake_changes));
+ /* THDVAR cannot be used in xtrabackup,
+ plugin variables for innodb are not loaded */
+ return (thd || !IS_XTRABACKUP())? THDVAR((THD*) thd, fake_changes) : FALSE ;
}
/******************************************************************//**
@@ -2091,7 +2097,10 @@ thd_flush_log_at_trx_commit(
/*================================*/
void* thd)
{
- return(THDVAR((THD*) thd, flush_log_at_trx_commit));
+ /* THDVAR cannot be used in xtrabackup,
+ plugin variables for innodb are not loaded,
+ this makes xtrabackup crash when trying to use them. */
+ return (thd || !IS_XTRABACKUP())? THDVAR((THD*)thd, flush_log_at_trx_commit) : FALSE;
}
/********************************************************************//**
@@ -3058,7 +3067,7 @@ trx_is_started(
/****************************************************************//**
Update log_checksum_algorithm_ptr with a pointer to the function corresponding
to a given checksum algorithm. */
-static
+
void
innodb_log_checksum_func_update(
/*============================*/
@@ -6233,20 +6242,23 @@ ha_innobase::innobase_initialize_autoinc()
break;
}
case DB_RECORD_NOT_FOUND:
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: MySQL and InnoDB data "
- "dictionaries are out of sync.\n"
- "InnoDB: Unable to find the AUTOINC column "
- "%s in the InnoDB table %s.\n"
- "InnoDB: We set the next AUTOINC column "
- "value to 0,\n"
- "InnoDB: in effect disabling the AUTOINC "
- "next value generation.\n"
- "InnoDB: You can either set the next "
- "AUTOINC value explicitly using ALTER TABLE\n"
- "InnoDB: or fix the data dictionary by "
- "recreating the table.\n",
- col_name, index->table->name);
+ char buf[MAX_FULL_NAME_LEN];
+ ut_format_name(index->table->name, TRUE, buf, sizeof(buf));
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "MySQL and InnoDB data "
+ "dictionaries are out of sync."
+ " Unable to find the AUTOINC column "
+ " %s in the InnoDB table %s."
+ " We set the next AUTOINC column "
+ "value to 0"
+ " in effect disabling the AUTOINC "
+ "next value generation."
+ " You can either set the next "
+ "AUTOINC value explicitly using ALTER TABLE "
+ " or fix the data dictionary by "
+ "recreating the table.",
+ col_name, buf);
/* This will disable the AUTOINC generation. */
auto_inc = 0;
@@ -6305,7 +6317,7 @@ ha_innobase::open(
DBUG_RETURN(1);
}
- if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt &&
+ if (UNIV_UNLIKELY(share->ib_table && share->ib_table->corrupted &&
srv_pass_corrupt_table <= 1)) {
free_share(share);
@@ -6341,23 +6353,24 @@ ha_innobase::open(
&& (table->s->fields
!= dict_table_get_n_user_cols(ib_table) - 1)))) {
ib_logf(IB_LOG_LEVEL_WARN,
- "table %s contains %lu user defined columns "
- "in InnoDB, but %lu columns in MySQL. Please "
+ "table %s contains " ULINTPF " user defined columns "
+ "in InnoDB, but %u columns in MySQL. Please "
"check INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and "
REFMAN "innodb-troubleshooting.html "
"for how to resolve it",
- norm_name, (ulong) dict_table_get_n_user_cols(ib_table),
- (ulong) table->s->fields);
+ norm_name, dict_table_get_n_user_cols(ib_table),
+ table->s->fields);
/* Mark this table as corrupted, so the drop table
or force recovery can still use it, but not others. */
ib_table->corrupted = true;
+ ib_table->file_unreadable = true;
dict_table_close(ib_table, FALSE, FALSE);
ib_table = NULL;
is_part = NULL;
}
- if (UNIV_UNLIKELY(ib_table && ib_table->is_corrupt &&
+ if (UNIV_UNLIKELY(ib_table && ib_table->corrupted &&
srv_pass_corrupt_table <= 1)) {
free_share(share);
my_free(upd_buf);
@@ -6467,7 +6480,7 @@ table_opened:
ib_table->thd = (void*)thd;
/* No point to init any statistics if tablespace is still encrypted. */
- if (!ib_table->is_encrypted) {
+ if (ib_table->is_readable()) {
dict_stats_init(ib_table);
} else {
ib_table->stat_initialized = 1;
@@ -6475,7 +6488,9 @@ table_opened:
MONITOR_INC(MONITOR_TABLE_OPEN);
- bool no_tablespace;
+ bool no_tablespace = false;
+ bool encrypted = false;
+ FilSpace space;
if (dict_table_is_discarded(ib_table)) {
@@ -6490,23 +6505,28 @@ table_opened:
no_tablespace = false;
- } else if (ib_table->ibd_file_missing) {
+ } else if (!ib_table->is_readable()) {
+ space = fil_space_acquire_silent(ib_table->space);
- ib_senderrf(
- thd, IB_LOG_LEVEL_WARN,
- ER_TABLESPACE_MISSING, norm_name);
-
- /* This means we have no idea what happened to the tablespace
- file, best to play it safe. */
-
- no_tablespace = true;
- } else if (ib_table->is_encrypted) {
- /* This means that tablespace was found but we could not
- decrypt encrypted page. */
- no_tablespace = true;
- ib_table->ibd_file_missing = true;
- } else {
- no_tablespace = false;
+ if (space()) {
+ if (space()->crypt_data && space()->crypt_data->is_encrypted()) {
+ /* This means that tablespace was found but we could not
+ decrypt encrypted page. */
+ no_tablespace = true;
+ encrypted = true;
+ } else {
+ no_tablespace = true;
+ }
+ } else {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN,
+ ER_TABLESPACE_MISSING, norm_name);
+
+ /* This means we have no idea what happened to the tablespace
+ file, best to play it safe. */
+
+ no_tablespace = true;
+ }
}
if (!thd_tablespace_op(thd) && no_tablespace) {
@@ -6517,27 +6537,33 @@ table_opened:
/* If table has no talespace but it has crypt data, check
is tablespace made unaccessible because encryption service
or used key_id is not available. */
- if (ib_table) {
- fil_space_crypt_t* crypt_data = ib_table->crypt_data;
+ if (encrypted) {
+ bool warning_pushed = false;
+ char buf[MAX_FULL_NAME_LEN];
+ ut_format_name(ib_table->name, TRUE, buf, sizeof(buf));
- if (crypt_data && crypt_data->should_encrypt()) {
+ if (!encryption_key_id_exists(space()->crypt_data->key_id)) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_DECRYPTION_FAILED,
+ "Table %s in file %s is encrypted but encryption service or"
+ " used key_id %u is not available. "
+ " Can't continue reading table.",
+ buf, space()->chain.start->name,
+ space()->crypt_data->key_id);
+ ret_err = HA_ERR_DECRYPTION_FAILED;
+ warning_pushed = true;
+ }
- if (!encryption_key_id_exists(crypt_data->key_id)) {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- HA_ERR_DECRYPTION_FAILED,
- "Table %s is encrypted but encryption service or"
- " used key_id %u is not available. "
- " Can't continue reading table.",
- ib_table->name, crypt_data->key_id);
- ret_err = HA_ERR_DECRYPTION_FAILED;
- }
- } else if (ib_table->is_encrypted) {
+ /* If table is marked as encrypted then we push
+ warning if it has not been already done as used
+ key_id might be found but it is incorrect. */
+ if (!warning_pushed) {
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
HA_ERR_DECRYPTION_FAILED,
- "Table %s is encrypted but encryption service or"
+ "Table %s in file %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
- ib_table->name);
+ buf, space()->chain.start->name);
ret_err = HA_ERR_DECRYPTION_FAILED;
}
}
@@ -6673,7 +6699,7 @@ table_opened:
/* Only if the table has an AUTOINC column. */
if (prebuilt->table != NULL
- && !prebuilt->table->ibd_file_missing
+ && prebuilt->table->is_readable()
&& table->found_next_number_field != NULL) {
dict_table_autoinc_lock(prebuilt->table);
@@ -8658,16 +8684,6 @@ ha_innobase::write_row(
ha_statistic_increment(&SSV::ha_write_count);
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
-
sql_command = thd_sql_command(user_thd);
if ((sql_command == SQLCOM_ALTER_TABLE
@@ -9005,16 +9021,6 @@ wsrep_error:
func_exit:
innobase_active_small();
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
-
DBUG_RETURN(error_result);
}
@@ -9425,16 +9431,6 @@ ha_innobase::update_row(
ha_statistic_increment(&SSV::ha_update_count);
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
-
if (prebuilt->upd_node) {
uvect = prebuilt->upd_node->update;
} else {
@@ -9540,16 +9536,6 @@ func_exit:
wsrep_error:
#endif /* WITH_WSREP */
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
-
DBUG_RETURN(err);
}
@@ -9578,11 +9564,6 @@ ha_innobase::delete_row(
ha_statistic_increment(&SSV::ha_delete_count);
- if (UNIV_UNLIKELY(share && share->ib_table
- && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
if (!prebuilt->upd_node) {
row_get_prebuilt_update_vector(prebuilt);
}
@@ -9617,11 +9598,6 @@ ha_innobase::delete_row(
wsrep_error:
#endif /* WITH_WSREP */
- if (UNIV_UNLIKELY(share && share->ib_table
- && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
DBUG_RETURN(convert_error_code_to_mysql(
error, prebuilt->table->flags, user_thd));
}
@@ -9872,17 +9848,13 @@ ha_innobase::index_read(
ha_statistic_increment(&SSV::ha_read_key_count);
- if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
- && share->ib_table && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
index = prebuilt->index;
if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) {
prebuilt->index_usable = FALSE;
DBUG_RETURN(HA_ERR_CRASHED);
}
+
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
DBUG_RETURN(dict_index_is_corrupted(index)
? HA_ERR_INDEX_CORRUPT
@@ -9949,11 +9921,6 @@ ha_innobase::index_read(
ret = DB_UNSUPPORTED;
}
- if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
- && share->ib_table && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
switch (ret) {
case DB_SUCCESS:
error = 0;
@@ -10113,11 +10080,6 @@ ha_innobase::change_active_index(
{
DBUG_ENTER("change_active_index");
- if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
- && share->ib_table && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
ut_ad(user_thd == ha_thd());
ut_a(prebuilt->trx == thd_to_trx(user_thd));
@@ -10237,13 +10199,23 @@ ha_innobase::general_fetch(
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
- if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
- && share->ib_table && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
ut_a(prebuilt->trx == thd_to_trx(user_thd));
+ if (prebuilt->table->is_readable()) {
+ } else {
+ if (prebuilt->table->corrupted) {
+ DBUG_RETURN(HA_ERR_CRASHED);
+ } else {
+ FilSpace space(prebuilt->table->space, true);
+
+ if (space()) {
+ DBUG_RETURN(HA_ERR_DECRYPTION_FAILED);
+ } else {
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+ }
+ }
+ }
+
innobase_srv_conc_enter_innodb(prebuilt->trx);
ret = row_search_for_mysql(
@@ -10251,11 +10223,6 @@ ha_innobase::general_fetch(
innobase_srv_conc_exit_innodb(prebuilt->trx);
- if (UNIV_UNLIKELY(srv_pass_corrupt_table <= 1 && share
- && share->ib_table && share->ib_table->is_corrupt)) {
- DBUG_RETURN(HA_ERR_CRASHED);
- }
-
switch (ret) {
case DB_SUCCESS:
error = 0;
@@ -12984,7 +12951,7 @@ ha_innobase::discard_or_import_tablespace(
user may want to set the DISCARD flag in order to IMPORT
a new tablespace. */
- if (dict_table->ibd_file_missing) {
+ if (!dict_table->is_readable()) {
ib_senderrf(
prebuilt->trx->mysql_thd,
IB_LOG_LEVEL_WARN, ER_TABLESPACE_MISSING,
@@ -12994,7 +12961,7 @@ ha_innobase::discard_or_import_tablespace(
err = row_discard_tablespace_for_mysql(
dict_table->name, prebuilt->trx);
- } else if (!dict_table->ibd_file_missing) {
+ } else if (dict_table->is_readable()) {
/* Commit the transaction in order to
release the table lock. */
trx_commit_for_mysql(prebuilt->trx);
@@ -13071,15 +13038,7 @@ ha_innobase::truncate()
update_thd(ha_thd());
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
+ DBUG_ASSERT(share->ib_table == prebuilt->table);
if (UNIV_UNLIKELY(prebuilt->trx->fake_changes)) {
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
@@ -13092,16 +13051,6 @@ ha_innobase::truncate()
err = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
-
switch (err) {
case DB_TABLESPACE_DELETED:
@@ -14502,15 +14451,7 @@ ha_innobase::analyze(
{
int ret;
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
+ DBUG_ASSERT(share->ib_table == prebuilt->table);
/* Simply call this->info_low() with all the flags
and request recalculation of the statistics */
@@ -14518,15 +14459,7 @@ ha_innobase::analyze(
HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
true /* this is ANALYZE */);
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
+ DBUG_ASSERT(share->ib_table == prebuilt->table);
if (ret != 0) {
return(HA_ADMIN_FAILED);
@@ -14630,7 +14563,8 @@ ha_innobase::check(
DBUG_RETURN(HA_ADMIN_CORRUPT);
- } else if (prebuilt->table->ibd_file_missing) {
+ } else if (!prebuilt->table->is_readable() &&
+ fil_space_get(prebuilt->table->space) == NULL) {
ib_senderrf(
thd, IB_LOG_LEVEL_ERROR,
@@ -14704,6 +14638,7 @@ ha_innobase::check(
server_mutex,
srv_fatal_semaphore_wait_threshold,
SRV_SEMAPHORE_WAIT_EXTENSION);
+
dberr_t err = btr_validate_index(index, prebuilt->trx);
/* Restore the fatal lock wait timeout after
@@ -14802,6 +14737,7 @@ ha_innobase::check(
if (!(index->type & DICT_CLUSTERED)) {
check_result = false;
});
+
if (!check_result) {
innobase_format_name(
index_name, sizeof index_name,
@@ -15831,15 +15767,7 @@ ha_innobase::transactional_table_lock(
update_thd(thd);
- if (share->ib_table != prebuilt->table) {
- fprintf(stderr,
- "InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
- 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);
- }
+ DBUG_ASSERT(share->ib_table == prebuilt->table);
if (!thd_tablespace_op(thd)) {
@@ -15850,7 +15778,7 @@ ha_innobase::transactional_table_lock(
ER_TABLESPACE_DISCARDED,
table->s->table_name.str);
- } else if (prebuilt->table->ibd_file_missing) {
+ } else if (!prebuilt->table->is_readable()) {
ib_senderrf(
thd, IB_LOG_LEVEL_ERROR,
@@ -17478,11 +17406,11 @@ innodb_log_archive_update(
if (in_val) {
/* turn archiving on */
- srv_log_archive_on = innobase_log_archive = 1;
+ innobase_log_archive = srv_log_archive_on = 1;
log_archive_archivelog();
} else {
/* turn archivng off */
- srv_log_archive_on = innobase_log_archive = 0;
+ innobase_log_archive = srv_log_archive_on = 0;
log_archive_noarchivelog();
}
}
@@ -22037,22 +21965,27 @@ ib_logf(
str = static_cast<char*>(malloc(BUFSIZ));
my_vsnprintf(str, BUFSIZ, format, args);
#endif /* __WIN__ */
-
- switch(level) {
- case IB_LOG_LEVEL_INFO:
- sql_print_information("InnoDB: %s", str);
- break;
- case IB_LOG_LEVEL_WARN:
- sql_print_warning("InnoDB: %s", str);
- break;
- case IB_LOG_LEVEL_ERROR:
- sql_print_error("InnoDB: %s", str);
- sd_notifyf(0, "STATUS=InnoDB: Error: %s", str);
- break;
- case IB_LOG_LEVEL_FATAL:
- sql_print_error("InnoDB: %s", str);
- sd_notifyf(0, "STATUS=InnoDB: Fatal: %s", str);
- break;
+ if (!IS_XTRABACKUP()) {
+ switch (level) {
+ case IB_LOG_LEVEL_INFO:
+ sql_print_information("InnoDB: %s", str);
+ break;
+ case IB_LOG_LEVEL_WARN:
+ sql_print_warning("InnoDB: %s", str);
+ break;
+ case IB_LOG_LEVEL_ERROR:
+ sql_print_error("InnoDB: %s", str);
+ sd_notifyf(0, "STATUS=InnoDB: Error: %s", str);
+ break;
+ case IB_LOG_LEVEL_FATAL:
+ sql_print_error("InnoDB: %s", str);
+ sd_notifyf(0, "STATUS=InnoDB: Fatal: %s", str);
+ break;
+ }
+ }
+ else {
+ /* Don't use server logger for XtraBackup, just print to stderr. */
+ fprintf(stderr, "InnoDB: %s\n", str);
}
va_end(args);
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 39e7c952f5d..ef8c62849ae 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -3137,7 +3137,7 @@ prepare_inplace_alter_table_dict(
clustered index of the old table, later. */
if (new_clustered
|| !ctx->online
- || user_table->ibd_file_missing
+ || !user_table->is_readable()
|| dict_table_is_discarded(user_table)) {
/* No need to allocate a modification log. */
ut_ad(!ctx->add_index[a]->online_log);
@@ -3557,6 +3557,43 @@ ha_innobase::prepare_inplace_alter_table(
goto func_exit;
}
+ indexed_table = prebuilt->table;
+
+ if (indexed_table->is_readable()) {
+ } else {
+ if (indexed_table->corrupted) {
+ /* Handled below */
+ } else {
+ FilSpace space(indexed_table->space, true);
+
+ if (space()) {
+ String str;
+ const char* engine= table_type();
+ char buf[MAX_FULL_NAME_LEN];
+ ut_format_name(indexed_table->name, TRUE, buf, sizeof(buf));
+
+ push_warning_printf(user_thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_DECRYPTION_FAILED,
+ "Table %s in file %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue reading table.",
+ buf, space()->chain.start->name);
+
+ my_error(ER_GET_ERRMSG, MYF(0), HA_ERR_DECRYPTION_FAILED, str.c_ptr(), engine);
+ DBUG_RETURN(true);
+ }
+ }
+ }
+
+ if (indexed_table->corrupted
+ || dict_table_get_first_index(indexed_table) == NULL
+ || dict_index_is_corrupted(
+ dict_table_get_first_index(indexed_table))) {
+ /* The clustered index is corrupted. */
+ my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0));
+ DBUG_RETURN(true);
+ }
+
if (ha_alter_info->handler_flags
& Alter_inplace_info::CHANGE_CREATE_OPTION) {
/* Check engine specific table options */
@@ -4209,7 +4246,7 @@ ok_exit:
DBUG_ASSERT(ctx->trx);
DBUG_ASSERT(ctx->prebuilt == prebuilt);
- if (prebuilt->table->ibd_file_missing
+ if (prebuilt->table->file_unreadable
|| dict_table_is_discarded(prebuilt->table)) {
goto all_done;
}
@@ -5231,7 +5268,7 @@ commit_try_rebuild(
/* The new table must inherit the flag from the
"parent" table. */
if (dict_table_is_discarded(user_table)) {
- rebuilt_table->ibd_file_missing = true;
+ rebuilt_table->file_unreadable = true;
rebuilt_table->flags2 |= DICT_TF2_DISCARDED;
}
@@ -5763,9 +5800,9 @@ ha_innobase::commit_inplace_alter_table(
if (ha_alter_info->group_commit_ctx) {
ctx_array = ha_alter_info->group_commit_ctx;
} else {
- ctx_single[0] = ctx0;
- ctx_single[1] = NULL;
- ctx_array = ctx_single;
+ ctx_single[0] = ctx0;
+ ctx_single[1] = NULL;
+ ctx_array = ctx_single;
}
DBUG_ASSERT(ctx0 == ctx_array[0]);
@@ -5794,6 +5831,19 @@ ha_innobase::commit_inplace_alter_table(
= static_cast<ha_innobase_inplace_ctx*>(*pctx);
DBUG_ASSERT(ctx->prebuilt->trx == prebuilt->trx);
+ /* If decryption failed for old table or new table
+ fail here. */
+ if ((ctx->old_table->file_unreadable &&
+ fil_space_get(ctx->old_table->space) != NULL)||
+ (ctx->new_table->file_unreadable &&
+ fil_space_get(ctx->new_table->space) != NULL)) {
+ String str;
+ const char* engine= table_type();
+ get_error_message(HA_ERR_DECRYPTION_FAILED, &str);
+ my_error(ER_GET_ERRMSG, MYF(0), HA_ERR_DECRYPTION_FAILED, str.c_ptr(), engine);
+ DBUG_RETURN(true);
+ }
+
/* Exclusively lock the table, to ensure that no other
transaction is holding locks on the table while we
change the table definition. The MySQL meta-data lock
diff --git a/storage/xtradb/include/btr0btr.ic b/storage/xtradb/include/btr0btr.ic
index 62a24873482..0f5f025d6a3 100644
--- a/storage/xtradb/include/btr0btr.ic
+++ b/storage/xtradb/include/btr0btr.ic
@@ -61,7 +61,7 @@ btr_block_get_func(
if (err == DB_DECRYPTION_FAILED) {
if (index && index->table) {
- index->table->is_encrypted = true;
+ index->table->file_unreadable = true;
}
}
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 4a632e2345f..9b4276efaa8 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2013, 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
@@ -675,13 +675,13 @@ buf_page_is_checksum_valid_none(
ulint checksum_field2)
MY_ATTRIBUTE((warn_unused_result));
-/********************************************************************//**
-Checks if a page is corrupt.
+/** Check if a page is corrupt.
@param[in] check_lsn true if LSN should be checked
@param[in] read_buf Page to be checked
@param[in] zip_size compressed size or 0
@param[in] space Pointer to tablespace
@return true if corrupted, false if not */
+UNIV_INTERN
bool
buf_page_is_corrupted(
bool check_lsn,
@@ -689,26 +689,13 @@ buf_page_is_corrupted(
ulint zip_size,
const fil_space_t* space)
MY_ATTRIBUTE((warn_unused_result));
-/********************************************************************//**
-Check if page is maybe compressed, encrypted or both when we encounter
-corrupted page. Note that we can't be 100% sure if page is corrupted
-or decrypt/decompress just failed.
-@param[in] bpage Page
-@return true if page corrupted, false if not */
-bool
-buf_page_check_corrupt(
- buf_page_t* bpage) /*!< in/out: buffer page read from disk */
- MY_ATTRIBUTE(( warn_unused_result));
-
-/********************************************************************//**
-Checks if a page is all zeroes.
-@return TRUE if the page is all zeroes */
+/** Check if a page is all zeroes.
+@param[in] read_buf database page
+@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
+@return whether the page is all zeroes */
+UNIV_INTERN
bool
-buf_page_is_zeroes(
-/*===============*/
- const byte* read_buf, /*!< in: a database page */
- const ulint zip_size); /*!< in: size of compressed page;
- 0 for uncompressed pages */
+buf_page_is_zeroes(const byte* read_buf, ulint zip_size);
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
Gets the space id, page offset, and byte offset within page of a
@@ -1270,15 +1257,18 @@ buf_page_init_for_read(
version of the tablespace in case we have done
DISCARD + IMPORT */
ulint offset);/*!< in: page number */
-/********************************************************************//**
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool.
-@return true if successful */
+/** Complete a read or write request of a file page to or from the buffer pool.
+@param[in,out] bpage Page to complete
+@return whether the operation succeeded
+@retval DB_SUCCESS always when writing, or if a read page was OK
+@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+ after decryption normal page checksum does
+ not match */
UNIV_INTERN
-bool
-buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage); /*!< in: pointer to the block in question */
+dberr_t
+buf_page_io_complete(buf_page_t* bpage)
+ MY_ATTRIBUTE((nonnull));
/********************************************************************//**
Calculates a folded value of a file page address to use in the page hash
table.
@@ -1680,7 +1670,6 @@ struct buf_page_t{
if written again we check is TRIM
operation needed. */
- unsigned key_version; /*!< key version for this block */
bool encrypted; /*!< page is still encrypted */
ulint real_size; /*!< Real size of the page
diff --git a/storage/xtradb/include/buf0rea.h b/storage/xtradb/include/buf0rea.h
index f0652b5d2cd..ab73108a71e 100644
--- a/storage/xtradb/include/buf0rea.h
+++ b/storage/xtradb/include/buf0rea.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 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
@@ -35,29 +35,37 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space space_id
+@param[in] zip_size compressed page size in bytes, or 0
+@param[in] offset page number
+@param[in] trx transaction
+@return DB_SUCCESS if page has been read and is not corrupted,
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */
UNIV_INTERN
-ibool
+dberr_t
buf_read_page(
-/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- trx_t* trx, /*!< in: trx */
- buf_page_t** bpage /*!< out: page */
-);
+ ulint space,
+ ulint zip_size,
+ ulint offset,
+ trx_t* trx);
+
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+@param[in] space Tablespace id
+@param[in] offset Page number */
UNIV_INTERN
-ibool
+void
buf_read_page_async(
-/*================*/
- ulint space, /*!< in: space id */
- ulint offset);/*!< in: page number */
+ ulint space,
+ ulint offset);
+
/********************************************************************//**
Applies a random read-ahead in buf_pool if there are at least a threshold
value of accessed pages from the random read-ahead area. Does not read any
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index b11c5f4ea1a..8bd3beda110 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/include/db0err.h
@@ -138,6 +138,8 @@ enum dberr_t {
of missing key management plugin,
or missing or incorrect key or
incorret AES method or algorithm. */
+ DB_PAGE_CORRUPTED, /* Page read from tablespace is
+ corrupted. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h
index 1622b927a76..6da8eb892d9 100644
--- a/storage/xtradb/include/dict0dict.h
+++ b/storage/xtradb/include/dict0dict.h
@@ -1767,16 +1767,6 @@ dict_close(void);
/*============*/
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
-Check whether the table is corrupted.
-@return nonzero for corrupted table, zero for valid tables */
-UNIV_INLINE
-ulint
-dict_table_is_corrupted(
-/*====================*/
- const dict_table_t* table) /*!< in: table */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/**********************************************************************//**
Check whether the index is corrupted.
@return nonzero for corrupted index, zero for valid indexes */
UNIV_INLINE
@@ -1820,6 +1810,15 @@ dict_set_corrupted_by_space(
/*========================*/
ulint space_id); /*!< in: space ID */
+/**********************************************************************//**
+Flags a table with specified space_id encrypted in the data dictionary
+cache
+@param[in] space_id Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(
+ ulint space_id);
+
/********************************************************************//**
Validate the table flags.
@return true if valid. */
@@ -1900,14 +1899,6 @@ dict_table_get_index_on_first_col(
in table */
#endif /* !UNIV_HOTBACKUP */
-/*************************************************************************
-set is_corrupt flag by space_id*/
-
-void
-dict_table_set_corrupt_by_space(
-/*============================*/
- ulint space_id,
- ibool need_mutex);
#ifndef UNIV_NONINL
#include "dict0dict.ic"
diff --git a/storage/xtradb/include/dict0dict.ic b/storage/xtradb/include/dict0dict.ic
index e3de7a33123..4ed1afc8094 100644
--- a/storage/xtradb/include/dict0dict.ic
+++ b/storage/xtradb/include/dict0dict.ic
@@ -1538,21 +1538,6 @@ dict_max_field_len_store_undo(
}
/********************************************************************//**
-Check whether the table is corrupted.
-@return nonzero for corrupted table, zero for valid tables */
-UNIV_INLINE
-ulint
-dict_table_is_corrupted(
-/*====================*/
- const dict_table_t* table) /*!< in: table */
-{
- ut_ad(table);
- ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-
- return(table->corrupted);
-}
-
-/********************************************************************//**
Check whether the index is corrupted.
@return nonzero for corrupted index, zero for valid indexes */
UNIV_INLINE
@@ -1564,7 +1549,7 @@ dict_index_is_corrupted(
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
return((index->type & DICT_CORRUPT)
- || (index->table && index->table->corrupted));
+ || (index->table && index->table->corrupted));
}
/********************************************************************//**
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index 96c85cd8a99..a32581a0e90 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2016, MariaDB Corporation.
+Copyright (c) 2013, 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
@@ -795,6 +795,9 @@ struct dict_index_t{
to first_blob_page_no; protected by
blobs_mutex; @see btr_blob_dbg_t */
#endif /* UNIV_BLOB_DEBUG */
+
+ bool is_readable() const;
+
#ifdef UNIV_DEBUG
ulint magic_n;/*!< magic number */
/** Value of dict_index_t::magic_n */
@@ -1062,11 +1065,13 @@ struct dict_table_t{
table is placed */
unsigned flags:DICT_TF_BITS; /*!< DICT_TF_... */
unsigned flags2:DICT_TF2_BITS; /*!< DICT_TF2_... */
- unsigned ibd_file_missing:1;
- /*!< TRUE if this is in a single-table
- tablespace and the .ibd file is missing; then
- we must return in ha_innodb.cc an error if the
- user tries to query such an orphaned table */
+ unsigned file_unreadable:1;
+ /*!< true if this is in a single-table
+ tablespace and the .ibd file is missing
+ or page decryption failed and page is
+ corrupted; then we must return in
+ ha_innodb.cc an error if the
+ user tries to query such table */
unsigned cached:1;/*!< TRUE if the table object has been added
to the dictionary cache */
unsigned to_be_dropped:1;
@@ -1364,10 +1369,19 @@ struct dict_table_t{
UT_LIST_BASE_NODE_T(lock_t)
locks; /*!< list of locks on the table; protected
by lock_sys->mutex */
- ibool is_corrupt;
- ibool is_encrypted;
+
#endif /* !UNIV_HOTBACKUP */
+ /* Returns true if this is a single-table tablespace
+ and the .ibd file is missing or page decryption failed
+ and/or page is corrupted.
+ @return true if table is readable
+ @retval false if table is not readable */
+ inline bool is_readable() const
+ {
+ return(UNIV_LIKELY(!file_unreadable));
+ }
+
#ifdef UNIV_DEBUG
ulint magic_n;/*!< magic number */
/** Value of dict_table_t::magic_n */
@@ -1375,6 +1389,16 @@ struct dict_table_t{
#endif /* UNIV_DEBUG */
};
+/* Returns true if this is a single-table tablespace
+and the .ibd file is missing or page decryption failed
+and/or page is corrupted.
+@return true if table is readable
+@retval false if table is not readable */
+inline bool dict_index_t::is_readable() const
+{
+ return(UNIV_LIKELY(!table->file_unreadable));
+}
+
/** A function object to add the foreign key constraint to the referenced set
of the referenced table, if it exists in the dictionary cache. */
struct dict_foreign_add_to_referenced_table {
diff --git a/storage/xtradb/include/fil0crypt.h b/storage/xtradb/include/fil0crypt.h
index e7e9676aa3a..228dfb895fe 100644
--- a/storage/xtradb/include/fil0crypt.h
+++ b/storage/xtradb/include/fil0crypt.h
@@ -117,8 +117,7 @@ struct fil_space_crypt_t : st_encryption_scheme
min_key_version(new_min_key_version),
page0_offset(0),
encryption(new_encryption),
- mutex(),
- key_found(new_min_key_version),
+ key_found(0),
rotate_state()
{
key_id = new_key_id;
@@ -136,6 +135,8 @@ struct fil_space_crypt_t : st_encryption_scheme
type = CRYPT_SCHEME_1;
min_key_version = key_get_latest_version();
}
+
+ key_found = min_key_version;
}
/** Destructor */
@@ -298,13 +299,15 @@ Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
@param[in] ptr Log entry start
@param[in] end_ptr Log entry end
@param[in] block buffer block
+@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED
@return position on log buffer */
UNIV_INTERN
-const byte*
+byte*
fil_parse_write_crypt_data(
- const byte* ptr,
+ byte* ptr,
const byte* end_ptr,
- const buf_block_t* block)
+ const buf_block_t* block,
+ dberr_t* err)
MY_ATTRIBUTE((warn_unused_result));
/******************************************************************
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index d73a68d9d34..2f03d2aa0f5 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -136,6 +136,7 @@ extern fil_addr_t fil_addr_null;
#define FIL_PAGE_DATA 38 /*!< start of the data on the page */
/* Following are used when page compression is used */
+
#define FIL_PAGE_COMPRESSED_SIZE 2 /*!< Number of bytes used to store
actual payload data size on
compressed pages. */
@@ -313,13 +314,21 @@ struct fil_space_t {
ulint n_pending_flushes; /*!< this is positive when flushing
the tablespace to disk; dropping of the
tablespace is forbidden if this is positive */
- ulint n_pending_ops;/*!< this is positive when we
- have pending operations against this
- tablespace. The pending operations can
- be ibuf merges or lock validation code
- trying to read a block.
- Dropping of the tablespace is forbidden
- if this is positive */
+ /** Number of pending buffer pool operations accessing the tablespace
+ without holding a table lock or dict_operation_lock S-latch
+ that would prevent the table (and tablespace) from being
+ dropped. An example is change buffer merge.
+ The tablespace cannot be dropped while this is nonzero,
+ or while fil_node_t::n_pending is nonzero.
+ Protected by fil_system->mutex. */
+ ulint n_pending_ops;
+ /** Number of pending block read or write operations
+ (when a write is imminent or a read has recently completed).
+ The tablespace object cannot be freed while this is nonzero,
+ but it can be detached from fil_system.
+ Note that fil_node_t::n_pending tracks actual pending I/O requests.
+ Protected by fil_system->mutex. */
+ ulint n_pending_ios;
hash_node_t hash; /*!< hash chain node */
hash_node_t name_hash;/*!< hash chain the name_hash table */
#ifndef UNIV_HOTBACKUP
@@ -650,13 +659,28 @@ fil_write_flushed_lsn_to_data_files(
Used by background threads that do not necessarily hold proper locks
for concurrency control.
@param[in] id tablespace ID
+@param[in] silent whether to silently ignore missing tablespaces
+@return the tablespace
+@retval NULL if missing or being deleted or truncated */
+UNIV_INTERN
+fil_space_t*
+fil_space_acquire_low(ulint id, bool silent)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/** Acquire a tablespace when it could be dropped concurrently.
+Used by background threads that do not necessarily hold proper locks
+for concurrency control.
+@param[in] id tablespace ID
@param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
+inline
fil_space_t*
-fil_space_acquire(ulint id, bool for_io = false)
- MY_ATTRIBUTE((warn_unused_result));
+fil_space_acquire(ulint id)
+{
+ return(fil_space_acquire_low(id, false));
+}
/** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks
@@ -664,15 +688,34 @@ for concurrency control.
@param[in] id tablespace ID
@return the tablespace
@retval NULL if missing or being deleted */
+inline
fil_space_t*
fil_space_acquire_silent(ulint id)
- MY_ATTRIBUTE((warn_unused_result));
+{
+ return(fil_space_acquire_low(id, true));
+}
/** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */
+UNIV_INTERN
void
fil_space_release(fil_space_t* space);
+/** Acquire a tablespace for reading or writing a block,
+when it could be dropped concurrently.
+@param[in] id tablespace ID
+@return the tablespace
+@retval NULL if missing */
+UNIV_INTERN
+fil_space_t*
+fil_space_acquire_for_io(ulint id);
+
+/** Release a tablespace acquired with fil_space_acquire_for_io().
+@param[in,out] space tablespace to release */
+UNIV_INTERN
+void
+fil_space_release_for_io(fil_space_t* space);
+
/** Return the next fil_space_t.
Once started, the caller must keep calling this until it returns NULL.
fil_space_acquire() and fil_space_release() are invoked here which
@@ -681,6 +724,7 @@ blocks a concurrent operation from dropping the tablespace.
If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t.
@retval NULL if this was the last */
+UNIV_INTERN
fil_space_t*
fil_space_next(
fil_space_t* prev_space)
@@ -694,11 +738,67 @@ blocks a concurrent operation from dropping the tablespace.
If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t.
@retval NULL if this was the last*/
+UNIV_INTERN
fil_space_t*
fil_space_keyrotate_next(
fil_space_t* prev_space)
MY_ATTRIBUTE((warn_unused_result));
+/** Wrapper with reference-counting for a fil_space_t. */
+class FilSpace
+{
+public:
+ /** Default constructor: Use this when reference counting
+ is done outside this wrapper. */
+ FilSpace() : m_space(NULL) {}
+
+ /** Constructor: Look up the tablespace and increment the
+ reference count if found.
+ @param[in] space_id tablespace ID
+ @param[in] silent whether not to print any errors */
+ explicit FilSpace(ulint space_id, bool silent = false)
+ : m_space(fil_space_acquire_low(space_id, silent)) {}
+
+ /** Assignment operator: This assumes that fil_space_acquire()
+ has already been done for the fil_space_t. The caller must
+ assign NULL if it calls fil_space_release().
+ @param[in] space tablespace to assign */
+ class FilSpace& operator=(fil_space_t* space)
+ {
+ /* fil_space_acquire() must have been invoked. */
+ ut_ad(space == NULL || space->n_pending_ops > 0);
+ m_space = space;
+ return(*this);
+ }
+
+ /** Destructor - Decrement the reference count if a fil_space_t
+ is still assigned. */
+ ~FilSpace()
+ {
+ if (m_space != NULL) {
+ fil_space_release(m_space);
+ }
+ }
+
+ /** Implicit type conversion
+ @return the wrapped object */
+ operator const fil_space_t*() const
+ {
+ return(m_space);
+ }
+
+ /** Explicit type conversion
+ @return the wrapped object */
+ const fil_space_t* operator()() const
+ {
+ return(m_space);
+ }
+
+private:
+ /** The wrapped pointer */
+ fil_space_t* m_space;
+};
+
/*******************************************************************//**
Reads the flushed lsn, arch no, and tablespace flag fields from a data
file at database startup.
@@ -721,22 +821,6 @@ fil_read_first_page(
fil_space_crypt_t** crypt_data) /*!< out: crypt data */
__attribute__((warn_unused_result));
-/*******************************************************************//**
-Increments the count of pending operation, if space is not being deleted.
-@return TRUE if being deleted, and operation should be skipped */
-UNIV_INTERN
-ibool
-fil_inc_pending_ops(
-/*================*/
- ulint id, /*!< in: space id */
- ibool print_err); /*!< in: need to print error or not */
-/*******************************************************************//**
-Decrements the count of pending operations. */
-UNIV_INTERN
-void
-fil_decr_pending_ops(
-/*=================*/
- ulint id); /*!< in: space id */
#endif /* !UNIV_HOTBACKUP */
/*******************************************************************//**
Parses the body of a log record written about an .ibd file operation. That is,
@@ -978,7 +1062,7 @@ space id is != 0.
@return DB_SUCCESS or error number */
UNIV_INTERN
dberr_t
-fil_load_single_table_tablespaces(void);
+fil_load_single_table_tablespaces(ibool (*pred)(const char*, const char*)=0);
/*===================================*/
/*******************************************************************//**
Returns TRUE if a single-table tablespace does not exist in the memory cache,
@@ -1017,6 +1101,9 @@ fil_space_for_table_exists_in_mem(
information to the .err log if a
matching tablespace is not found from
memory */
+ bool remove_from_data_dict_if_does_not_exist,
+ /*!< in: remove from the data dictionary
+ if tablespace does not exist */
bool adjust_space, /*!< in: whether to adjust space id
when find table space mismatch */
mem_heap_t* heap, /*!< in: heap memory */
@@ -1428,36 +1515,6 @@ fil_space_get_by_id(
/*================*/
ulint id); /*!< in: space id */
-/******************************************************************
-Get id of first tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space();
-/*=================*/
-
-/******************************************************************
-Get id of next tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space(
-/*===============*/
- ulint id); /*!< in: space id */
-
-/******************************************************************
-Get id of first tablespace that has node or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space_safe();
-/*======================*/
-
-/******************************************************************
-Get id of next tablespace that has node or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space_safe(
-/*====================*/
- ulint id); /*!< in: previous space id */
-
#endif /* UNIV_INNOCHECKSUM */
/****************************************************************//**
diff --git a/storage/xtradb/include/os0sync.h b/storage/xtradb/include/os0sync.h
index 48c56a73369..62f651413e1 100644
--- a/storage/xtradb/include/os0sync.h
+++ b/storage/xtradb/include/os0sync.h
@@ -2,6 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
+Copyright (c) 2017, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -38,12 +39,11 @@ Created 9/6/1995 Heikki Tuuri
#include "ut0lst.h"
#include "sync0types.h"
-#if defined __i386__ || defined __x86_64__ || defined _M_IX86 \
- || defined _M_X64 || defined __WIN__
-
-#define IB_STRONG_MEMORY_MODEL
-
-#endif /* __i386__ || __x86_64__ || _M_IX86 || _M_X64 || __WIN__ */
+#ifdef CPU_LEVEL1_DCACHE_LINESIZE
+# define CACHE_LINE_SIZE CPU_LEVEL1_DCACHE_LINESIZE
+#else
+# error CPU_LEVEL1_DCACHE_LINESIZE is undefined
+#endif /* CPU_LEVEL1_DCACHE_LINESIZE */
#ifdef HAVE_WINDOWS_ATOMICS
typedef LONG lock_word_t; /*!< On Windows, InterlockedExchange operates
@@ -940,6 +940,51 @@ for synchronization */
"Memory barrier is not used"
#endif
+
+/** Simple counter aligned to CACHE_LINE_SIZE
+@tparam Type the integer type of the counter
+@tparam atomic whether to use atomic memory access */
+template <typename Type = ulint, bool atomic = false>
+struct MY_ALIGNED(CACHE_LINE_SIZE) simple_counter
+{
+ /** Increment the counter */
+ Type inc() { return add(1); }
+ /** Decrement the counter */
+ Type dec() { return sub(1); }
+
+ /** Add to the counter
+ @param[in] i amount to be added
+ @return the value of the counter after adding */
+ Type add(Type i)
+ {
+ compile_time_assert(!atomic || sizeof(Type) == sizeof(ulint));
+ if (atomic) {
+ return os_atomic_increment_ulint(&m_counter, i);
+ } else {
+ return m_counter += i;
+ }
+ }
+ /** Subtract from the counter
+ @param[in] i amount to be subtracted
+ @return the value of the counter after adding */
+ Type sub(Type i)
+ {
+ compile_time_assert(!atomic || sizeof(Type) == sizeof(ulint));
+ if (atomic) {
+ return os_atomic_decrement_ulint(&m_counter, i);
+ } else {
+ return m_counter -= i;
+ }
+ }
+
+ /** @return the value of the counter (non-atomic access)! */
+ operator Type() const { return m_counter; }
+
+private:
+ /** The counter */
+ Type m_counter;
+};
+
#ifndef UNIV_NONINL
#include "os0sync.ic"
#endif
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index c18bc7c1fc3..cf7824d91e7 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -3,7 +3,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
-Copyright (c) 2013, 2017, MariaDB Corporation Ab. All Rights Reserved.
+Copyright (c) 2013, 2017, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -55,11 +55,10 @@ Created 10/10/1995 Heikki Tuuri
/* Global counters used inside InnoDB. */
struct srv_stats_t {
- typedef ib_counter_t<lsn_t, 1, single_indexer_t> lsn_ctr_1_t;
- typedef ib_counter_t<ulint, 1, single_indexer_t> ulint_ctr_1_t;
- typedef ib_counter_t<lint, 1, single_indexer_t> lint_ctr_1_t;
typedef ib_counter_t<ulint, 64> ulint_ctr_64_t;
- typedef ib_counter_t<ib_int64_t, 1, single_indexer_t> ib_int64_ctr_1_t;
+ typedef simple_counter<lsn_t> lsn_ctr_1_t;
+ typedef simple_counter<ulint> ulint_ctr_1_t;
+ typedef simple_counter<ib_int64_t> ib_int64_ctr_1_t;
/** Count the amount of data written in total (in bytes) */
ulint_ctr_1_t data_written;
@@ -73,8 +72,9 @@ struct srv_stats_t {
/** Amount of data written to the log files in bytes */
lsn_ctr_1_t os_log_written;
- /** Number of writes being done to the log files */
- lint_ctr_1_t os_log_pending_writes;
+ /** Number of writes being done to the log files.
+ Protected by log_sys->write_mutex. */
+ ulint_ctr_1_t os_log_pending_writes;
/** We increase this counter, when we don't have enough
space in the log buffer and have to flush it */
@@ -148,7 +148,7 @@ struct srv_stats_t {
ulint_ctr_1_t n_lock_wait_count;
/** Number of threads currently waiting on database locks */
- lint_ctr_1_t n_lock_wait_current_count;
+ simple_counter<ulint, true> n_lock_wait_current_count;
/** Number of rows read. */
ulint_ctr_64_t n_rows_read;
@@ -496,7 +496,9 @@ as enum type because the configure option takes unsigned integer type. */
extern ulong srv_innodb_stats_method;
#ifdef UNIV_LOG_ARCHIVE
-extern ibool srv_log_archive_on;
+extern bool srv_log_archive_on;
+extern bool srv_archive_recovery;
+extern ib_uint64_t srv_archive_recovery_limit_lsn;
#endif /* UNIV_LOG_ARCHIVE */
extern char* srv_file_flush_method_str;
@@ -547,6 +549,14 @@ extern ulong srv_pass_corrupt_table;
extern ulong srv_log_checksum_algorithm;
+extern bool srv_apply_log_only;
+
+extern bool srv_backup_mode;
+extern bool srv_close_files;
+extern bool srv_xtrabackup;
+
+#define IS_XTRABACKUP() (srv_xtrabackup)
+
extern my_bool srv_force_primary_key;
/* Helper macro to support srv_pass_corrupt_table checks. If 'cond' is FALSE,
diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h
index 0c18b657fd7..9bfffd09532 100644
--- a/storage/xtradb/include/trx0sys.h
+++ b/storage/xtradb/include/trx0sys.h
@@ -336,8 +336,9 @@ trx_sys_update_wsrep_checkpoint(
trx_sysf_t* sys_header, /*!< in: sys_header */
mtr_t* mtr); /*!< in: mtr */
-void
-/** Read WSREP checkpoint XID from sys header. */
+/** Read WSREP checkpoint XID from sys header.
+@return true on success, false on error. */
+bool
trx_sys_read_wsrep_checkpoint(
XID* xid); /*!< out: WSREP XID */
#endif /* WITH_WSREP */
diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index e698f08f15b..310053b9145 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -635,7 +635,7 @@ functions. */
#ifdef __WIN__
#define usleep(a) Sleep((a)/1000)
-typedef ulint os_thread_ret_t;
+typedef DWORD os_thread_ret_t;
#define OS_THREAD_DUMMY_RETURN return(0)
#else
typedef void* os_thread_ret_t;
diff --git a/storage/xtradb/include/ut0counter.h b/storage/xtradb/include/ut0counter.h
index 447484ba985..4f736428a17 100644
--- a/storage/xtradb/include/ut0counter.h
+++ b/storage/xtradb/include/ut0counter.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 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
@@ -48,8 +49,6 @@ Created 2012/04/12 by Sunny Bains
/** Get the offset into the counter array. */
template <typename Type, int N>
struct generic_indexer_t {
- /** Default constructor/destructor should be OK. */
-
/** @return offset within m_counter */
size_t offset(size_t index) const UNIV_NOTHROW {
return(((index % N) + 1) * (CACHE_LINE_SIZE / sizeof(Type)));
@@ -62,8 +61,6 @@ struct generic_indexer_t {
use the thread id. */
template <typename Type, int N>
struct get_sched_indexer_t : public generic_indexer_t<Type, N> {
- /** Default constructor/destructor should be OK. */
-
/* @return result from sched_getcpu(), the thread id if it fails. */
size_t get_rnd_index() const UNIV_NOTHROW {
@@ -80,31 +77,17 @@ struct get_sched_indexer_t : public generic_indexer_t<Type, N> {
/** Use the thread id to index into the counter array. */
template <typename Type, int N>
struct thread_id_indexer_t : public generic_indexer_t<Type, N> {
- /** Default constructor/destructor should are OK. */
-
/* @return a random number, currently we use the thread id. Where
thread id is represented as a pointer, it may not work as
effectively. */
size_t get_rnd_index() const UNIV_NOTHROW {
return((lint) os_thread_get_curr_id());
}
-};
-
-/** For counters wher N=1 */
-template <typename Type, int N=1>
-struct single_indexer_t {
- /** Default constructor/destructor should are OK. */
-
- /** @return offset within m_counter */
- size_t offset(size_t index) const UNIV_NOTHROW {
- ut_ad(N == 1);
- return((CACHE_LINE_SIZE / sizeof(Type)));
- }
- /* @return 1 */
- size_t get_rnd_index() const UNIV_NOTHROW {
- ut_ad(N == 1);
- return(1);
+ /** @return a random offset to the array */
+ size_t get_rnd_offset() const UNIV_NOTHROW
+ {
+ return(generic_indexer_t<Type, N>::offset(get_rnd_index()));
}
};
@@ -116,17 +99,11 @@ template <
typename Type,
int N = IB_N_SLOTS,
template<typename, int> class Indexer = thread_id_indexer_t>
-class ib_counter_t {
-public:
- ib_counter_t() { memset(m_counter, 0x0, sizeof(m_counter)); }
-
+struct MY_ALIGNED(CACHE_LINE_SIZE) ib_counter_t
+{
+#ifdef UNIV_DEBUG
~ib_counter_t()
{
- ut_ad(validate());
- }
-
- bool validate() UNIV_NOTHROW {
-#ifdef UNIV_DEBUG
size_t n = (CACHE_LINE_SIZE / sizeof(Type));
/* Check that we aren't writing outside our defined bounds. */
@@ -135,27 +112,23 @@ public:
ut_ad(m_counter[i + j] == 0);
}
}
-#endif /* UNIV_DEBUG */
- return(true);
}
+#endif /* UNIV_DEBUG */
- /** If you can't use a good index id. Increment by 1. */
+ /** Increment the counter by 1. */
void inc() UNIV_NOTHROW { add(1); }
- /** If you can't use a good index id.
- * @param n - is the amount to increment */
- void add(Type n) UNIV_NOTHROW {
- size_t i = m_policy.offset(m_policy.get_rnd_index());
-
- ut_ad(i < UT_ARR_SIZE(m_counter));
+ /** Increment the counter by 1.
+ @param[in] index a reasonably thread-unique identifier */
+ void inc(size_t index) UNIV_NOTHROW { add(index, 1); }
- m_counter[i] += n;
- }
+ /** Add to the counter.
+ @param[in] n amount to be added */
+ void add(Type n) UNIV_NOTHROW { add(m_policy.get_rnd_offset(), n); }
- /** Use this if you can use a unique indentifier, saves a
- call to get_rnd_index().
- @param i - index into a slot
- @param n - amount to increment */
+ /** Add to the counter.
+ @param[in] index a reasonably thread-unique identifier
+ @param[in] n amount to be added */
void add(size_t index, Type n) UNIV_NOTHROW {
size_t i = m_policy.offset(index);
@@ -164,31 +137,6 @@ public:
m_counter[i] += n;
}
- /** If you can't use a good index id. Decrement by 1. */
- void dec() UNIV_NOTHROW { sub(1); }
-
- /** If you can't use a good index id.
- * @param - n is the amount to decrement */
- void sub(Type n) UNIV_NOTHROW {
- size_t i = m_policy.offset(m_policy.get_rnd_index());
-
- ut_ad(i < UT_ARR_SIZE(m_counter));
-
- m_counter[i] -= n;
- }
-
- /** Use this if you can use a unique indentifier, saves a
- call to get_rnd_index().
- @param i - index into a slot
- @param n - amount to decrement */
- void sub(size_t index, Type n) UNIV_NOTHROW {
- size_t i = m_policy.offset(index);
-
- ut_ad(i < UT_ARR_SIZE(m_counter));
-
- m_counter[i] -= n;
- }
-
/* @return total value - not 100% accurate, since it is not atomic. */
operator Type() const UNIV_NOTHROW {
Type total = 0;
diff --git a/storage/xtradb/lock/lock0wait.cc b/storage/xtradb/lock/lock0wait.cc
index 8f9ea7e10aa..a447027e336 100644
--- a/storage/xtradb/lock/lock0wait.cc
+++ b/storage/xtradb/lock/lock0wait.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2014, 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
@@ -273,6 +273,9 @@ lock_wait_suspend_thread(
slot = lock_wait_table_reserve_slot(thr, lock_wait_timeout);
+ lock_wait_mutex_exit();
+ trx_mutex_exit(trx);
+
if (thr->lock_state == QUE_THR_LOCK_ROW) {
srv_stats.n_lock_wait_count.inc();
srv_stats.n_lock_wait_current_count.inc();
@@ -284,19 +287,21 @@ lock_wait_suspend_thread(
}
}
- lock_wait_mutex_exit();
- trx_mutex_exit(trx);
-
ulint lock_type = ULINT_UNDEFINED;
- lock_mutex_enter();
-
+ /* The wait_lock can be cleared by another thread when the
+ lock is released. But the wait can only be initiated by the
+ current thread which owns the transaction. Only acquire the
+ mutex if the wait_lock is still active. */
if (const lock_t* wait_lock = trx->lock.wait_lock) {
- lock_type = lock_get_type_low(wait_lock);
+ lock_mutex_enter();
+ wait_lock = trx->lock.wait_lock;
+ if (wait_lock) {
+ lock_type = lock_get_type_low(wait_lock);
+ }
+ lock_mutex_exit();
}
- lock_mutex_exit();
-
had_dict_lock = trx->dict_operation_lock_mode;
switch (had_dict_lock) {
diff --git a/storage/xtradb/log/log0crypt.cc b/storage/xtradb/log/log0crypt.cc
index e6b5c845757..f6c1416d81a 100644
--- a/storage/xtradb/log/log0crypt.cc
+++ b/storage/xtradb/log/log0crypt.cc
@@ -25,8 +25,7 @@ Modified Jan Lindström jan.lindstrom@mariadb.com
*******************************************************/
#include "m_string.h"
#include "log0crypt.h"
-#include <my_crypt.h>
-#include <my_crypt.h>
+#include <mysql/service_my_crypt.h>
#include "log0log.h"
#include "srv0start.h" // for srv_start_lsn
@@ -34,8 +33,6 @@ Modified Jan Lindström jan.lindstrom@mariadb.com
#include "ha_prototypes.h" // IB_LOG_
-#include "my_crypt.h"
-
/* Used for debugging */
// #define DEBUG_CRYPT 1
#define UNENCRYPTED_KEY_VER 0
diff --git a/storage/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc
index 25c8ed06981..309de7daaf8 100644
--- a/storage/xtradb/log/log0log.cc
+++ b/storage/xtradb/log/log0log.cc
@@ -2629,7 +2629,7 @@ loop:
start_lsn += len;
buf += len;
- if (recv_sys->report(ut_time())) {
+ if (recv_sys && recv_sys->report(ut_time())) {
ib_logf(IB_LOG_LEVEL_INFO, "Read redo log up to LSN=" LSN_PF,
start_lsn);
sd_notifyf(0, "STATUS=Read redo log up to LSN=" LSN_PF,
diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc
index 120f1432ccf..978e6051711 100644
--- a/storage/xtradb/log/log0recv.cc
+++ b/storage/xtradb/log/log0recv.cc
@@ -692,7 +692,6 @@ recv_synchronize_groups(
/***********************************************************************//**
Checks the consistency of the checkpoint info
@return TRUE if ok */
-static
ibool
recv_check_cp_is_consistent(
/*========================*/
@@ -722,7 +721,7 @@ recv_check_cp_is_consistent(
/********************************************************//**
Looks for the maximum consistent checkpoint from the log groups.
@return error code or DB_SUCCESS */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
recv_find_max_checkpoint(
/*=====================*/
@@ -1383,7 +1382,12 @@ recv_parse_or_apply_log_rec_body(
}
break;
case MLOG_FILE_WRITE_CRYPT_DATA:
- ptr = const_cast<byte*>(fil_parse_write_crypt_data(ptr, end_ptr, block));
+ dberr_t err;
+ ptr = const_cast<byte*>(fil_parse_write_crypt_data(ptr, end_ptr, block, &err));
+
+ if (err != DB_SUCCESS) {
+ recv_sys->found_corrupt_log = TRUE;
+ }
break;
default:
ptr = NULL;
@@ -1868,6 +1872,11 @@ recv_apply_hashed_log_recs(bool last_batch)
break;
}
+ if (recv_sys->found_corrupt_log) {
+ mutex_exit(&recv_sys->mutex);
+ return;
+ }
+
mutex_exit(&recv_sys->mutex);
os_thread_sleep(500000);
}
@@ -1932,6 +1941,10 @@ recv_apply_hashed_log_recs(bool last_batch)
mutex_exit(&(recv_sys->mutex));
+ if (recv_sys->found_corrupt_log) {
+ return;
+ }
+
os_thread_sleep(500000);
mutex_enter(&(recv_sys->mutex));
@@ -3460,6 +3473,7 @@ recv_recovery_from_checkpoint_finish(void)
#ifdef __WIN__
if (recv_writer_thread_handle) {
CloseHandle(recv_writer_thread_handle);
+ recv_writer_thread_handle = 0;
}
#endif /* __WIN__ */
@@ -3686,6 +3700,102 @@ recv_reset_log_files_for_backup(
}
#endif /* UNIV_HOTBACKUP */
+/******************************************************//**
+Checks the 4-byte checksum to the trailer checksum field of a log
+block. We also accept a log block in the old format before
+InnoDB-3.23.52 where the checksum field contains the log block number.
+@return TRUE if ok, or if the log block may be in the format of InnoDB
+version predating 3.23.52 */
+UNIV_INTERN
+ibool
+log_block_checksum_is_ok_or_old_format(
+/*===================================*/
+ const byte* block) /*!< in: pointer to a log block */
+{
+#ifdef UNIV_LOG_DEBUG
+ return(TRUE);
+#endif /* UNIV_LOG_DEBUG */
+
+ ulint block_checksum = log_block_get_checksum(block);
+
+ if (UNIV_LIKELY(srv_log_checksum_algorithm ==
+ SRV_CHECKSUM_ALGORITHM_NONE ||
+ log_block_calc_checksum(block) == block_checksum)) {
+
+ return(TRUE);
+ }
+
+ if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32 ||
+ srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB ||
+ srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_NONE) {
+
+ const char* algo = NULL;
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "log block checksum mismatch: expected " ULINTPF ", "
+ "calculated checksum " ULINTPF,
+ block_checksum,
+ log_block_calc_checksum(block));
+
+ if (block_checksum == LOG_NO_CHECKSUM_MAGIC) {
+
+ algo = "none";
+ } else if (block_checksum ==
+ log_block_calc_checksum_crc32(block)) {
+
+ algo = "crc32";
+ } else if (block_checksum ==
+ log_block_calc_checksum_innodb(block)) {
+
+ algo = "innodb";
+ }
+
+ if (algo) {
+
+ const char* current_algo;
+
+ current_algo = buf_checksum_algorithm_name(
+ (srv_checksum_algorithm_t)
+ srv_log_checksum_algorithm);
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "current InnoDB log checksum type: %s, "
+ "detected log checksum type: %s",
+ current_algo,
+ algo);
+ }
+
+ ib_logf(IB_LOG_LEVEL_FATAL,
+ "STRICT method was specified for innodb_log_checksum, "
+ "so we intentionally assert here.");
+ }
+
+ ut_ad(srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_CRC32 ||
+ srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_INNODB);
+
+ if (block_checksum == LOG_NO_CHECKSUM_MAGIC ||
+ block_checksum == log_block_calc_checksum_crc32(block) ||
+ block_checksum == log_block_calc_checksum_innodb(block)) {
+
+ return(TRUE);
+ }
+
+ if (log_block_get_hdr_no(block) == block_checksum) {
+
+ /* We assume the log block is in the format of
+ InnoDB version < 3.23.52 and the block is ok */
+#if 0
+ fprintf(stderr,
+ "InnoDB: Scanned old format < InnoDB-3.23.52"
+ " log block number %lu\n",
+ log_block_get_hdr_no(block));
+#endif
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
void recv_dblwr_t::add(byte* page)
{
pages.push_back(page);
diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc
index 03200fee80b..4f219b18428 100644
--- a/storage/xtradb/os/os0file.cc
+++ b/storage/xtradb/os/os0file.cc
@@ -130,7 +130,7 @@ UNIV_INTERN os_ib_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];
#define OS_AIO_MERGE_N_CONSECUTIVE 64
#ifdef WITH_INNODB_DISALLOW_WRITES
-#define WAIT_ALLOW_WRITES() os_event_wait(srv_allow_writes_event)
+#define WAIT_ALLOW_WRITES() if (!IS_XTRABACKUP()) os_event_wait(srv_allow_writes_event)
#else
#define WAIT_ALLOW_WRITES() do { } while (0)
#endif /* WITH_INNODB_DISALLOW_WRITES */
@@ -1001,7 +1001,6 @@ os_file_lock(
#ifndef UNIV_HOTBACKUP
/****************************************************************//**
Creates the seek mutexes used in positioned reads and writes. */
-static
void
os_io_init_simple(void)
/*===================*/
@@ -1640,6 +1639,10 @@ os_file_create_simple_no_error_handling_func(
return((os_file_t) -1);
}
+ if (IS_XTRABACKUP()) {
+ share_mode |= FILE_SHARE_DELETE | FILE_SHARE_WRITE;
+ }
+
file = CreateFile((LPCTSTR) name,
access,
share_mode,
@@ -1921,7 +1924,10 @@ os_file_create_func(
create_mode &= ~OS_FILE_ON_ERROR_NO_EXIT;
create_mode &= ~OS_FILE_ON_ERROR_SILENT;
-
+ if (srv_backup_mode){
+ /* Permit others to write, while I'm reading. */
+ share_mode |= FILE_SHARE_WRITE;
+ }
if (create_mode == OS_FILE_OPEN_RAW) {
ut_a(!srv_read_only_mode);
@@ -3525,7 +3531,7 @@ os_file_get_status(
fh = CreateFile(
(LPCTSTR) path, // File to open
access,
- 0, // No sharing
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, // Default security
OPEN_EXISTING, // Existing file only
FILE_ATTRIBUTE_NORMAL, // Normal file
diff --git a/storage/xtradb/row/row0import.cc b/storage/xtradb/row/row0import.cc
index baa7bcbea09..81d6fda9e53 100644
--- a/storage/xtradb/row/row0import.cc
+++ b/storage/xtradb/row/row0import.cc
@@ -2030,15 +2030,12 @@ 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_zip_size(), space)
+ if (buf_page_is_corrupted(false, page, get_zip_size(), NULL)
|| (page_get_page_no(page) != offset / m_page_size
&& page_get_page_no(page) != 0)) {
@@ -2201,7 +2198,7 @@ row_import_discard_changes(
index->space = FIL_NULL;
}
- table->ibd_file_missing = TRUE;
+ table->file_unreadable = true;
fil_close_tablespace(trx, table->space);
}
@@ -3447,7 +3444,7 @@ row_import_for_mysql(
ut_a(table->space);
ut_ad(prebuilt->trx);
- ut_a(table->ibd_file_missing);
+ ut_a(table->file_unreadable);
trx_start_if_not_started(prebuilt->trx);
@@ -3752,7 +3749,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;
if (autoinc != 0) {
diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc
index 8dbf093a17d..f4f96d32c50 100644
--- a/storage/xtradb/row/row0ins.cc
+++ b/storage/xtradb/row/row0ins.cc
@@ -1518,7 +1518,7 @@ run_again:
}
if (check_table == NULL
- || check_table->ibd_file_missing
+ || check_table->file_unreadable
|| check_index == NULL) {
if (!srv_read_only_mode && check_ref) {
@@ -2410,8 +2410,7 @@ row_ins_clust_index_entry_low(
&cursor, 0, __FILE__, __LINE__, &mtr);
if (err != DB_SUCCESS) {
- index->table->is_encrypted = true;
- index->table->ibd_file_missing = true;
+ index->table->file_unreadable = true;
mtr_commit(&mtr);
goto func_exit;
}
@@ -2771,7 +2770,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/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc
index a17ee405720..666b59b42db 100644
--- a/storage/xtradb/row/row0log.cc
+++ b/storage/xtradb/row/row0log.cc
@@ -3674,7 +3674,7 @@ row_log_apply(
rw_lock_x_lock(dict_index_get_lock(index));
- if (!dict_table_is_corrupted(index->table)) {
+ if (!index->table->corrupted) {
error = row_log_apply_ops(trx, index, &dup);
} else {
error = DB_SUCCESS;
diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc
index 24cd9687a47..57b08801225 100644
--- a/storage/xtradb/row/row0merge.cc
+++ b/storage/xtradb/row/row0merge.cc
@@ -1620,7 +1620,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;
@@ -3695,7 +3696,7 @@ row_merge_rename_tables_dict(
table is in a non-system tablespace where space > 0. */
if (err == DB_SUCCESS
&& old_table->space != TRX_SYS_SPACE
- && !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);
@@ -4005,6 +4006,7 @@ row_merge_build_indexes(
os_mem_alloc_large(&block_size));
if (crypt_block == NULL) {
+ fil_space_release(space);
DBUG_RETURN(DB_OUT_OF_MEMORY);
}
} else {
@@ -4070,13 +4072,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/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc
index 7c8636d354f..463981f51dd 100644
--- a/storage/xtradb/row/row0mysql.cc
+++ b/storage/xtradb/row/row0mysql.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2000, 2016, 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
@@ -663,6 +663,7 @@ handle_new_error:
abort();
case DB_CORRUPTION:
+ case DB_PAGE_CORRUPTED:
fputs("InnoDB: We detected index corruption"
" in an InnoDB type table.\n"
"InnoDB: You have to dump + drop + reimport"
@@ -1280,6 +1281,71 @@ run_again:
}
/*********************************************************************//**
+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
+@return DB_DECRYPTION_FAILED table is encrypted but decryption failed
+DB_CORRUPTION table is corrupted
+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 = DB_SUCCESS;
+ FilSpace space(table->space, true);
+ char buf[MAX_FULL_NAME_LEN];
+ ut_format_name(table->name, TRUE, buf, sizeof(buf));
+
+ if (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,HA_ERR_DECRYPTION_FAILED,
+ "Table %s in file %s is encrypted but encryption service or"
+ " used key_id %u is not available. "
+ " Can't continue reading table.",
+ buf, space()->chain.start->name,
+ space()->crypt_data->key_id);
+ }
+
+ err = DB_DECRYPTION_FAILED;
+ } else {
+ if (push_warning) {
+ ib_push_warning(trx, DB_CORRUPTION,
+ "Table %s in file %s corrupted.",
+ buf, space()->chain.start->name);
+ }
+
+ err = DB_CORRUPTION;
+ }
+
+ } else {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "InnoDB: MySQL is trying to use a table handle"
+ " but the .ibd file for"
+ " table %s does not exist."
+ " Have you deleted the .ibd file"
+ " from the database directory under"
+ " the MySQL datadir, or have you"
+ " used DISCARD TABLESPACE?"
+ " Look from " REFMAN "innodb-troubleshooting.html"
+ " how you can resolve the problem.",
+ buf);
+
+ err = DB_TABLESPACE_NOT_FOUND;
+ }
+
+ return (err);
+}
+
+/*********************************************************************//**
Does an insert for MySQL.
@return error code or DB_SUCCESS */
UNIV_INTERN
@@ -1308,20 +1374,8 @@ row_insert_for_mysql(
return(DB_TABLESPACE_DELETED);
- } else if (prebuilt->table->ibd_file_missing) {
-
- ib_logf(IB_LOG_LEVEL_ERROR,
- ".ibd file is missing for table %s",
- 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 %lu 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 (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
@@ -1460,11 +1514,10 @@ error_exit:
que_thr_stop_for_mysql_no_error(thr, trx);
if (UNIV_LIKELY(!(trx->fake_changes))) {
-
if (table->is_system_db) {
- srv_stats.n_system_rows_inserted.add((size_t)trx->id, 1);
+ srv_stats.n_system_rows_inserted.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_inserted.add((size_t)trx->id, 1);
+ srv_stats.n_rows_inserted.inc(size_t(trx->id));
}
if (prebuilt->clust_index_was_generated) {
@@ -1712,28 +1765,8 @@ row_update_for_mysql(
ut_ad(trx != NULL);
UT_NOT_USED(mysql_rec);
- if (prebuilt->table->ibd_file_missing) {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Error:\n"
- "InnoDB: MySQL is trying to use a table handle"
- " but the .ibd file for\n"
- "InnoDB: table %s does not exist.\n"
- "InnoDB: Have you deleted the .ibd file"
- " from the database directory under\n"
- "InnoDB: the MySQL datadir, or have you"
- " used DISCARD TABLESPACE?\n"
- "InnoDB: Look from\n"
- "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
- "InnoDB: how you can resolve the problem.\n",
- prebuilt->table->name);
- return(DB_ERROR);
- } else if (prebuilt->table->is_encrypted) {
- 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.",
- 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 (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
@@ -1873,17 +1906,15 @@ run_again:
dict_table_n_rows_dec(prebuilt->table);
if (table->is_system_db) {
- srv_stats.n_system_rows_deleted.add(
- (size_t)trx->id, 1);
+ srv_stats.n_system_rows_deleted.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_deleted.add((size_t)trx->id, 1);
+ srv_stats.n_rows_deleted.inc(size_t(trx->id));
}
} else {
if (table->is_system_db) {
- srv_stats.n_system_rows_updated.add(
- (size_t)trx->id, 1);
+ srv_stats.n_system_rows_updated.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));
}
}
@@ -2121,17 +2152,15 @@ run_again:
dict_table_n_rows_dec(table);
if (table->is_system_db) {
- srv_stats.n_system_rows_deleted.add(
- (size_t)trx->id, 1);
+ srv_stats.n_system_rows_deleted.inc(size_t(trx->id));
} else {
- srv_stats.n_rows_deleted.add((size_t)trx->id, 1);
+ srv_stats.n_rows_deleted.inc(size_t(trx->id));
}
} else {
if (table->is_system_db) {
- srv_stats.n_system_rows_updated.add(
- (size_t)trx->id, 1);
+ srv_stats.n_system_rows_updated.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));
}
}
@@ -3128,7 +3157,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;
@@ -3185,8 +3214,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 (table->space == TRX_SYS_SPACE) {
char table_name[MAX_FULL_NAME_LEN + 1];
@@ -3401,10 +3428,8 @@ row_truncate_table_for_mysql(
if (dict_table_is_discarded(table)) {
return(DB_TABLESPACE_DELETED);
- } else if (table->is_encrypted) {
- return(DB_DECRYPTION_FAILED);
- } else if (table->ibd_file_missing) {
- return(DB_TABLESPACE_NOT_FOUND);
+ } else if (!table->is_readable()) {
+ return (row_mysql_get_table_status(table, trx, true));
}
trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
@@ -3570,7 +3595,7 @@ row_truncate_table_for_mysql(
"create a new tablespace",
table->name);
- table->ibd_file_missing = 1;
+ table->file_unreadable = true;
err = DB_ERROR;
goto funct_exit;
}
@@ -3994,19 +4019,6 @@ row_drop_table_for_mysql(
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;
- }
-
/* Turn on this drop bit before we could release the dictionary
latch */
table->to_be_dropped = true;
@@ -4378,7 +4390,7 @@ row_drop_table_for_mysql(
from table->heap, which will be freed by
dict_table_remove_from_cache(table) below. */
space_id = table->space;
- ibd_file_missing = table->ibd_file_missing;
+ ibd_file_missing = table->file_unreadable;
table_flags = table->flags;
is_temp = DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY);
@@ -4389,7 +4401,8 @@ row_drop_table_for_mysql(
have a temp flag but not know the temp path */
ut_a(table->dir_path_of_temp_table == NULL || is_temp);
if (dict_table_is_discarded(table)
- || table->ibd_file_missing) {
+ || (!table->is_readable()
+ && fil_space_get(table->space) == NULL)) {
/* Do not attempt to drop known-to-be-missing
tablespaces. */
space_id = 0;
@@ -4465,8 +4478,9 @@ row_drop_table_for_mysql(
if (!is_temp
&& !fil_space_for_table_exists_in_mem(
space_id, tablename,
- print_msg, false, NULL, 0,
+ print_msg, IS_XTRABACKUP() && print_msg, false, NULL, 0,
table_flags)) {
+
/* This might happen if we are dropping a
discarded tablespace */
err = DB_SUCCESS;
@@ -4801,7 +4815,8 @@ loop:
"'%s.frm' was lost.", table->name);
}
- if (table->ibd_file_missing) {
+ if (!table->is_readable()
+ && fil_space_get(table->space) == NULL) {
ib_logf(IB_LOG_LEVEL_WARN,
"Missing %s.ibd file for table %s.",
table->name, table->name);
@@ -5075,7 +5090,8 @@ row_rename_table_for_mysql(
stderr);
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;
@@ -5145,7 +5161,7 @@ row_rename_table_for_mysql(
which have space IDs > 0. */
if (err == DB_SUCCESS
&& table->space != TRX_SYS_SPACE
- && !table->ibd_file_missing) {
+ && table->is_readable()) {
/* Make a new pathname to update SYS_DATAFILES. */
char* new_path = row_make_new_pathname(table, new_name);
diff --git a/storage/xtradb/row/row0purge.cc b/storage/xtradb/row/row0purge.cc
index 35b3520749b..8a1dbd6f69f 100644
--- a/storage/xtradb/row/row0purge.cc
+++ b/storage/xtradb/row/row0purge.cc
@@ -777,7 +777,7 @@ row_purge_parse_undo_rec(
goto err_exit;
}
- if (node->table->ibd_file_missing) {
+ if (node->table->file_unreadable) {
/* We skip purge of missing .ibd files */
dict_table_close(node->table, FALSE, FALSE);
diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index 29569bb31e7..7d4435eba5b 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -62,6 +62,7 @@ Created 12/19/1997 Heikki Tuuri
#include "srv0start.h"
#include "m_string.h" /* for my_sys.h */
#include "my_sys.h" /* DEBUG_SYNC_C */
+#include "fil0fil.h"
#include "my_compare.h" /* enum icp_result */
@@ -3046,11 +3047,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);
@@ -3728,13 +3730,12 @@ row_search_for_mysql(
return(DB_TABLESPACE_DELETED);
- } else if (prebuilt->table->ibd_file_missing) {
-
- return(DB_TABLESPACE_NOT_FOUND);
-
- } else if (prebuilt->table->is_encrypted) {
-
- return(DB_DECRYPTION_FAILED);
+ } else if (!prebuilt->table->is_readable()) {
+ if (fil_space_get(prebuilt->table->space) == NULL) {
+ return(DB_TABLESPACE_NOT_FOUND);
+ } else {
+ return(DB_DECRYPTION_FAILED);
+ }
} else if (!prebuilt->index_usable) {
return(DB_MISSING_HISTORY);
@@ -4193,7 +4194,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;
@@ -4213,7 +4214,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;
}
@@ -4305,7 +4306,7 @@ rec_loop:
wrong_offs:
if (srv_pass_corrupt_table && index->table->space != 0 &&
index->table->space < SRV_LOG_SPACE_FIRST_ID) {
- index->table->is_corrupt = TRUE;
+ index->table->file_unreadable = TRUE;
fil_space_set_corrupt(index->table->space);
}
@@ -4366,20 +4367,22 @@ wrong_offs:
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(srv_force_recovery > 0
- || (index->table->is_corrupt &&
+ || (!index->table->is_readable() &&
srv_pass_corrupt_table == 2))) {
if (!rec_validate(rec, offsets)
|| !btr_index_rec_validate(rec, index, FALSE)) {
- fprintf(stderr,
- "InnoDB: Index corruption: rec offs %lu"
- " next offs %lu, page no %lu,\n"
- "InnoDB: ",
- (ulong) page_offset(rec),
- (ulong) next_offs,
- (ulong) page_get_page_no(page_align(rec)));
- dict_index_name_print(stderr, trx, index);
- fputs(". We try to skip the record.\n",
- stderr);
+ char buf[MAX_FULL_NAME_LEN];
+ ut_format_name(index->table->name, FALSE, buf, sizeof(buf));
+
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Index %s corrupted: rec offs " ULINTPF
+ " next offs " ULINTPF
+ ", page no " ULINTPF " ."
+ " We try to skip the record.",
+ buf,
+ page_offset(rec),
+ next_offs,
+ page_get_page_no(page_align(rec)));
goto next_rec;
}
diff --git a/storage/xtradb/row/row0uins.cc b/storage/xtradb/row/row0uins.cc
index 651042fb820..f14a4ef9bcf 100644
--- a/storage/xtradb/row/row0uins.cc
+++ b/storage/xtradb/row/row0uins.cc
@@ -320,7 +320,7 @@ row_undo_ins_parse_undo_rec(
/* Skip the UNDO if we can't find the table or the .ibd file. */
if (UNIV_UNLIKELY(node->table == NULL)) {
- } else if (UNIV_UNLIKELY(node->table->ibd_file_missing)) {
+ } else if (UNIV_UNLIKELY(node->table->file_unreadable)) {
close_table:
dict_table_close(node->table, dict_locked, FALSE);
node->table = NULL;
diff --git a/storage/xtradb/row/row0umod.cc b/storage/xtradb/row/row0umod.cc
index 19576d976bd..8deba4f00a5 100644
--- a/storage/xtradb/row/row0umod.cc
+++ b/storage/xtradb/row/row0umod.cc
@@ -1068,7 +1068,7 @@ row_undo_mod_parse_undo_rec(
return;
}
- if (node->table->ibd_file_missing) {
+ if (node->table->file_unreadable) {
dict_table_close(node->table, dict_locked, FALSE);
/* We skip undo operations to missing .ibd files */
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index 1c40baee04b..bf4b9124da7 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -203,7 +203,7 @@ performance killer causing calling thread to context switch. Besides, Innodb
is preallocating large number (often millions) of os_events. With kernel event
objects it takes a big chunk out of non-paged pool, which is better suited
for tasks like IO than for storing idle event objects. */
-UNIV_INTERN ibool srv_use_native_conditions = FALSE;
+UNIV_INTERN ibool srv_use_native_conditions = TRUE;
#endif /* __WIN__ */
UNIV_INTERN ulint srv_n_data_files = 0;
@@ -366,7 +366,9 @@ readahead request. */
UNIV_INTERN ulong srv_read_ahead_threshold = 56;
#ifdef UNIV_LOG_ARCHIVE
-UNIV_INTERN ibool srv_log_archive_on = FALSE;
+UNIV_INTERN bool srv_log_archive_on;
+UNIV_INTERN bool srv_archive_recovery;
+UNIV_INTERN ib_uint64_t srv_archive_recovery_limit_lsn;
#endif /* UNIV_LOG_ARCHIVE */
/* This parameter is used to throttle the number of insert buffers that are
@@ -522,6 +524,12 @@ UNIV_INTERN ulong srv_doublewrite_batch_size = 120;
UNIV_INTERN ulong srv_replication_delay = 0;
+UNIV_INTERN bool srv_apply_log_only;
+
+UNIV_INTERN bool srv_backup_mode;
+UNIV_INTERN bool srv_close_files;
+UNIV_INTERN bool srv_xtrabackup;
+
UNIV_INTERN ulong srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
UNIV_INTERN ulong srv_log_checksum_algorithm =
diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index 5255a7454ea..aa51012816d 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -140,7 +140,7 @@ SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
UNIV_INTERN enum srv_shutdown_state srv_shutdown_state = SRV_SHUTDOWN_NONE;
/** Files comprising the system tablespace */
-static os_file_t files[1000];
+os_file_t files[1000];
/** io_handler_thread parameters for thread identification */
static ulint n[SRV_MAX_N_IO_THREADS];
@@ -826,7 +826,7 @@ open_log_file(
/*********************************************************************//**
Creates or opens database data files and closes them.
@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
open_or_create_data_files(
/*======================*/
@@ -1080,8 +1080,10 @@ skip_size_check:
/* This is the earliest location where we can load
the double write buffer. */
if (i == 0) {
+ /* XtraBackup never loads corrupted pages from
+ the doublewrite buffer */
buf_dblwr_init_or_load_pages(
- files[i], srv_data_file_names[i], true);
+ files[i], srv_data_file_names[i], !IS_XTRABACKUP());
}
bool retry = true;
@@ -1365,12 +1367,15 @@ srv_undo_tablespace_open(
/********************************************************************
Opens the configured number of undo tablespaces.
@return DB_SUCCESS or error code */
-static
dberr_t
srv_undo_tablespaces_init(
/*======================*/
ibool create_new_db, /*!< in: TRUE if new db being
created */
+ ibool backup_mode, /*!< in: TRUE disables reading
+ the system tablespace (used in
+ XtraBackup), FALSE is passed on
+ recovery. */
const ulint n_conf_tablespaces, /*!< in: configured undo
tablespaces */
ulint* n_opened) /*!< out: number of UNDO
@@ -1424,7 +1429,7 @@ srv_undo_tablespaces_init(
we build the undo_tablespace_ids ourselves since they don't
already exist. */
- if (!create_new_db) {
+ if (!create_new_db && !backup_mode) {
n_undo_tablespaces = trx_rseg_get_n_undo_tablespaces(
undo_tablespace_ids);
} else {
@@ -2287,11 +2292,11 @@ innobase_start_or_create_for_mysql(void)
max_flushed_lsn = min_flushed_lsn
= log_get_lsn();
goto files_checked;
- } else if (i < 2) {
- /* must have at least 2 log files */
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Only one log file found.");
- return(err);
+ } else if (i < 2 && !IS_XTRABACKUP()) {
+ /* must have at least 2 log files */
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Only one log file found.");
+ return(err);
}
/* opened all files */
@@ -2385,6 +2390,7 @@ files_checked:
err = srv_undo_tablespaces_init(
create_new_db,
+ FALSE,
srv_undo_tablespaces,
&srv_undo_tablespaces_open);
@@ -2531,6 +2537,11 @@ files_checked:
recv_group_scan_log_recs(). */
recv_apply_hashed_log_recs(true);
+
+ if (recv_sys->found_corrupt_log) {
+ return (DB_CORRUPTION);
+ }
+
DBUG_PRINT("ib_log", ("apply completed"));
}
@@ -2653,6 +2664,17 @@ files_checked:
dict_check_tablespaces_and_store_max_id(dict_check);
}
+ if (IS_XTRABACKUP()
+ && !srv_backup_mode
+ && srv_read_only_mode
+ && srv_log_file_size_requested != srv_log_file_size) {
+
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Log files size mismatch, ignored in readonly mode");
+ srv_log_file_size_requested = srv_log_file_size;
+ }
+
+
if (!srv_force_recovery
&& !recv_sys->found_corrupt_log
&& (srv_log_file_size_requested != srv_log_file_size
@@ -3287,7 +3309,8 @@ innobase_shutdown_for_mysql(void)
srv_was_started = FALSE;
srv_start_has_been_called = FALSE;
-
+ /* reset io_tid_i, in case current process does second innodb start (xtrabackup might do that).*/
+ io_tid_i = 0;
return(DB_SUCCESS);
}
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc
index 1c4fb19430e..558fe8a2c49 100644
--- a/storage/xtradb/trx/trx0sys.cc
+++ b/storage/xtradb/trx/trx0sys.cc
@@ -404,7 +404,7 @@ trx_sys_update_wsrep_checkpoint(
}
-void
+bool
trx_sys_read_wsrep_checkpoint(XID* xid)
/*===================================*/
{
@@ -427,7 +427,7 @@ trx_sys_read_wsrep_checkpoint(XID* xid)
xid->formatID = -1;
trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
mtr_commit(&mtr);
- return;
+ return false;
}
xid->formatID = (int)mach_read_from_4(
@@ -444,6 +444,7 @@ trx_sys_read_wsrep_checkpoint(XID* xid)
XIDDATASIZE);
mtr_commit(&mtr);
+ return true;
}
#endif /* WITH_WSREP */
@@ -1339,14 +1340,17 @@ trx_sys_close(void)
trx_purge_sys_close();
/* Free the double write data structures. */
- buf_dblwr_free();
+ if (buf_dblwr) {
+ buf_dblwr_free();
+ }
- ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
/* Only prepared transactions may be left in the system. Free them. */
ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx
|| srv_read_only_mode
- || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
+ || (IS_XTRABACKUP() && srv_apply_log_only));
+
while ((trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) != NULL) {
trx_free_prepared(trx);
@@ -1377,10 +1381,12 @@ trx_sys_close(void)
UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
}
- ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
- ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
- ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
- ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
+ if (!IS_XTRABACKUP() || !srv_apply_log_only) {
+ ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
+ ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
+ ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
+ ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
+ }
mutex_free(&trx_sys->mutex);
@@ -1427,6 +1433,9 @@ ulint
trx_sys_any_active_transactions(void)
/*=================================*/
{
+ if (IS_XTRABACKUP() && srv_apply_log_only) {
+ return(0);
+ }
mutex_enter(&trx_sys->mutex);
ulint total_trx = UT_LIST_GET_LEN(trx_sys->mysql_trx_list);
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 92d7525ea84..d0cb4a883cc 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -661,7 +661,7 @@ trx_resurrect_table_locks(
i != tables.end(); i++) {
if (dict_table_t* table = dict_table_open_on_id(
*i, FALSE, DICT_TABLE_OP_LOAD_TABLESPACE)) {
- if (table->ibd_file_missing
+ if (table->file_unreadable
|| dict_table_is_temporary(table)) {
mutex_enter(&dict_sys->mutex);
dict_table_close(table, TRUE, FALSE);
@@ -721,9 +721,16 @@ trx_resurrect_insert(
if (srv_force_recovery == 0) {
- trx->state = TRX_STATE_PREPARED;
- trx_sys->n_prepared_trx++;
- trx_sys->n_prepared_recovered_trx++;
+ /* XtraBackup should rollback prepared XA
+ transactions */
+ if (IS_XTRABACKUP()) {
+ trx->state = TRX_STATE_ACTIVE;
+ }
+ else {
+ trx->state = TRX_STATE_PREPARED;
+ trx_sys->n_prepared_trx++;
+ trx_sys->n_prepared_recovered_trx++;
+ }
} else {
fprintf(stderr,
"InnoDB: Since innodb_force_recovery"
@@ -790,13 +797,16 @@ trx_resurrect_update_in_prepared_state(
if (srv_force_recovery == 0) {
if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) {
- trx_sys->n_prepared_trx++;
- trx_sys->n_prepared_recovered_trx++;
+ if (!IS_XTRABACKUP()) {
+ trx_sys->n_prepared_trx++;
+ trx_sys->n_prepared_recovered_trx++;
+ }
} else {
ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED));
}
-
- trx->state = TRX_STATE_PREPARED;
+ /* XtraBackup should rollback prepared XA
+ transactions */
+ trx->state = IS_XTRABACKUP()?TRX_STATE_ACTIVE: TRX_STATE_PREPARED;
} else {
fprintf(stderr,
"InnoDB: Since innodb_force_recovery"
diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc
index acedb56879a..fd52537ae11 100644
--- a/storage/xtradb/ut/ut0ut.cc
+++ b/storage/xtradb/ut/ut0ut.cc
@@ -852,6 +852,8 @@ ut_strerr(
return("BLOB record length is greater than 10%% of redo log");
case DB_DECRYPTION_FAILED:
return("Table is encrypted but decrypt failed.");
+ case DB_PAGE_CORRUPTED:
+ return("Page read from tablespace is corrupted.");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */