mariadb/storage/innobase/include/fsp0sysspace.h
Jan Lindström eca238aea7 MDEV-13557: Startup failure, unable to decrypt ibdata1
Fixes also MDEV-13488: InnoDB writes CRYPT_INFO even though
encryption is not enabled.

Fixes also MDEV-13093: Leak of Datafile::m_crypt_info on
shutdown after failed startup.

Problem was that we created encryption metadata (crypt_data) for
system tablespace even when no encryption was enabled and too early.
System tablespace can be encrypted only using key rotation.

Test innodb-key-rotation-disable, innodb_encryption, innodb_lotoftables
require adjustment because INFORMATION_SCHEMA INNODB_TABLESPACES_ENCRYPTION
contain row only if tablespace really has encryption metadata.

xb_load_single_table_tablespace(): Do not call
fil_space_destroy_crypt_data() any more, because Datafile::m_crypt_data
has been removed.

fil_crypt_realloc_iops(): Avoid divide by zero.

fil_crypt_set_thread_cnt(): Set fil_crypt_threads_event if
encryption threads exist. This is required to find tablespaces
requiring key rotation if no other changes happen.

fil_crypt_find_space_to_rotate(): Decrease the amount of time waiting
when nothing happens to better enable key rotation on startup.

fil_ibd_open(), fil_ibd_load(): Load possible crypt_data from first
page.

class Datafile, class SysTablespace : remove m_crypt_info field.

Datafile::get_first_page(): Return a pointer to first page buffer.

fsp_header_init(): Write encryption metadata to page 0 only if
tablespace is encrypted or encryption is disabled by table option.

i_s_dict_fill_tablespaces_encryption(): Skip tablespaces that do not
contain encryption metadata. This is required to avoid too early
wait condition trigger in encrypted -> unencrypted state transfer.
2017-08-31 08:36:56 +03:00

299 lines
8.3 KiB
C++

