diff options
Diffstat (limited to 'storage/innobase/include/row0import.h')
-rw-r--r-- | storage/innobase/include/row0import.h | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/storage/innobase/include/row0import.h b/storage/innobase/include/row0import.h index fd2651da39e..7019ab2a900 100644 --- a/storage/innobase/include/row0import.h +++ b/storage/innobase/include/row0import.h @@ -28,11 +28,296 @@ Created 2012-02-08 by Sunny Bains #define row0import_h #include "dict0types.h" +#include "ut0new.h" +#include "os0file.h" +#include "buf0buf.h" +#include "trx0trx.h" +#include "page0page.h" // Forward declarations struct trx_t; struct dict_table_t; struct row_prebuilt_t; +struct fil_iterator_t; +struct row_import; + +/** The size of the buffer to use for IO. +@param n physical page size +@return number of pages */ +#define IO_BUFFER_SIZE(n) ((1024 * 1024) / (n)) + +/** Functor that is called for each physical page that is read from the +tablespace file. */ +class AbstractCallback +{ +public: + /** Constructor + @param trx covering transaction */ + AbstractCallback(trx_t* trx, uint32_t space_id) + : + m_zip_size(0), + m_trx(trx), + m_space(space_id), + m_xdes(), + m_xdes_page_no(UINT32_MAX), + m_space_flags(UINT32_MAX) UNIV_NOTHROW { } + + /** Free any extent descriptor instance */ + virtual ~AbstractCallback() + { + UT_DELETE_ARRAY(m_xdes); + } + + /** Determine the page size to use for traversing the tablespace + @param file_size size of the tablespace file in bytes + @param block contents of the first page in the tablespace file. + @retval DB_SUCCESS or error code. */ + virtual dberr_t init( + os_offset_t file_size, + const buf_block_t* block) UNIV_NOTHROW; + + /** @return true if compressed table. */ + bool is_compressed_table() const UNIV_NOTHROW + { + return get_zip_size(); + } + + /** @return the tablespace flags */ + uint32_t get_space_flags() const { return m_space_flags; } + + /** + Set the name of the physical file and the file handle that is used + to open it for the file that is being iterated over. + @param filename the physical name of the tablespace file + @param file OS file handle */ + void set_file(const char* filename, pfs_os_file_t file) UNIV_NOTHROW + { + m_file = file; + m_filepath = filename; + } + + ulint get_zip_size() const { return m_zip_size; } + ulint physical_size() const + { + return m_zip_size ? m_zip_size : srv_page_size; + } + + const char* filename() const { return m_filepath; } + + /** + 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->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; + + /** @return the tablespace identifier */ + uint32_t get_space_id() const { return m_space; } + + bool is_interrupted() const { return trx_is_interrupted(m_trx); } + + /** + Get the data page depending on the table type, compressed or not. + @param block - block read from disk + @retval the buffer frame */ + static byte* get_frame(const buf_block_t* block) + { + return block->page.zip.data + ? block->page.zip.data : block->page.frame; + } + + /** Invoke the functionality for the callback */ + virtual dberr_t run(const fil_iterator_t& iter, + buf_block_t* block) UNIV_NOTHROW = 0; + +protected: + /** Get the physical offset of the extent descriptor within the page. + @param page_no page number of the extent descriptor + @param page contents of the page containing the extent descriptor. + @return the start of the xdes array in a page */ + const xdes_t* xdes( + ulint page_no, + const page_t* page) const UNIV_NOTHROW + { + ulint offset; + + offset = xdes_calc_descriptor_index(get_zip_size(), page_no); + + return(page + XDES_ARR_OFFSET + XDES_SIZE * offset); + } + + /** Set the current page directory (xdes). If the extent descriptor is + marked as free then free the current extent descriptor and set it to + 0. This implies that all pages that are covered by this extent + descriptor are also freed. + + @param page_no offset of page within the file + @param page page contents + @return DB_SUCCESS or error code. */ + dberr_t set_current_xdes( + uint32_t page_no, + const page_t* page) UNIV_NOTHROW + { + m_xdes_page_no = page_no; + + UT_DELETE_ARRAY(m_xdes); + m_xdes = NULL; + + if (mach_read_from_4(XDES_ARR_OFFSET + XDES_STATE + page) + != XDES_FREE) { + const ulint physical_size = m_zip_size + ? m_zip_size : srv_page_size; + + m_xdes = UT_NEW_ARRAY_NOKEY(xdes_t, physical_size); + + /* Trigger OOM */ + DBUG_EXECUTE_IF( + "ib_import_OOM_13", + UT_DELETE_ARRAY(m_xdes); + m_xdes = NULL; + ); + + if (m_xdes == NULL) { + return(DB_OUT_OF_MEMORY); + } + + memcpy(m_xdes, page, physical_size); + } + + return(DB_SUCCESS); + } + + /** Check if the page is marked as free in the extent descriptor. + @param page_no page number to check in the extent descriptor. + @return true if the page is marked as free */ + bool is_free(uint32_t page_no) const UNIV_NOTHROW + { + ut_a(xdes_calc_descriptor_page(get_zip_size(), page_no) + == m_xdes_page_no); + + if (m_xdes != 0) { + const xdes_t* xdesc = xdes(page_no, m_xdes); + ulint pos = page_no % FSP_EXTENT_SIZE; + + return xdes_is_free(xdesc, pos); + } + + /* If the current xdes was free, the page must be free. */ + return(true); + } + +protected: + /** The ROW_FORMAT=COMPRESSED page size, or 0. */ + ulint m_zip_size; + + /** File handle to the tablespace */ + pfs_os_file_t m_file; + + /** Physical file path. */ + const char* m_filepath; + + /** Covering transaction. */ + trx_t* m_trx; + + /** Space id of the file being iterated over. */ + uint32_t m_space; + + /** Current extent descriptor page */ + xdes_t* m_xdes; + + /** Physical page offset in the file of the extent descriptor */ + uint32_t m_xdes_page_no; + + /** Flags value read from the header page */ + uint32_t m_space_flags; +}; + +/** +Try and determine the index root pages by checking if the next/prev +pointers are both FIL_NULL. We need to ensure that skip deleted pages. */ +struct FetchIndexRootPages : public AbstractCallback { + + /** Index information gathered from the .ibd file. */ + struct Index { + + Index(index_id_t id, uint32_t page_no) + : + m_id(id), + m_page_no(page_no) { } + + index_id_t m_id; /*!< Index id */ + uint32_t m_page_no; /*!< Root page number */ + }; + + /** Constructor + @param trx covering (user) transaction + @param table table definition in server .*/ + FetchIndexRootPages(const dict_table_t* table, trx_t* trx) + : + AbstractCallback(trx, UINT32_MAX), + m_table(table), m_index(0, 0) UNIV_NOTHROW { } + + FetchIndexRootPages() + : + AbstractCallback(nullptr, UINT32_MAX), + m_table(nullptr), m_index(0, 0) UNIV_NOTHROW { } + + /** Destructor */ + ~FetchIndexRootPages() UNIV_NOTHROW override = default; + + /** Fetch the clustered index root page in the tablespace + @param iter Tablespace iterator + @param block Block to use for IO + @retval DB_SUCCESS or error code */ + dberr_t run(const fil_iterator_t& iter, + buf_block_t* block) UNIV_NOTHROW override; + + /** Check that fsp flags and row formats match. + @param block block to convert, it is not from the buffer pool. + @retval DB_SUCCESS or error code. */ + dberr_t operator()(buf_block_t* block) UNIV_NOTHROW override; + + /** Get row format from the header and the root index page. */ + enum row_type get_row_format(buf_block_t *block) + { + if (!page_is_comp(block->page.frame)) + return ROW_TYPE_REDUNDANT; + /* With full_crc32 we cannot tell between dynamic or compact, and + return not_used. We cannot simply return dynamic or compact, as + the client of this function will not be able to tell whether it is + dynamic because of this or the other branch below. Returning + default would also work if it is immediately handled, but is still + more ambiguous than not_used, which is not a row_format at all. */ + if (fil_space_t::full_crc32(m_space_flags)) + return ROW_TYPE_NOT_USED; + if (m_space_flags & FSP_FLAGS_MASK_ATOMIC_BLOBS) + { + if (FSP_FLAGS_GET_ZIP_SSIZE(m_space_flags)) + return ROW_TYPE_COMPRESSED; + else + return ROW_TYPE_DYNAMIC; + } + return ROW_TYPE_COMPACT; + } + + /** Update the import configuration that will be used to import + the tablespace. */ + dberr_t build_row_import(row_import* cfg) const UNIV_NOTHROW; + + /** Table definition in server. When the table is being created, + there's no table yet so m_table is nullptr */ + const dict_table_t* m_table; + + /** Table row format. Only used when a (stub) table is being created + in which case m_table is null, for obtaining row format from the + .ibd for the stub table. */ + enum row_type m_row_format; + + /** Index information */ + Index m_index; +}; /*****************************************************************//** Imports a tablespace. The space id in the .ibd file must match the space id @@ -64,4 +349,29 @@ dberr_t row_import_update_index_root(trx_t* trx, dict_table_t* table, bool reset) MY_ATTRIBUTE((nonnull, warn_unused_result)); +/********************************************************************//** +Iterate over all or some pages in the tablespace. +@param dir_path - the path to data dir storing the tablespace +@param name - the table name +@param n_io_buffers - number of blocks to read and write together +@param callback - functor that will do the page queries or updates +@return DB_SUCCESS or error code */ +dberr_t +fil_tablespace_iterate( +/*===================*/ + const char* dir_path, + const char* name, + ulint n_io_buffers, + AbstractCallback& callback); + +/** +Read the row type from a .cfg file. +@param[in] dir_path Path to the data directory containing the .cfg file +@param[in] name Name of the table +@param[in] thd Session +@param[out] result The row format read from the .cfg file +@return DB_SUCCESS or error code. */ +dberr_t get_row_type_from_cfg(const char* dir_path, const char* name, THD* thd, + rec_format_enum& result); + #endif /* row0import_h */ |