diff options
Diffstat (limited to 'storage/innobase/row/row0import.cc')
-rw-r--r-- | storage/innobase/row/row0import.cc | 616 |
1 files changed, 241 insertions, 375 deletions
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 3c29461c19d..4afe9e874bb 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2022, MariaDB Corporation. +Copyright (c) 2015, 2023, 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 @@ -32,15 +32,15 @@ Created 2012-02-08 by Sunny Bains. #include "que0que.h" #include "dict0boot.h" #include "dict0load.h" -#include "ibuf0ibuf.h" #include "pars0pars.h" +#include "row0row.h" #include "row0sel.h" #include "row0mysql.h" #include "srv0start.h" #include "row0quiesce.h" #include "fil0pagecompress.h" #include "trx0undo.h" -#include "row0row.h" +#include "lock0lock.h" #ifdef HAVE_LZO #include "lzo/lzo1x.h" #endif @@ -258,19 +258,18 @@ public: } /** Position the cursor on the first user record. */ - void open(buf_block_t* block) UNIV_NOTHROW + rec_t* open(buf_block_t* block, const dict_index_t* index) noexcept + MY_ATTRIBUTE((warn_unused_result)) { + m_cur.index = const_cast<dict_index_t*>(index); page_cur_set_before_first(block, &m_cur); - - if (!end()) { - next(); - } + return next(); } /** Move to the next record. */ - void next() UNIV_NOTHROW + rec_t* next() noexcept MY_ATTRIBUTE((warn_unused_result)) { - page_cur_move_to_next(&m_cur); + return page_cur_move_to_next(&m_cur); } /** @@ -292,37 +291,36 @@ public: /** Remove the current record @return true on success */ - bool remove( - const dict_index_t* index, - rec_offs* offsets) UNIV_NOTHROW + bool remove(rec_offs* offsets) UNIV_NOTHROW { - ut_ad(page_is_leaf(m_cur.block->frame)); + const dict_index_t* const index = m_cur.index; + ut_ad(page_is_leaf(m_cur.block->page.frame)); /* We can't end up with an empty page unless it is root. */ - if (page_get_n_recs(m_cur.block->frame) <= 1) { + if (page_get_n_recs(m_cur.block->page.frame) <= 1) { return(false); } if (!rec_offs_any_extern(offsets) && m_cur.block->page.id().page_no() != index->page - && ((page_get_data_size(m_cur.block->frame) + && ((page_get_data_size(m_cur.block->page.frame) - rec_offs_size(offsets) < BTR_CUR_PAGE_COMPRESS_LIMIT(index)) - || !page_has_siblings(m_cur.block->frame) - || (page_get_n_recs(m_cur.block->frame) < 2))) { + || !page_has_siblings(m_cur.block->page.frame) + || (page_get_n_recs(m_cur.block->page.frame) < 2))) { return false; } #ifdef UNIV_ZIP_DEBUG page_zip_des_t* page_zip = buf_block_get_page_zip(m_cur.block); ut_a(!page_zip || page_zip_validate( - page_zip, m_cur.block->frame, index)); + page_zip, m_cur.block->page.frame, index)); #endif /* UNIV_ZIP_DEBUG */ - page_cur_delete_rec(&m_cur, index, offsets, &m_mtr); + page_cur_delete_rec(&m_cur, offsets, &m_mtr); #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate( - page_zip, m_cur.block->frame, index)); + page_zip, m_cur.block->page.frame, index)); #endif /* UNIV_ZIP_DEBUG */ return true; @@ -370,24 +368,23 @@ public: } private: - /** Begin import, position the cursor on the first record. */ - void open() UNIV_NOTHROW; + /** Begin import, position the cursor on the first record. */ + inline bool open() noexcept; - /** Close the persistent curosr and commit the mini-transaction. */ - void close() UNIV_NOTHROW; + /** Close the persistent cursor and commit the mini-transaction. */ + void close() noexcept { m_mtr.commit(); btr_pcur_close(&m_pcur); } - /** Position the cursor on the next record. - @return DB_SUCCESS or error code */ - dberr_t next() UNIV_NOTHROW; + /** Position the cursor on the next record. + @return DB_SUCCESS or error code */ + dberr_t next() noexcept; - /** Store the persistent cursor position and reopen the - B-tree cursor in BTR_MODIFY_TREE mode, because the - tree structure may be changed during a pessimistic delete. */ - void purge_pessimistic_delete() UNIV_NOTHROW; + /** Store the persistent cursor position and reopen the + B-tree cursor in BTR_MODIFY_TREE mode, because the + tree structure may be changed during a pessimistic delete. */ + inline dberr_t purge_pessimistic_delete() noexcept; - /** Purge delete-marked records. - @param offsets current row offsets. */ - void purge() UNIV_NOTHROW; + /** Purge a delete-marked record. */ + dberr_t purge() noexcept; protected: // Disable copying @@ -468,7 +465,7 @@ public: Called for every page in the tablespace. If the page was not updated then its state must be set to BUF_PAGE_NOT_USED. For compressed tables the page descriptor memory will be at offset: - block->frame + srv_page_size; + block->page.frame + srv_page_size; @param block block read from file, note it is not from the buffer pool @retval DB_SUCCESS or error code. */ virtual dberr_t operator()(buf_block_t* block) UNIV_NOTHROW = 0; @@ -485,7 +482,7 @@ public: static byte* get_frame(const buf_block_t* block) { return block->page.zip.data - ? block->page.zip.data : block->frame; + ? block->page.zip.data : block->page.frame; } /** Invoke the functionality for the callback */ @@ -618,7 +615,7 @@ AbstractCallback::init( os_offset_t file_size, const buf_block_t* block) UNIV_NOTHROW { - const page_t* page = block->frame; + const page_t* page = block->page.frame; m_space_flags = fsp_header_get_flags(page); if (!fil_space_t::is_valid_flags(m_space_flags, true)) { @@ -757,7 +754,7 @@ dberr_t FetchIndexRootPages::operator()(buf_block_t* block) UNIV_NOTHROW return(DB_CORRUPTION); } - if (!page_is_comp(block->frame) != + if (!page_is_comp(block->page.frame) != !dict_table_is_comp(m_table)) { ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, @@ -1458,8 +1455,6 @@ row_import::set_root_by_heuristic() UNIV_NOTHROW " the tablespace has " << m_n_indexes << " indexes"; } - dict_mutex_enter_for_mysql(); - ulint i = 0; dberr_t err = DB_SUCCESS; @@ -1499,8 +1494,6 @@ row_import::set_root_by_heuristic() UNIV_NOTHROW } } - dict_mutex_exit_for_mysql(); - return(err); } @@ -1510,14 +1503,13 @@ Purge delete marked records. dberr_t IndexPurge::garbage_collect() UNIV_NOTHROW { - dberr_t err; ibool comp = dict_table_is_comp(m_index->table); /* Open the persistent cursor and start the mini-transaction. */ - open(); + dberr_t err = open() ? next() : DB_CORRUPTION; - while ((err = next()) == DB_SUCCESS) { + for (; err == DB_SUCCESS; err = next()) { rec_t* rec = btr_pcur_get_rec(&m_pcur); ibool deleted = rec_get_deleted_flag(rec, comp); @@ -1525,7 +1517,10 @@ IndexPurge::garbage_collect() UNIV_NOTHROW if (!deleted) { ++m_n_rows; } else { - purge(); + err = purge(); + if (err != DB_SUCCESS) { + break; + } } } @@ -1538,40 +1533,33 @@ IndexPurge::garbage_collect() UNIV_NOTHROW /** Begin import, position the cursor on the first record. */ -void -IndexPurge::open() UNIV_NOTHROW +inline bool IndexPurge::open() noexcept { - mtr_start(&m_mtr); + m_mtr.start(); + m_mtr.set_log_mode(MTR_LOG_NO_REDO); - mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO); + btr_pcur_init(&m_pcur); - btr_pcur_open_at_index_side( - true, m_index, BTR_MODIFY_LEAF, &m_pcur, true, 0, &m_mtr); - btr_pcur_move_to_next_user_rec(&m_pcur, &m_mtr); - if (rec_is_metadata(btr_pcur_get_rec(&m_pcur), *m_index)) { - ut_ad(btr_pcur_is_on_user_rec(&m_pcur)); - /* Skip the metadata pseudo-record. */ - } else { - btr_pcur_move_to_prev_on_page(&m_pcur); - } -} + if (m_pcur.open_leaf(true, m_index, BTR_MODIFY_LEAF, &m_mtr) != DB_SUCCESS) + return false; -/** -Close the persistent curosr and commit the mini-transaction. */ -void -IndexPurge::close() UNIV_NOTHROW -{ - btr_pcur_close(&m_pcur); - mtr_commit(&m_mtr); + rec_t *rec= page_rec_get_next(btr_pcur_get_rec(&m_pcur)); + if (!rec) + return false; + if (rec_is_metadata(rec, *m_index)) + /* Skip the metadata pseudo-record. */ + btr_pcur_get_page_cur(&m_pcur)->rec= rec; + return true; } /** Position the cursor on the next record. @return DB_SUCCESS or error code */ -dberr_t -IndexPurge::next() UNIV_NOTHROW +dberr_t IndexPurge::next() noexcept { - btr_pcur_move_to_next_on_page(&m_pcur); + if (UNIV_UNLIKELY(!btr_pcur_move_to_next_on_page(&m_pcur))) { + return DB_CORRUPTION; + } /* When switching pages, commit the mini-transaction in order to release the latch on the old page. */ @@ -1592,9 +1580,12 @@ IndexPurge::next() UNIV_NOTHROW mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO); - btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr); + if (m_pcur.restore_position(BTR_MODIFY_LEAF, &m_mtr) + == btr_pcur_t::CORRUPTED) { + return DB_CORRUPTION; + } /* The following is based on btr_pcur_move_to_next_user_rec(). */ - m_pcur.old_stored = false; + m_pcur.old_rec = nullptr; ut_ad(m_pcur.latch_mode == BTR_MODIFY_LEAF); do { if (btr_pcur_is_after_last_on_page(&m_pcur)) { @@ -1602,56 +1593,12 @@ IndexPurge::next() UNIV_NOTHROW return DB_END_OF_INDEX; } - buf_block_t* block = btr_pcur_get_block(&m_pcur); - uint32_t next_page = btr_page_get_next(block->frame); - - /* MDEV-13542 FIXME: Make these checks part of - btr_pcur_move_to_next_page(), and introduce a - return status that will be checked in all callers! */ - switch (next_page) { - default: - if (next_page != block->page.id().page_no()) { - break; - } - /* MDEV-20931 FIXME: Check that - next_page is within the tablespace - bounds! Also check that it is not a - change buffer bitmap page. */ - /* fall through */ - case 0: - case 1: - case FIL_NULL: - return DB_CORRUPTION; + if (dberr_t err = btr_pcur_move_to_next_page(&m_pcur, + &m_mtr)) { + return err; } - - dict_index_t* index = m_pcur.btr_cur.index; - buf_block_t* next_block = btr_block_get( - *index, next_page, BTR_MODIFY_LEAF, false, - &m_mtr); - - if (UNIV_UNLIKELY(!next_block - || !fil_page_index_page_check( - next_block->frame) - || !!dict_index_is_spatial(index) - != (fil_page_get_type( - next_block->frame) - == FIL_PAGE_RTREE) - || page_is_comp(next_block->frame) - != page_is_comp(block->frame) - || btr_page_get_prev( - next_block->frame) - != block->page.id().page_no())) { - return DB_CORRUPTION; - } - - btr_leaf_page_release(block, BTR_MODIFY_LEAF, &m_mtr); - - page_cur_set_before_first(next_block, - &m_pcur.btr_cur.page_cur); - - ut_d(page_check_dir(next_block->frame)); - } else { - btr_pcur_move_to_next_on_page(&m_pcur); + } else if (!btr_pcur_move_to_next_on_page(&m_pcur)) { + return DB_CORRUPTION; } } while (!btr_pcur_is_on_user_rec(&m_pcur)); @@ -1662,41 +1609,38 @@ IndexPurge::next() UNIV_NOTHROW Store the persistent cursor position and reopen the B-tree cursor in BTR_MODIFY_TREE mode, because the tree structure may be changed during a pessimistic delete. */ -void -IndexPurge::purge_pessimistic_delete() UNIV_NOTHROW +inline dberr_t IndexPurge::purge_pessimistic_delete() noexcept { - dberr_t err; - - btr_pcur_restore_position(BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE, - &m_pcur, &m_mtr); - - ut_ad(rec_get_deleted_flag( - btr_pcur_get_rec(&m_pcur), - dict_table_is_comp(m_index->table))); - - btr_cur_pessimistic_delete( - &err, FALSE, btr_pcur_get_btr_cur(&m_pcur), 0, false, &m_mtr); - - ut_a(err == DB_SUCCESS); + dberr_t err; + if (m_pcur.restore_position(BTR_PURGE_TREE, &m_mtr) != btr_pcur_t::CORRUPTED) + { + ut_ad(rec_get_deleted_flag(btr_pcur_get_rec(&m_pcur), + m_index->table->not_redundant())); + btr_cur_pessimistic_delete(&err, FALSE, btr_pcur_get_btr_cur(&m_pcur), 0, + false, &m_mtr); + } + else + err= DB_CORRUPTION; - /* Reopen the B-tree cursor in BTR_MODIFY_LEAF mode */ - mtr_commit(&m_mtr); + m_mtr.commit(); + return err; } -/** -Purge delete-marked records. */ -void -IndexPurge::purge() UNIV_NOTHROW +dberr_t IndexPurge::purge() noexcept { - btr_pcur_store_position(&m_pcur, &m_mtr); - - purge_pessimistic_delete(); - - mtr_start(&m_mtr); - - mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO); - - btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr); + btr_pcur_store_position(&m_pcur, &m_mtr); + m_mtr.commit(); + m_mtr.start(); + m_mtr.set_log_mode(MTR_LOG_NO_REDO); + dberr_t err= purge_pessimistic_delete(); + + m_mtr.start(); + m_mtr.set_log_mode(MTR_LOG_NO_REDO); + if (err == DB_SUCCESS) + err= (m_pcur.restore_position(BTR_MODIFY_LEAF, &m_mtr) == + btr_pcur_t::CORRUPTED) + ? DB_CORRUPTION : DB_SUCCESS; + return err; } /** Adjust the BLOB reference for a single column that is externally stored @@ -1806,10 +1750,8 @@ re-organising the B+tree. @return true if purge succeeded */ inline bool PageConverter::purge() UNIV_NOTHROW { - const dict_index_t* index = m_index->m_srv_index; - /* We can't have a page that is empty and not root. */ - if (m_rec_iter.remove(index, m_offsets)) { + if (m_rec_iter.remove(m_offsets)) { ++m_index->m_stats.m_n_purged; @@ -1873,7 +1815,9 @@ PageConverter::update_records( /* This will also position the cursor on the first user record. */ - m_rec_iter.open(block); + if (!m_rec_iter.open(block, m_index->m_srv_index)) { + return DB_CORRUPTION; + } while (!m_rec_iter.end()) { rec_t* rec = m_rec_iter.current(); @@ -1904,17 +1848,19 @@ PageConverter::update_records( optimistic delete. */ if (deleted) { + ++m_index->m_stats.m_n_deleted; /* A successful purge will move the cursor to the next record. */ - if (!purge()) { - m_rec_iter.next(); + if (purge()) { + continue; } - - ++m_index->m_stats.m_n_deleted; } else { ++m_index->m_stats.m_n_rows; - m_rec_iter.next(); + } + + if (!m_rec_iter.next()) { + return DB_CORRUPTION; } } @@ -1934,7 +1880,7 @@ PageConverter::update_index_page( return(DB_SUCCESS); } - buf_frame_t* page = block->frame; + buf_frame_t* page = block->page.frame; const index_id_t id = btr_page_get_index_id(page); if (id != m_index->m_id) { @@ -1985,7 +1931,7 @@ PageConverter::update_index_page( m_index->m_srv_index->id); if (UNIV_LIKELY_NULL(block->page.zip.data)) { memcpy(&block->page.zip.data[PAGE_HEADER + PAGE_INDEX_ID], - &block->frame[PAGE_HEADER + PAGE_INDEX_ID], 8); + &block->page.frame[PAGE_HEADER + PAGE_INDEX_ID], 8); } if (m_index->m_srv_index->is_clust()) { @@ -1994,12 +1940,12 @@ PageConverter::update_index_page( } } else if (page_is_leaf(page)) { /* Set PAGE_MAX_TRX_ID on secondary index leaf pages. */ - mach_write_to_8(&block->frame[PAGE_HEADER + PAGE_MAX_TRX_ID], - m_trx->id); + mach_write_to_8(&block->page.frame + [PAGE_HEADER + PAGE_MAX_TRX_ID], m_trx->id); if (UNIV_LIKELY_NULL(block->page.zip.data)) { memcpy_aligned<8>(&block->page.zip.data [PAGE_HEADER + PAGE_MAX_TRX_ID], - &block->frame + &block->page.frame [PAGE_HEADER + PAGE_MAX_TRX_ID], 8); } } else { @@ -2009,7 +1955,8 @@ clear_page_max_trx_id: in MySQL 5.6, 5.7 and MariaDB 10.0 and 10.1 would set the field to the transaction ID even on clustered index pages. */ - memset_aligned<8>(&block->frame[PAGE_HEADER + PAGE_MAX_TRX_ID], + memset_aligned<8>(&block->page.frame + [PAGE_HEADER + PAGE_MAX_TRX_ID], 0, 8); if (UNIV_LIKELY_NULL(block->page.zip.data)) { memset_aligned<8>(&block->page.zip.data @@ -2031,7 +1978,9 @@ clear_page_max_trx_id: return(DB_SUCCESS); } - return page_is_leaf(block->frame) ? update_records(block) : DB_SUCCESS; + return page_is_leaf(block->page.frame) + ? update_records(block) + : DB_SUCCESS; } /** Validate the space flags and update tablespace header page. @@ -2078,8 +2027,8 @@ PageConverter::update_page(buf_block_t* block, uint16_t& page_type) case FIL_PAGE_INDEX: case FIL_PAGE_RTREE: - /* We need to decompress the contents into block->frame - before we can do any thing with Btree pages. */ + /* We need to decompress the contents + before we can do anything. */ if (is_compressed_table() && !buf_zip_decompress(block, TRUE)) { return(DB_CORRUPTION); @@ -2135,9 +2084,9 @@ dberr_t PageConverter::operator()(buf_block_t* block) UNIV_NOTHROW /* If we already had an old page with matching number in the buffer pool, evict it now, because we no longer evict the pages on DISCARD TABLESPACE. */ - buf_page_get_gen(block->page.id(), get_zip_size(), - RW_NO_LATCH, NULL, BUF_EVICT_IF_IN_POOL, - __FILE__, __LINE__, NULL, NULL); + buf_page_get_low(block->page.id(), get_zip_size(), RW_NO_LATCH, + nullptr, BUF_PEEK_IF_IN_POOL, + nullptr, nullptr, false); uint16_t page_type; @@ -2151,7 +2100,7 @@ dberr_t PageConverter::operator()(buf_block_t* block) UNIV_NOTHROW if (!block->page.zip.data) { buf_flush_init_for_writing( - NULL, block->frame, NULL, full_crc32); + NULL, block->page.frame, NULL, full_crc32); } else if (fil_page_type_is_index(page_type)) { buf_flush_init_for_writing( NULL, block->page.zip.data, &block->page.zip, @@ -2173,11 +2122,8 @@ dberr_t row_import_cleanup( /*===============*/ row_prebuilt_t* prebuilt, /*!< in/out: prebuilt from handler */ - trx_t* trx, /*!< in/out: transaction for import */ dberr_t err) /*!< in: error code */ { - ut_a(prebuilt->trx != trx); - if (err != DB_SUCCESS) { dict_table_t* table = prebuilt->table; table->file_unreadable = true; @@ -2191,10 +2137,6 @@ row_import_cleanup( ib::info() << "Discarding tablespace of table " << table->name << ": " << err; - if (!trx->dict_operation_lock_mode) { - row_mysql_lock_data_dictionary(trx); - } - for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); index; index = UT_LIST_GET_NEXT(indexes, index)) { @@ -2202,15 +2144,13 @@ row_import_cleanup( } } - ut_a(trx->dict_operation_lock_mode == RW_X_LATCH); - DBUG_EXECUTE_IF("ib_import_before_commit_crash", DBUG_SUICIDE();); - trx_commit_for_mysql(trx); - - row_mysql_unlock_data_dictionary(trx); + prebuilt->trx->commit(); - trx->free(); + if (prebuilt->trx->dict_operation_lock_mode) { + row_mysql_unlock_data_dictionary(prebuilt->trx); + } prebuilt->trx->op_info = ""; @@ -2226,10 +2166,9 @@ dberr_t row_import_error( /*=============*/ row_prebuilt_t* prebuilt, /*!< in/out: prebuilt from handler */ - trx_t* trx, /*!< in/out: transaction for import */ dberr_t err) /*!< in: error code */ { - if (!trx_is_interrupted(trx)) { + if (!trx_is_interrupted(prebuilt->trx)) { char table_name[MAX_FULL_NAME_LEN + 1]; innobase_format_name( @@ -2237,12 +2176,12 @@ row_import_error( prebuilt->table->name.m_name); ib_senderrf( - trx->mysql_thd, IB_LOG_LEVEL_WARN, + prebuilt->trx->mysql_thd, IB_LOG_LEVEL_WARN, ER_INNODB_IMPORT_ERROR, table_name, (ulong) err, ut_strerr(err)); } - return(row_import_cleanup(prebuilt, trx, err)); + return row_import_cleanup(prebuilt, err); } /*****************************************************************//** @@ -2376,43 +2315,28 @@ row_import_set_sys_max_row_id( mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); - btr_pcur_open_at_index_side( - false, // High end - index, - BTR_SEARCH_LEAF, - &pcur, - true, // Init cursor - 0, // Leaf level - &mtr); - - btr_pcur_move_to_prev_on_page(&pcur); - rec = btr_pcur_get_rec(&pcur); - - /* Check for empty table. */ - if (page_rec_is_infimum(rec)) { - /* The table is empty. */ - } else if (rec_is_metadata(rec, *index)) { - /* The clustered index contains the metadata record only, - that is, the table is empty. */ - } else { - row_id = mach_read_from_6(rec); + if (pcur.open_leaf(false, index, BTR_SEARCH_LEAF, &mtr) + == DB_SUCCESS) { + rec = btr_pcur_move_to_prev_on_page(&pcur); + + if (!rec) { + /* The table is corrupted. */ + } else if (page_rec_is_infimum(rec)) { + /* The table is empty. */ + } else if (rec_is_metadata(rec, *index)) { + /* The clustered index contains the metadata + record only, that is, the table is empty. */ + } else { + row_id = mach_read_from_6(rec); + } } - btr_pcur_close(&pcur); mtr_commit(&mtr); if (row_id) { /* Update the system row id if the imported index row id is greater than the max system row id. */ - - mutex_enter(&dict_sys.mutex); - - if (row_id >= dict_sys.row_id) { - dict_sys.row_id = row_id + 1; - dict_hdr_flush_row_id(); - } - - mutex_exit(&dict_sys.mutex); + dict_sys.update_row_id(row_id); } } @@ -3161,18 +3085,16 @@ and apply it to dict_table_t static dberr_t handle_instant_metadata(dict_table_t *table, const row_import &cfg) { - dict_get_and_save_data_dir_path(table, false); + dict_get_and_save_data_dir_path(table); char *filepath; if (DICT_TF_HAS_DATA_DIR(table->flags)) { ut_a(table->data_dir_path); - - filepath= - fil_make_filepath(table->data_dir_path, table->name.m_name, IBD, true); + filepath= fil_make_filepath(table->data_dir_path, table->name, IBD, true); } else - filepath= fil_make_filepath(nullptr, table->name.m_name, IBD, false); + filepath= fil_make_filepath(nullptr, table->name, IBD, false); if (!filepath) return DB_OUT_OF_MEMORY; @@ -3195,9 +3117,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table, static_cast<byte *>(aligned_malloc(srv_page_size, srv_page_size)), &aligned_free); - if (dberr_t err= os_file_read_no_error_handling(IORequestReadPartial, - file, first_page.get(), 0, - srv_page_size, nullptr)) + if (dberr_t err= os_file_read(IORequestReadPartial, file, first_page.get(), + 0, srv_page_size, nullptr)) return err; auto space_flags= fsp_header_get_flags(first_page.get()); @@ -3232,7 +3153,7 @@ static dberr_t handle_instant_metadata(dict_table_t *table, aligned_malloc(UNIV_PAGE_SIZE_MAX, UNIV_PAGE_SIZE_MAX)), &aligned_free); - if (dberr_t err= os_file_read_no_error_handling( + if (dberr_t err= os_file_read( IORequestReadPartial, file, page.get(), 3 * physical_size, physical_size, nullptr)) return err; @@ -3249,14 +3170,6 @@ static dberr_t handle_instant_metadata(dict_table_t *table, { dict_index_t *index= dict_table_get_first_index(table); - auto tmp1= table->space_id; - table->space_id= page_get_space_id(page.get()); - SCOPE_EXIT([tmp1, table]() { table->space_id= tmp1; }); - - auto tmp2= index->page; - index->page= page_get_page_no(page.get()); - SCOPE_EXIT([tmp2, index]() { index->page= tmp2; }); - if (!page_is_comp(page.get()) != !dict_table_is_comp(table)) { ib_errf(current_thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, @@ -3265,7 +3178,7 @@ static dberr_t handle_instant_metadata(dict_table_t *table, } if (btr_cur_instant_root_init(index, page.get())) - return DB_ERROR; + return DB_CORRUPTION; ut_ad(index->n_core_null_bytes != dict_index_t::NO_CORE_NULL_BYTES); @@ -3284,6 +3197,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table, while (btr_page_get_level(page.get()) != 0) { const rec_t *rec= page_rec_get_next(page_get_infimum_rec(page.get())); + if (!rec) + return DB_CORRUPTION; /* Relax the assertion in rec_init_offsets(). */ ut_ad(!index->in_instant_init); @@ -3295,10 +3210,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table, uint64_t child_page_no= btr_node_ptr_get_child_page_no(rec, offsets); if (dberr_t err= - os_file_read_no_error_handling(IORequestReadPartial, file, - page.get(), - child_page_no * physical_size, - physical_size, nullptr)) + os_file_read(IORequestReadPartial, file, page.get(), + child_page_no * physical_size, physical_size, nullptr)) return err; if (dberr_t err= decrypt_decompress(space_crypt, space_flags, @@ -3308,18 +3221,22 @@ static dberr_t handle_instant_metadata(dict_table_t *table, return err; } - const auto *rec= page_rec_get_next(page_get_infimum_rec(page.get())); + const auto *rec= page_rec_get_next_const(page_get_infimum_rec(page.get())); const auto comp= dict_table_is_comp(index->table); - const auto info_bits= rec_get_info_bits(rec, comp); - if (page_rec_is_supremum(rec) || !(info_bits & REC_INFO_MIN_REC_FLAG)) + if (!rec || page_rec_is_supremum(rec)) { + corrupted_metadata: ib::error() << "Table " << index->table->name << " is missing instant ALTER metadata"; index->table->corrupted= true; return DB_CORRUPTION; } + const auto info_bits= rec_get_info_bits(rec, comp); + if (!(info_bits & REC_INFO_MIN_REC_FLAG)) + goto corrupted_metadata; + if ((info_bits & ~REC_INFO_DELETED_FLAG) != REC_INFO_MIN_REC_FLAG || (comp && rec_get_status(rec) != REC_STATUS_INSTANT)) { @@ -3373,11 +3290,10 @@ static dberr_t handle_instant_metadata(dict_table_t *table, &aligned_free); if (dberr_t err= - os_file_read_no_error_handling(IORequestReadPartial, file, - second_page.get(), physical_size * - mach_read_from_4(ptr + - BTR_EXTERN_PAGE_NO), - srv_page_size, nullptr)) + os_file_read(IORequestReadPartial, file, second_page.get(), + physical_size * + mach_read_from_4(ptr + BTR_EXTERN_PAGE_NO), + physical_size, nullptr)) return err; if (dberr_t err= decrypt_decompress(space_crypt, space_flags, @@ -3585,8 +3501,6 @@ row_import_update_index_root(trx_t* trx, dict_table_t* table, bool reset) que_thr_t* thr; - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - ut_a(thr = que_fork_start_command(graph)); que_run_threads(thr); @@ -3703,7 +3617,7 @@ dberr_t row_import_update_discarded_flag(trx_t* trx, table_id_t table_id, pars_info_bind_function( info, "my_func", row_import_set_discarded, &discard); - dberr_t err = que_eval_sql(info, sql, false, trx); + dberr_t err = que_eval_sql(info, sql, trx); ut_a(discard.n_recs == 1); ut_a(discard.flags2 != ULINT32_UNDEFINED); @@ -3784,15 +3698,15 @@ dberr_t FetchIndexRootPages::run(const fil_iterator_t& iter, const bool encrypted= iter.crypt_data != NULL && iter.crypt_data->should_encrypt(); byte* const readptr= iter.io_buffer; - block->frame= readptr; + block->page.frame= readptr; if (block->page.zip.data) block->page.zip.data= readptr; bool page_compressed= false; - dberr_t err= os_file_read_no_error_handling( - IORequestReadPartial, iter.file, readptr, 3 * size, size, 0); + dberr_t err= os_file_read(IORequestReadPartial, iter.file, readptr, + 3 * size, size, nullptr); if (err != DB_SUCCESS) { ib::error() << iter.filepath << ": os_file_read() failed"; @@ -3884,7 +3798,7 @@ static dberr_t fil_iterate( required by buf_zip_decompress() */ dberr_t err = DB_SUCCESS; bool page_compressed = false; - bool punch_hole = true; + bool punch_hole = !my_test_if_thinly_provisioned(iter.file); for (offset = iter.start; offset < iter.end; offset += n_bytes) { if (callback.is_interrupted()) { @@ -3893,7 +3807,7 @@ static dberr_t fil_iterate( } byte* io_buffer = iter.io_buffer; - block->frame = io_buffer; + block->page.frame = io_buffer; if (block->page.zip.data) { /* Zip IO is done in the compressed page buffer. */ @@ -3916,9 +3830,8 @@ static dberr_t fil_iterate( ? iter.crypt_io_buffer : io_buffer; byte* const writeptr = readptr; - err = os_file_read_no_error_handling( - IORequestReadPartial, - iter.file, readptr, offset, n_bytes, 0); + err = os_file_read(IORequestReadPartial, iter.file, readptr, + offset, n_bytes, nullptr); if (err != DB_SUCCESS) { ib::error() << iter.filepath << ": os_file_read() failed"; @@ -3933,7 +3846,7 @@ static dberr_t fil_iterate( for (ulint i = 0; i < n_pages_read; ++block->page.id_, - ++i, page_off += size, block->frame += size) { + ++i, page_off += size, block->page.frame += size) { byte* src = readptr + i * size; const ulint page_no = page_get_page_no(src); if (!page_no && block->page.id().page_no()) { @@ -3990,7 +3903,7 @@ page_corrupted: } else if (!page_compressed && type != FIL_PAGE_TYPE_XDES && !block->page.zip.data) { - block->frame = src; + block->page.frame = src; frame_changed = true; } else { ut_ad(dst != src); @@ -4042,8 +3955,7 @@ page_corrupted: if ((err = callback(block)) != DB_SUCCESS) { goto func_exit; } else if (!updated) { - updated = block->page.state() - == BUF_BLOCK_FILE_PAGE; + updated = !!block->page.frame; } /* If tablespace is encrypted we use additional @@ -4051,10 +3963,10 @@ page_corrupted: for decrypting readptr == crypt_io_buffer != io_buffer. Destination for decryption is a buffer pool block - block->frame == dst == io_buffer that is updated. + block->page.frame == dst == io_buffer that is updated. Pages that did not require decryption even when tablespace is marked as encrypted are not copied - instead block->frame is set to src == readptr. + instead block->page.frame is set to src == readptr. For encryption we again use temporary scratch area writeptr != io_buffer == dst @@ -4087,7 +3999,7 @@ page_corrupted: if (block->page.zip.data) { block->page.zip.data = dst; } else { - block->frame = dst; + block->page.frame = dst; } } @@ -4203,18 +4115,17 @@ fil_tablespace_iterate( return(DB_CORRUPTION);); /* Make sure the data_dir_path is set. */ - dict_get_and_save_data_dir_path(table, false); + dict_get_and_save_data_dir_path(table); - if (DICT_TF_HAS_DATA_DIR(table->flags)) { - ut_a(table->data_dir_path); + ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path); - filepath = fil_make_filepath( - table->data_dir_path, table->name.m_name, IBD, true); - } else { - filepath = fil_make_filepath( - NULL, table->name.m_name, IBD, false); - } + const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags) + ? table->data_dir_path : nullptr; + filepath = fil_make_filepath(data_dir_path, + {table->name.m_name, + strlen(table->name.m_name)}, + IBD, data_dir_path != nullptr); if (!filepath) { return(DB_OUT_OF_MEMORY); } else { @@ -4251,13 +4162,13 @@ fil_tablespace_iterate( buf_block_t* block = reinterpret_cast<buf_block_t*> (ut_zalloc_nokey(sizeof *block)); - block->frame = page; - block->page.init(BUF_BLOCK_FILE_PAGE, page_id_t(~0ULL), 1); + block->page.frame = page; + block->page.init(buf_page_t::UNFIXED + 1, page_id_t{~0ULL}); - /* Read the first page and determine the page and zip size. */ + /* Read the first page and determine the page size. */ - err = os_file_read_no_error_handling(IORequestReadPartial, - file, page, 0, srv_page_size, 0); + err = os_file_read(IORequestReadPartial, file, page, 0, srv_page_size, + nullptr); if (err == DB_SUCCESS) { err = callback.init(file_size, block); @@ -4306,8 +4217,9 @@ fil_tablespace_iterate( if (block->page.zip.ssize) { ut_ad(iter.n_io_buffers == 1); - block->frame = iter.io_buffer; - block->page.zip.data = block->frame + srv_page_size; + block->page.frame = iter.io_buffer; + block->page.zip.data = block->page.frame + + srv_page_size; } err = callback.run(iter, block); @@ -4351,9 +4263,9 @@ row_import_for_mysql( row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL */ { dberr_t err; - trx_t* trx; ib_uint64_t autoinc = 0; char* filepath = NULL; + trx_t* trx = prebuilt->trx; /* The caller assured that this is not read_only_mode and that no temorary tablespace is being imported. */ @@ -4362,28 +4274,12 @@ row_import_for_mysql( ut_ad(table->space_id); ut_ad(table->space_id < SRV_SPACE_ID_UPPER_BOUND); - ut_ad(prebuilt->trx); + ut_ad(trx); + ut_ad(trx->state == TRX_STATE_ACTIVE); ut_ad(!table->is_readable()); ibuf_delete_for_discarded_space(table->space_id); - trx_start_if_not_started(prebuilt->trx, true); - - trx = trx_create(); - - /* So that the table is not DROPped during recovery. */ - trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - - trx_start_if_not_started(trx, true); - - /* So that we can send error messages to the user. */ - trx->mysql_thd = prebuilt->trx->mysql_thd; - - /* Ensure that the table will be dropped by trx_rollback_active() - in case of a crash. */ - - trx->table_id = table->id; - /* Assign an undo segment for the transaction, so that the transaction will be recovered after a crash. */ @@ -4398,25 +4294,19 @@ row_import_for_mysql( DBUG_EXECUTE_IF("ib_import_undo_assign_failure", err = DB_TOO_MANY_CONCURRENT_TRXS;); - if (err != DB_SUCCESS) { - - return(row_import_cleanup(prebuilt, trx, err)); - - } else if (trx->rsegs.m_redo.undo == 0) { - + if (err == DB_SUCCESS && !trx->has_logged_persistent()) { err = DB_TOO_MANY_CONCURRENT_TRXS; - return(row_import_cleanup(prebuilt, trx, err)); + } + if (err != DB_SUCCESS) { + return row_import_cleanup(prebuilt, err); } - prebuilt->trx->op_info = "read meta-data file"; - - /* Prevent DDL operations while we are checking. */ - - rw_lock_s_lock(&dict_sys.latch); + trx->op_info = "read meta-data file"; row_import cfg; + THD* thd = trx->mysql_thd; - err = row_import_read_cfg(table, trx->mysql_thd, cfg); + err = row_import_read_cfg(table, thd, cfg); /* Check if the table column definitions match the contents of the config file. */ @@ -4424,14 +4314,13 @@ row_import_for_mysql( if (err == DB_SUCCESS) { if (dberr_t err = handle_instant_metadata(table, cfg)) { - rw_lock_s_unlock(&dict_sys.latch); - return row_import_error(prebuilt, trx, err); + return row_import_error(prebuilt, err); } /* We have a schema file, try and match it with our data dictionary. */ - err = cfg.match_schema(trx->mysql_thd); + err = cfg.match_schema(thd); /* Update index->page and SYS_INDEXES.PAGE_NO to match the B-tree root page numbers in the tablespace. Use the index @@ -4442,15 +4331,10 @@ row_import_for_mysql( autoinc = cfg.m_autoinc; } - rw_lock_s_unlock(&dict_sys.latch); - DBUG_EXECUTE_IF("ib_import_set_index_root_failure", err = DB_TOO_MANY_CONCURRENT_TRXS;); } else if (cfg.m_missing) { - - rw_lock_s_unlock(&dict_sys.latch); - /* We don't have a schema file, we will have to discover the index root pages from the .ibd file and skip the schema matching step. */ @@ -4460,13 +4344,13 @@ row_import_for_mysql( cfg.m_zip_size = 0; if (UT_LIST_GET_LEN(table->indexes) > 1) { - ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR, + ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_INTERNAL_ERROR, "Drop all secondary indexes before importing " "table %s when .cfg file is missing.", table->name.m_name); err = DB_ERROR; - return row_import_error(prebuilt, trx, err); + return row_import_error(prebuilt, err); } FetchIndexRootPages fetchIndexRootPages(table, trx); @@ -4487,24 +4371,18 @@ row_import_for_mysql( err = cfg.set_root_by_heuristic(); if (err == DB_SUCCESS) { - if (dberr_t err = - handle_instant_metadata(table, - cfg)) { - return row_import_error( - prebuilt, trx, err); - } + err = handle_instant_metadata(table, + cfg); } } } - } else { - rw_lock_s_unlock(&dict_sys.latch); } if (err != DB_SUCCESS) { - return(row_import_error(prebuilt, trx, err)); + return row_import_error(prebuilt, err); } - prebuilt->trx->op_info = "importing tablespace"; + trx->op_info = "importing tablespace"; ib::info() << "Phase I - Update all pages"; @@ -4546,31 +4424,28 @@ row_import_for_mysql( if (err != DB_DECRYPTION_FAILED) { - ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR, + ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_INTERNAL_ERROR, "Error importing tablespace for table %s : %s", table_name, ut_strerr(err)); } - return(row_import_cleanup(prebuilt, trx, err)); + return row_import_cleanup(prebuilt, err); } - row_mysql_lock_data_dictionary(trx); - /* If the table is stored in a remote tablespace, we need to determine that filepath from the link file and system tables. Find the space ID in SYS_TABLES since this is an ALTER TABLE. */ - dict_get_and_save_data_dir_path(table, true); + dict_get_and_save_data_dir_path(table); - if (DICT_TF_HAS_DATA_DIR(table->flags)) { - ut_a(table->data_dir_path); + ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path); + const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags) + ? table->data_dir_path : nullptr; + fil_space_t::name_type name{ + table->name.m_name, strlen(table->name.m_name)}; - filepath = fil_make_filepath( - table->data_dir_path, table->name.m_name, IBD, true); - } else { - filepath = fil_make_filepath( - NULL, table->name.m_name, IBD, false); - } + filepath = fil_make_filepath(data_dir_path, name, IBD, + data_dir_path != nullptr); DBUG_EXECUTE_IF( "ib_import_OOM_15", @@ -4579,13 +4454,10 @@ row_import_for_mysql( ); if (filepath == NULL) { - row_mysql_unlock_data_dictionary(trx); - return(row_import_cleanup(prebuilt, trx, DB_OUT_OF_MEMORY)); + return row_import_cleanup(prebuilt, DB_OUT_OF_MEMORY); } /* Open the tablespace so that we can access via the buffer pool. - We set the 2nd param (fix_dict = true) here because we already - have an x-lock on dict_sys.latch and dict_sys.mutex. The tablespace is initially opened as a temporary one, because we will not be writing any redo log for it before we have invoked fil_space_t::set_imported() to declare it a persistent tablespace. */ @@ -4593,35 +4465,29 @@ row_import_for_mysql( ulint fsp_flags = dict_tf_to_fsp_flags(table->flags); table->space = fil_ibd_open( - true, true, FIL_TYPE_IMPORT, table->space_id, - fsp_flags, table->name, filepath, &err); + 2, FIL_TYPE_IMPORT, table->space_id, + fsp_flags, name, filepath, &err); ut_ad((table->space == NULL) == (err != DB_SUCCESS)); DBUG_EXECUTE_IF("ib_import_open_tablespace_failure", err = DB_TABLESPACE_NOT_FOUND; table->space = NULL;); if (!table->space) { - row_mysql_unlock_data_dictionary(trx); - - ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR, + ib_senderrf(thd, IB_LOG_LEVEL_ERROR, ER_GET_ERRMSG, err, ut_strerr(err), filepath); - - ut_free(filepath); - - return(row_import_cleanup(prebuilt, trx, err)); } - row_mysql_unlock_data_dictionary(trx); - ut_free(filepath); - err = ibuf_check_bitmap_on_import(trx, table->space); + if (err == DB_SUCCESS) { + err = ibuf_check_bitmap_on_import(trx, table->space); + } DBUG_EXECUTE_IF("ib_import_check_bitmap_failure", err = DB_CORRUPTION;); if (err != DB_SUCCESS) { - return(row_import_cleanup(prebuilt, trx, err)); + return row_import_cleanup(prebuilt, err); } /* The first index must always be the clustered index. */ @@ -4629,7 +4495,7 @@ row_import_for_mysql( dict_index_t* index = dict_table_get_first_index(table); if (!dict_index_is_clust(index)) { - return(row_import_error(prebuilt, trx, DB_CORRUPTION)); + return row_import_error(prebuilt, DB_CORRUPTION); } /* Update the Btree segment headers for index node and @@ -4641,7 +4507,7 @@ row_import_for_mysql( err = DB_CORRUPTION;); if (err != DB_SUCCESS) { - return(row_import_error(prebuilt, trx, err)); + return row_import_error(prebuilt, err); } else if (cfg.requires_purge(index->name)) { /* Purge any delete-marked records that couldn't be @@ -4660,7 +4526,7 @@ row_import_for_mysql( DBUG_EXECUTE_IF("ib_import_cluster_failure", err = DB_CORRUPTION;); if (err != DB_SUCCESS) { - return(row_import_error(prebuilt, trx, err)); + return row_import_error(prebuilt, err); } /* For secondary indexes, purge any records that couldn't be purged @@ -4673,7 +4539,7 @@ row_import_for_mysql( err = DB_CORRUPTION;); if (err != DB_SUCCESS) { - return(row_import_error(prebuilt, trx, err)); + return row_import_error(prebuilt, err); } /* Ensure that the next available DB_ROW_ID is not smaller than @@ -4697,7 +4563,7 @@ row_import_for_mysql( ib::warn() << "Waiting for flush to complete on " << prebuilt->table->name; } - os_thread_sleep(20000); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); } ib::info() << "Phase IV - Flush complete"; @@ -4712,13 +4578,13 @@ row_import_for_mysql( err = row_import_update_index_root(trx, table, false); if (err != DB_SUCCESS) { - return(row_import_error(prebuilt, trx, err)); + return row_import_error(prebuilt, err); } err = row_import_update_discarded_flag(trx, table->id, false); if (err != DB_SUCCESS) { - return(row_import_error(prebuilt, trx, err)); + return row_import_error(prebuilt, err); } table->file_unreadable = false; @@ -4734,5 +4600,5 @@ row_import_for_mysql( btr_write_autoinc(dict_table_get_first_index(table), autoinc); } - return(row_import_cleanup(prebuilt, trx, err)); + return row_import_cleanup(prebuilt, err); } |