/*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
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 include/fsp0sysspace.h
Multi file, shared, system tablespace implementation.
Created 2013-7-26 by Kevin Lewis
*******************************************************/
#ifndef fsp0sysspace_h
#define fsp0sysspace_h
#include "univ.i"
#include "fsp0space.h"
/** If the last data file is auto-extended, we add this many pages to it
at a time. We have to make this public because it is a config variable. */
extern ulong sys_tablespace_auto_extend_increment;
#ifdef UNIV_DEBUG
/** Control if extra debug checks need to be done for temporary tablespace.
Default = true that is disable such checks.
This variable is not exposed to end-user but still kept as variable for
developer to enable it during debug. */
extern bool srv_skip_temp_table_checks_debug;
#endif /* UNIV_DEBUG */
/** Data structure that contains the information about shared tablespaces.
Currently this can be the system tablespace or a temporary table tablespace */
class SysTablespace : public Tablespace
{
public:
SysTablespace()
:
m_auto_extend_last_file(),
m_last_file_size_max(),
m_created_new_raw(),
m_is_tablespace_full(false),
m_sanity_checks_done(false)
{
/* No op */
}
~SysTablespace()
{
shutdown();
}
/** Set tablespace full status
@param[in] is_full true if full */
void set_tablespace_full_status(bool is_full)
{
m_is_tablespace_full = is_full;
}
/** Get tablespace full status
@return true if table is full */
bool get_tablespace_full_status()
{
return(m_is_tablespace_full);
}
/** Set sanity check status
@param[in] status true if sanity checks are done */
void set_sanity_check_status(bool status)
{
m_sanity_checks_done = status;
}
/** Get sanity check status
@return true if sanity checks are done */
bool get_sanity_check_status()
{
return(m_sanity_checks_done);
}
/** Parse the input params and populate member variables.
@param filepath path to data files
@param supports_raw true if it supports raw devices
@return true on success parse */
bool parse_params(const char* filepath, bool supports_raw);
/** Check the data file specification.
@param[out] create_new_db true if a new database
is to be created
@param[in] min_expected_size expected tablespace
size in bytes
@return DB_SUCCESS if all OK else error code */
dberr_t check_file_spec(
bool* create_new_db,
ulint min_expected_tablespace_size);
/** Free the memory allocated by parse() */
void shutdown();
/** Normalize the file size, convert to extents. */
void normalize();
/**
@return true if a new raw device was created. */
bool created_new_raw() const
{
return(m_created_new_raw);
}
/**
@return auto_extend value setting */
ulint can_auto_extend_last_file() const
{
return(m_auto_extend_last_file);
}
/** Set the last file size.
@param[in] size the size to set */
void set_last_file_size(ulint size)
{
ut_ad(!m_files.empty());
m_files.back().m_size = size;
}
/** Get the size of the last data file in the tablespace
@return the size of the last data file in the array */
ulint last_file_size() const
{
ut_ad(!m_files.empty());
return(m_files.back().m_size);
}
/**
@return the autoextend increment in pages. */
ulint get_autoextend_increment() const
{
return(sys_tablespace_auto_extend_increment
* ((1024 * 1024) / UNIV_PAGE_SIZE));
}
/**
@return next increment size */
ulint get_increment() const;
/** Open or create the data files
@param[in] is_temp whether this is a temporary tablespace
@param[in] create_new_db whether we are creating a new database
@param[out] sum_new_sizes sum of sizes of the new files added
@param[out] flush_lsn FIL_PAGE_FILE_FLUSH_LSN of first file
@return DB_SUCCESS or error code */
dberr_t open_or_create(
bool is_temp,
bool create_new_db,
ulint* sum_new_sizes,
lsn_t* flush_lsn)
MY_ATTRIBUTE((warn_unused_result));
private:
/** Check the tablespace header for this tablespace.
@param[out] flushed_lsn the value of FIL_PAGE_FILE_FLUSH_LSN
@return DB_SUCCESS or error code */
dberr_t read_lsn_and_check_flags(lsn_t* flushed_lsn);
/**
@return true if the last file size is valid. */
bool is_valid_size() const
{
return(m_last_file_size_max >= last_file_size());
}
/**
@return true if configured to use raw devices */
bool has_raw_device();
/** Note that the data file was not found.
@param[in] file data file object
@param[out] create_new_db true if a new instance to be created
@return DB_SUCESS or error code */
dberr_t file_not_found(Datafile& file, bool* create_new_db);
/** Note that the data file was found.
@param[in,out] file data file object
@return true if a new instance to be created */
bool file_found(Datafile& file);
/** Create a data file.
@param[in,out] file data file object
@return DB_SUCCESS or error code */
dberr_t create(Datafile& file);
/** Create a data file.
@param[in,out] file data file object
@return DB_SUCCESS or error code */
dberr_t create_file(Datafile& file);
/** Open a data file.
@param[in,out] file data file object
@return DB_SUCCESS or error code */
dberr_t open_file(Datafile& file);
/** Set the size of the file.
@param[in,out] file data file object
@return DB_SUCCESS or error code */
dberr_t set_size(Datafile& file);
/** Convert a numeric string that optionally ends in G or M, to a
number containing megabytes.
@param[in] ptr string with a quantity in bytes
@param[out] megs the number in megabytes
@return next character in string */
static char* parse_units(char* ptr, ulint* megs);
private:
enum file_status_t {
FILE_STATUS_VOID = 0, /** status not set */
FILE_STATUS_RW_PERMISSION_ERROR,/** permission error */
FILE_STATUS_READ_WRITE_ERROR, /** not readable/writable */
FILE_STATUS_NOT_REGULAR_FILE_ERROR /** not a regular file */
};
/** Verify the size of the physical file
@param[in] file data file object
@return DB_SUCCESS if OK else error code. */
dberr_t check_size(Datafile& file);
/** Check if a file can be opened in the correct mode.
@param[in,out] file data file object
@param[out] reason exact reason if file_status check failed.
@return DB_SUCCESS or error code. */
dberr_t check_file_status(
const Datafile& file,
file_status_t& reason);
/* DATA MEMBERS */
/** if true, then we auto-extend the last data file */
bool m_auto_extend_last_file;
/** if != 0, this tells the max size auto-extending may increase the
last data file size */
ulint m_last_file_size_max;
/** If the following is true we do not allow
inserts etc. This protects the user from forgetting
the 'newraw' keyword to my.cnf */
bool m_created_new_raw;
/** Tablespace full status */
bool m_is_tablespace_full;
/** if false, then sanity checks are still pending */
bool m_sanity_checks_done;
};
/* GLOBAL OBJECTS */
/** The control info of the system tablespace. */
extern SysTablespace srv_sys_space;
/** The control info of a temporary table shared tablespace. */
extern SysTablespace srv_tmp_space;
/** Check if the space_id is for a system-tablespace (shared + temp).
@param[in] id Space ID to check
@return true if id is a system tablespace, false if not. */
UNIV_INLINE
bool
is_system_tablespace(ulint id)
{
return(id == TRX_SYS_SPACE || id == SRV_TMP_SPACE_ID);
}
/** Check if predefined shared tablespace.
@return true if predefined shared tablespace */
UNIV_INLINE
bool
is_predefined_tablespace(
ulint id)
{
ut_ad(srv_sys_space.space_id() == TRX_SYS_SPACE);
ut_ad(TRX_SYS_SPACE == 0);
return(id == TRX_SYS_SPACE
|| id == SRV_TMP_SPACE_ID
|| srv_is_undo_tablespace(id));
}
#endif /* fsp0sysspace_h */