diff options
Diffstat (limited to 'storage/innobase/row/row0import.cc')
-rw-r--r-- | storage/innobase/row/row0import.cc | 267 |
1 files changed, 127 insertions, 140 deletions
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 4fdc6581005..1fdd2ac9b94 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -31,12 +31,12 @@ Created 2012-02-08 by Sunny Bains. #include "dict0load.h" #include "ibuf0ibuf.h" #include "pars0pars.h" -#include "row0upd.h" #include "row0sel.h" #include "row0mysql.h" #include "srv0start.h" #include "row0quiesce.h" #include "fil0pagecompress.h" +#include "trx0undo.h" #ifdef HAVE_LZO #include "lzo/lzo1x.h" #endif @@ -354,11 +354,11 @@ class AbstractCallback public: /** Constructor @param trx covering transaction */ - AbstractCallback(trx_t* trx) + AbstractCallback(trx_t* trx, ulint space_id) : m_page_size(0, 0, false), m_trx(trx), - m_space(ULINT_UNDEFINED), + m_space(space_id), m_xdes(), m_xdes_page_no(ULINT_UNDEFINED), m_space_flags(ULINT_UNDEFINED) UNIV_NOTHROW { } @@ -408,14 +408,13 @@ 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 + UNIV_PAGE_SIZE; + block->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; - /** - @return the space id of the tablespace */ - virtual ulint get_space_id() const UNIV_NOTHROW = 0; + /** @return the tablespace identifier */ + ulint get_space_id() const { return m_space; } bool is_interrupted() const { return trx_is_interrupted(m_trx); } @@ -575,7 +574,7 @@ AbstractCallback::init( ib::error() << "Page size " << m_page_size.physical() << " of ibd file is not the same as the server page" - " size " << univ_page_size.physical(); + " size " << srv_page_size; return(DB_CORRUPTION); @@ -588,11 +587,12 @@ AbstractCallback::init( return(DB_CORRUPTION); } - ut_a(m_space == ULINT_UNDEFINED); - m_size = mach_read_from_4(page + FSP_SIZE); m_free_limit = mach_read_from_4(page + FSP_FREE_LIMIT); - m_space = mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID); + if (m_space == ULINT_UNDEFINED) { + m_space = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + + page); + } return set_current_xdes(0, page); } @@ -621,19 +621,12 @@ struct FetchIndexRootPages : public AbstractCallback { @param table table definition in server .*/ FetchIndexRootPages(const dict_table_t* table, trx_t* trx) : - AbstractCallback(trx), + AbstractCallback(trx, ULINT_UNDEFINED), m_table(table) UNIV_NOTHROW { } /** Destructor */ virtual ~FetchIndexRootPages() UNIV_NOTHROW { } - /** - @retval the space id of the tablespace being iterated over */ - virtual ulint get_space_id() const UNIV_NOTHROW - { - return(m_space); - } - /** Called for each block as it is read from the file. @param block block to convert, it is not from the buffer pool. @retval DB_SUCCESS or error code. */ @@ -792,8 +785,23 @@ class PageConverter : public AbstractCallback { public: /** Constructor @param cfg config of table being imported. + @param space_id tablespace identifier @param trx transaction covering the import */ - PageConverter(row_import* cfg, trx_t* trx) UNIV_NOTHROW; + PageConverter(row_import* cfg, ulint space_id, trx_t* trx) + : + AbstractCallback(trx, space_id), + m_cfg(cfg), + m_index(cfg->m_indexes), + m_current_lsn(log_get_lsn()), + m_page_zip_ptr(0), + m_rec_iter(), + m_offsets_(), m_offsets(m_offsets_), + m_heap(0), + m_cluster_index(dict_table_get_first_index(cfg->m_table)) + { + ut_ad(m_current_lsn); + rec_offs_init(m_offsets_); + } virtual ~PageConverter() UNIV_NOTHROW { @@ -802,13 +810,6 @@ public: } } - /** - @retval the server space id of the tablespace being iterated over */ - virtual ulint get_space_id() const UNIV_NOTHROW - { - return(m_cfg->m_table->space); - } - /** Called for each block as it is read from the file. @param block block to convert, it is not from the buffer pool. @retval DB_SUCCESS or error code. */ @@ -868,17 +869,14 @@ private: /** Purge delete-marked records, only if it is possible to do so without re-organising the B+tree. - @param offsets current row offsets. @retval true if purged */ - bool purge(const ulint* offsets) UNIV_NOTHROW; + bool purge() UNIV_NOTHROW; /** Adjust the BLOB references and sys fields for the current record. - @param index the index being converted @param rec record to update @param offsets column offsets for the record @return DB_SUCCESS or error code. */ dberr_t adjust_cluster_record( - const dict_index_t* index, rec_t* rec, const ulint* offsets) UNIV_NOTHROW; @@ -1347,8 +1345,6 @@ row_import::set_root_by_name() UNIV_NOTHROW /* We've already checked that it exists. */ ut_a(index != 0); - /* Set the root page number and space id. */ - index->space = m_table->space; index->page = cfg_index->m_page_no; } } @@ -1408,7 +1404,6 @@ row_import::set_root_by_heuristic() UNIV_NOTHROW cfg_index[i].m_srv_index = index; - index->space = m_table->space; index->page = cfg_index[i].m_page_no; ++i; @@ -1463,6 +1458,13 @@ IndexPurge::open() UNIV_NOTHROW 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); + } } /** @@ -1552,28 +1554,6 @@ IndexPurge::purge() UNIV_NOTHROW btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr); } -/** Constructor -@param cfg config of table being imported. -@param trx transaction covering the import */ -inline -PageConverter::PageConverter( - row_import* cfg, - trx_t* trx) - : - AbstractCallback(trx), - m_cfg(cfg), - m_index(cfg->m_indexes), - m_current_lsn(log_get_lsn()), - m_page_zip_ptr(0), - m_rec_iter(), - m_offsets_(), m_offsets(m_offsets_), - m_heap(0), - m_cluster_index(dict_table_get_first_index(cfg->m_table)) UNIV_NOTHROW -{ - ut_a(m_current_lsn > 0); - rec_offs_init(m_offsets_); -} - /** Adjust the BLOB reference for a single column that is externally stored @param rec record to update @param offsets column offsets for the record @@ -1606,7 +1586,7 @@ PageConverter::adjust_cluster_index_blob_column( return(DB_CORRUPTION); } - field += BTR_EXTERN_SPACE_ID - BTR_EXTERN_FIELD_REF_SIZE + len; + field += len - (BTR_EXTERN_FIELD_REF_SIZE - BTR_EXTERN_SPACE_ID); mach_write_to_4(field, get_space_id()); @@ -1677,11 +1657,8 @@ PageConverter::adjust_cluster_index_blob_ref( /** Purge delete-marked records, only if it is possible to do so without re-organising the B+tree. -@param offsets current row offsets. @return true if purge succeeded */ -inline -bool -PageConverter::purge(const ulint* offsets) UNIV_NOTHROW +inline bool PageConverter::purge() UNIV_NOTHROW { const dict_index_t* index = m_index->m_srv_index; @@ -1705,7 +1682,6 @@ PageConverter::purge(const ulint* offsets) UNIV_NOTHROW inline dberr_t PageConverter::adjust_cluster_record( - const dict_index_t* index, rec_t* rec, const ulint* offsets) UNIV_NOTHROW { @@ -1716,10 +1692,20 @@ PageConverter::adjust_cluster_record( /* Reset DB_TRX_ID and DB_ROLL_PTR. Normally, these fields are only written in conjunction with other changes to the record. */ - - row_upd_rec_sys_fields( - rec, m_page_zip_ptr, m_cluster_index, m_offsets, - m_trx, roll_ptr_t(1) << ROLL_PTR_INSERT_FLAG_POS); + ulint trx_id_pos = m_cluster_index->n_uniq + ? m_cluster_index->n_uniq : 1; + if (m_page_zip_ptr) { + page_zip_write_trx_id_and_roll_ptr( + m_page_zip_ptr, rec, m_offsets, trx_id_pos, + 0, roll_ptr_t(1) << ROLL_PTR_INSERT_FLAG_POS, + NULL); + } else { + ulint len; + byte* ptr = rec_get_nth_field( + rec, m_offsets, trx_id_pos, &len); + ut_ad(len == DATA_TRX_ID_LEN); + memcpy(ptr, reset_trx_id, sizeof reset_trx_id); + } } return(err); @@ -1758,8 +1744,7 @@ PageConverter::update_records( if (clust_index) { - dberr_t err = adjust_cluster_record( - m_index->m_srv_index, rec, m_offsets); + dberr_t err = adjust_cluster_record(rec, m_offsets); if (err != DB_SUCCESS) { return(err); @@ -1773,7 +1758,7 @@ PageConverter::update_records( /* A successful purge will move the cursor to the next record. */ - if (!purge(m_offsets)) { + if (!purge()) { m_rec_iter.next(); } @@ -1836,6 +1821,13 @@ PageConverter::update_index_page( if (dict_index_is_clust(m_index->m_srv_index)) { if (page_is_root(page)) { /* Preserve the PAGE_ROOT_AUTO_INC. */ + if (m_index->m_srv_index->table->supports_instant() + && btr_cur_instant_root_init( + const_cast<dict_index_t*>( + m_index->m_srv_index), + page)) { + return(DB_CORRUPTION); + } } else { /* Clear PAGE_MAX_TRX_ID so that it can be used for other purposes in the future. IMPORT @@ -1938,6 +1930,8 @@ PageConverter::update_page( return(DB_CORRUPTION); } + /* fall through */ + case FIL_PAGE_TYPE_INSTANT: /* This is on every page in the tablespace. */ mach_write_to_4( get_frame(block) @@ -2052,12 +2046,13 @@ row_import_discard_changes( index = UT_LIST_GET_NEXT(indexes, index)) { index->page = FIL_NULL; - index->space = FIL_NULL; } table->file_unreadable = true; - - fil_close_tablespace(trx, table->space); + if (table->space) { + fil_close_tablespace(trx, table->space_id); + table->space = NULL; + } } /*****************************************************************//** @@ -2084,7 +2079,7 @@ row_import_cleanup( row_mysql_unlock_data_dictionary(trx); - trx_free_for_mysql(trx); + trx_free(trx); prebuilt->trx->op_info = ""; @@ -2129,8 +2124,6 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result)) dberr_t row_import_adjust_root_pages_of_secondary_indexes( /*==============================================*/ - row_prebuilt_t* prebuilt, /*!< in/out: prebuilt from - handler */ trx_t* trx, /*!< in: transaction used for the import */ dict_table_t* table, /*!< in: table the indexes @@ -2154,7 +2147,6 @@ row_import_adjust_root_pages_of_secondary_indexes( ut_a(!dict_index_is_clust(index)); if (!(index->type & DICT_CORRUPT) - && index->space != FIL_NULL && index->page != FIL_NULL) { /* Update the Btree segment headers for index node and @@ -2269,7 +2261,14 @@ row_import_set_sys_max_row_id( rec = btr_pcur_get_rec(&pcur); /* Check for empty table. */ - if (!page_rec_is_infimum(rec)) { + if (page_rec_is_infimum(rec)) { + /* The table is empty. */ + err = DB_SUCCESS; + } else if (rec_is_metadata(rec, index)) { + /* The clustered index contains the metadata record only, + that is, the table is empty. */ + err = DB_SUCCESS; + } else { ulint len; const byte* field; mem_heap_t* heap = NULL; @@ -2296,9 +2295,6 @@ row_import_set_sys_max_row_id( if (heap != NULL) { mem_heap_free(heap); } - } else { - /* The table is empty. */ - err = DB_SUCCESS; } btr_pcur_close(&pcur); @@ -2385,8 +2381,7 @@ row_import_cfg_read_index_fields( /*=============================*/ FILE* file, /*!< in: file to write to */ THD* thd, /*!< in/out: session */ - row_index_t* index, /*!< Index being read in */ - row_import* cfg) /*!< in/out: meta-data read */ + row_index_t* index) /*!< Index being read in */ { byte row[sizeof(ib_uint32_t) * 3]; ulint n_fields = index->m_n_fields; @@ -2606,8 +2601,7 @@ row_import_read_index_data( return(err); } - err = row_import_cfg_read_index_fields( - file, thd, cfg_index, cfg); + err = row_import_cfg_read_index_fields(file, thd, cfg_index); if (err != DB_SUCCESS) { return(err); @@ -2937,14 +2931,14 @@ row_import_read_v1( const ulint logical_page_size = mach_read_from_4(ptr); ptr += sizeof(ib_uint32_t); - if (logical_page_size != univ_page_size.logical()) { + if (logical_page_size != srv_page_size) { ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, "Tablespace to be imported has a different" " page size than this server. Server page size" - " is " ULINTPF ", whereas tablespace page size" + " is %lu, whereas tablespace page size" " is " ULINTPF, - univ_page_size.logical(), + srv_page_size, logical_page_size); return(DB_ERROR); @@ -2983,7 +2977,6 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result)) dberr_t row_import_read_meta_data( /*======================*/ - dict_table_t* table, /*!< in: table */ FILE* file, /*!< in: File to read from */ THD* thd, /*!< in: session */ row_import& cfg) /*!< out: contents of the .cfg file */ @@ -3057,7 +3050,7 @@ row_import_read_cfg( cfg.m_missing = false; - err = row_import_read_meta_data(table, file, thd, cfg); + err = row_import_read_meta_data(file, thd, cfg); fclose(file); } @@ -3086,6 +3079,8 @@ row_import_update_index_root( que_t* graph = 0; dberr_t err = DB_SUCCESS; + ut_ad(reset || table->space->id == table->space_id); + static const char sql[] = { "PROCEDURE UPDATE_INDEX_ROOT() IS\n" "BEGIN\n" @@ -3123,7 +3118,7 @@ row_import_update_index_root( mach_write_to_4( reinterpret_cast<byte*>(&space), - reset ? FIL_NULL : index->space); + reset ? FIL_NULL : index->table->space_id); mach_write_to_8( reinterpret_cast<byte*>(&index_id), @@ -3226,22 +3221,13 @@ row_import_set_discarded( return(FALSE); } -/*****************************************************************//** -Update the DICT_TF2_DISCARDED flag in SYS_TABLES. -@return DB_SUCCESS or error code. */ -dberr_t -row_import_update_discarded_flag( -/*=============================*/ - trx_t* trx, /*!< in/out: transaction that - covers the update */ - table_id_t table_id, /*!< in: Table for which we want - to set the root table->flags2 */ - bool discarded, /*!< in: set MIX_LEN column bit - to discarded, if true */ - bool dict_locked) /*!< in: set to true if the - caller already owns the - dict_sys_t:: mutex. */ - +/** Update the DICT_TF2_DISCARDED flag in SYS_TABLES.MIX_LEN. +@param[in,out] trx dictionary transaction +@param[in] table_id table identifier +@param[in] discarded whether to set or clear the flag +@return DB_SUCCESS or error code */ +dberr_t row_import_update_discarded_flag(trx_t* trx, table_id_t table_id, + bool discarded) { pars_info_t* info; discard_t discard; @@ -3280,7 +3266,7 @@ row_import_update_discarded_flag( pars_info_bind_function( info, "my_func", row_import_set_discarded, &discard); - dberr_t err = que_eval_sql(info, sql, !dict_locked, trx); + dberr_t err = que_eval_sql(info, sql, false, trx); ut_a(discard.n_recs == 1); ut_a(discard.flags2 != ULINT32_UNDEFINED); @@ -3659,8 +3645,8 @@ fil_tablespace_iterate( We allocate an extra page in case it is a compressed table. One page is to ensure alignement. */ - void* page_ptr = ut_malloc_nokey(3 * UNIV_PAGE_SIZE); - byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE)); + void* page_ptr = ut_malloc_nokey(3U << srv_page_size_shift); + byte* page = static_cast<byte*>(ut_align(page_ptr, srv_page_size)); buf_block_t* block = reinterpret_cast<buf_block_t*> (ut_zalloc_nokey(sizeof *block)); @@ -3676,7 +3662,7 @@ fil_tablespace_iterate( request.disable_partial_io_warnings(); err = os_file_read_no_error_handling(request, file, page, 0, - UNIV_PAGE_SIZE, 0); + srv_page_size, 0); if (err == DB_SUCCESS) { err = callback.init(file_size, block); @@ -3715,23 +3701,24 @@ fil_tablespace_iterate( /* Add an extra page for compressed page scratch area. */ void* io_buffer = ut_malloc_nokey( - (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE); + (2 + iter.n_io_buffers) << srv_page_size_shift); iter.io_buffer = static_cast<byte*>( - ut_align(io_buffer, UNIV_PAGE_SIZE)); + ut_align(io_buffer, srv_page_size)); void* crypt_io_buffer = NULL; if (iter.crypt_data) { crypt_io_buffer = ut_malloc_nokey( - (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE); + (2 + iter.n_io_buffers) + << srv_page_size_shift); iter.crypt_io_buffer = static_cast<byte*>( - ut_align(crypt_io_buffer, UNIV_PAGE_SIZE)); + ut_align(crypt_io_buffer, srv_page_size)); } if (block->page.zip.ssize) { ut_ad(iter.n_io_buffers == 1); block->frame = iter.io_buffer; - block->page.zip.data = block->frame + UNIV_PAGE_SIZE; + block->page.zip.data = block->frame + srv_page_size; } err = fil_iterate(iter, block, callback); @@ -3783,17 +3770,18 @@ row_import_for_mysql( /* The caller assured that this is not read_only_mode and that no temorary tablespace is being imported. */ ut_ad(!srv_read_only_mode); - ut_ad(!dict_table_is_temporary(table)); + ut_ad(!table->is_temporary()); - ut_a(table->space); + ut_ad(table->space_id); + ut_ad(table->space_id < SRV_LOG_SPACE_FIRST_ID); ut_ad(prebuilt->trx); - ut_a(!table->is_readable()); + ut_ad(!table->is_readable()); - ibuf_delete_for_discarded_space(table->space); + ibuf_delete_for_discarded_space(table->space_id); trx_start_if_not_started(prebuilt->trx, true); - trx = trx_allocate_for_mysql(); + trx = trx_create(); /* So that the table is not DROPped during recovery. */ trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); @@ -3811,14 +3799,13 @@ row_import_for_mysql( /* Assign an undo segment for the transaction, so that the transaction will be recovered after a crash. */ - mutex_enter(&trx->undo_mutex); - /* TODO: Do not write any undo log for the IMPORT cleanup. */ - trx_undo_t** pundo = &trx->rsegs.m_redo.update_undo; - err = trx_undo_assign_undo(trx, trx->rsegs.m_redo.rseg, pundo, - TRX_UNDO_UPDATE); - - mutex_exit(&trx->undo_mutex); + { + mtr_t mtr; + mtr.start(); + trx_undo_assign(trx, &err, &mtr); + mtr.commit(); + } DBUG_EXECUTE_IF("ib_import_undo_assign_failure", err = DB_TOO_MANY_CONCURRENT_TRXS;); @@ -3827,7 +3814,7 @@ row_import_for_mysql( return(row_import_cleanup(prebuilt, trx, err)); - } else if (trx->rsegs.m_redo.update_undo == 0) { + } else if (trx->rsegs.m_redo.undo == 0) { err = DB_TOO_MANY_CONCURRENT_TRXS; return(row_import_cleanup(prebuilt, trx, err)); @@ -3915,7 +3902,7 @@ row_import_for_mysql( /* Iterate over all the pages and do the sanity checking and the conversion required to import the tablespace. */ - PageConverter converter(&cfg, trx); + PageConverter converter(&cfg, table->space_id, trx); /* Set the IO buffer size in pages. */ @@ -3994,18 +3981,19 @@ row_import_for_mysql( have an x-lock on dict_operation_lock 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_set_imported() to declare it a persistent tablespace. */ + fil_space_t::set_imported() to declare it a persistent tablespace. */ ulint fsp_flags = dict_tf_to_fsp_flags(table->flags); - err = fil_ibd_open( - true, true, FIL_TYPE_IMPORT, table->space, - fsp_flags, table->name.m_name, filepath); + table->space = fil_ibd_open( + true, true, FIL_TYPE_IMPORT, table->space_id, + fsp_flags, table->name, filepath, &err); + ut_ad((table->space == NULL) == (err != DB_SUCCESS)); DBUG_EXECUTE_IF("ib_import_open_tablespace_failure", - err = DB_TABLESPACE_NOT_FOUND;); + err = DB_TABLESPACE_NOT_FOUND; table->space = NULL;); - if (err != DB_SUCCESS) { + if (!table->space) { row_mysql_unlock_data_dictionary(trx); ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR, @@ -4072,7 +4060,7 @@ row_import_for_mysql( during the page conversion phase. */ err = row_import_adjust_root_pages_of_secondary_indexes( - prebuilt, trx, table, cfg); + trx, table, cfg); DBUG_EXECUTE_IF("ib_import_sec_root_adjust_failure", err = DB_CORRUPTION;); @@ -4101,7 +4089,7 @@ row_import_for_mysql( { FlushObserver observer(prebuilt->table->space, trx, NULL); - buf_LRU_flush_or_remove_pages(prebuilt->table->space, + buf_LRU_flush_or_remove_pages(prebuilt->table->space_id, &observer); if (observer.is_interrupted()) { @@ -4112,7 +4100,7 @@ row_import_for_mysql( } ib::info() << "Phase IV - Flush complete"; - fil_space_set_imported(prebuilt->table->space); + prebuilt->table->space->set_imported(); /* The dictionary latches will be released in in row_import_cleanup() after the transaction commit, for both success and error. */ @@ -4126,8 +4114,7 @@ row_import_for_mysql( return(row_import_error(prebuilt, trx, err)); } - /* Update the table's discarded flag, unset it. */ - err = row_import_update_discarded_flag(trx, table->id, false, true); + err = row_import_update_discarded_flag(trx, table->id, false); if (err != DB_SUCCESS) { return(row_import_error(prebuilt, trx, err)); |