diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index c7daf2fa3c23..b5591a71202e 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -345,6 +345,7 @@ SET(INNOBASE_SOURCES srv/srv0conc.cc srv/srv0mon.cc srv/srv0srv.cc + srv/srv0space.cc srv/srv0start.cc sync/sync0arr.cc sync/sync0rw.cc diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 0a880ecc7c2c..07ae75995e10 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -44,6 +44,7 @@ Created 1/8/1996 Heikki Tuuri #include "ut0vec.h" #include "dict0priv.h" #include "fts0priv.h" +#include "srv0space.h" /*****************************************************************//** Based on a table object, this function builds the entry to be inserted @@ -325,7 +326,7 @@ dict_build_table_def_step( /* All non-compressed temporary tables are stored in shared temp-tablespace */ if (dict_table_is_temporary(table)) { - table->space = srv_temp_tablespace.m_temp_tablespace_id; + table->space = srv_tmp_space.space_id(); } } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index b84729586b71..09a5d89c5afe 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -54,6 +54,7 @@ Created 10/25/1995 Heikki Tuuri # include "srv0srv.h" static ulint srv_data_read, srv_data_written; #endif /* !UNIV_HOTBACKUP */ +#include "srv0space.h" /* IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE @@ -1930,38 +1931,25 @@ fil_write_flushed_lsn_to_data_files( } /*******************************************************************//** -Reads the flushed lsn, arch no, and tablespace flag fields from a data +Reads the flushed lsn and tablespace flag fields from a data file at database startup. */ UNIV_INTERN void fil_read_first_page( /*================*/ os_file_t data_file, /*!< in: open data file */ - ibool one_read_already, /*!< in: TRUE if min and max - parameters below already - contain sensible data */ ulint* flags, /*!< out: tablespace flags */ ulint* space_id, /*!< out: tablespace ID */ -#ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< out: min of archived - log numbers in data files */ - ulint* max_arch_log_no, /*!< out: max of archived - log numbers in data files */ -#endif /* UNIV_LOG_ARCHIVE */ lsn_t* min_flushed_lsn, /*!< out: min of flushed lsn values in data files */ lsn_t* max_flushed_lsn) /*!< out: max of flushed lsn values in data files */ { - byte* buf; - byte* page; - lsn_t flushed_lsn; - - buf = static_cast(ut_malloc(2 * UNIV_PAGE_SIZE)); + byte* buf = static_cast(ut_malloc(2 * UNIV_PAGE_SIZE)); /* Align the memory for a possible read from a raw device */ - page = static_cast(ut_align(buf, UNIV_PAGE_SIZE)); + byte* page = static_cast(ut_align(buf, UNIV_PAGE_SIZE)); os_file_read(data_file, page, 0, UNIV_PAGE_SIZE); @@ -1969,34 +1957,17 @@ fil_read_first_page( *space_id = fsp_header_get_space_id(page); - flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); + lsn_t flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); ut_free(buf); - if (!one_read_already) { - *min_flushed_lsn = flushed_lsn; - *max_flushed_lsn = flushed_lsn; -#ifdef UNIV_LOG_ARCHIVE - *min_arch_log_no = arch_log_no; - *max_arch_log_no = arch_log_no; -#endif /* UNIV_LOG_ARCHIVE */ - return; - } - if (*min_flushed_lsn > flushed_lsn) { *min_flushed_lsn = flushed_lsn; } + if (*max_flushed_lsn < flushed_lsn) { *max_flushed_lsn = flushed_lsn; } -#ifdef UNIV_LOG_ARCHIVE - if (*min_arch_log_no > arch_log_no) { - *min_arch_log_no = arch_log_no; - } - if (*max_arch_log_no < arch_log_no) { - *max_arch_log_no = arch_log_no; - } -#endif /* UNIV_LOG_ARCHIVE */ } /*================ SINGLE-TABLE TABLESPACES ==========================*/ @@ -3636,11 +3607,7 @@ fil_open_single_table_tablespace( /* Read the first page of the datadir tablespace, if found. */ if (def.success) { fil_read_first_page( - def.file, FALSE, &def.flags, &def.id, -#ifdef UNIV_LOG_ARCHIVE - &space_arch_log_no, &space_arch_log_no, -#endif /* UNIV_LOG_ARCHIVE */ - &def.lsn, &def.lsn); + def.file, &def.flags, &def.id, &def.lsn, &def.lsn); /* Validate this single-table-tablespace with SYS_TABLES, but do not compare the DATA_DIR flag, in case the @@ -3660,16 +3627,15 @@ fil_open_single_table_tablespace( /* Read the first page of the remote tablespace */ if (remote.success) { fil_read_first_page( - remote.file, FALSE, &remote.flags, &remote.id, -#ifdef UNIV_LOG_ARCHIVE - &remote.arch_log_no, &remote.arch_log_no, -#endif /* UNIV_LOG_ARCHIVE */ + remote.file, &remote.flags, &remote.id, &remote.lsn, &remote.lsn); /* Validate this single-table-tablespace with SYS_TABLES, but do not compare the DATA_DIR flag, in case the tablespace was relocated. */ - ulint mod_remote_flags = remote.flags & ~FSP_FLAGS_MASK_DATA_DIR; + ulint mod_remote_flags = + remote.flags & ~FSP_FLAGS_MASK_DATA_DIR; + if (remote.id == id && mod_remote_flags == mod_flags) { valid_tablespaces_found++; remote.valid = TRUE; @@ -3685,11 +3651,7 @@ fil_open_single_table_tablespace( /* Read the first page of the datadir tablespace, if found. */ if (dict.success) { fil_read_first_page( - dict.file, FALSE, &dict.flags, &dict.id, -#ifdef UNIV_LOG_ARCHIVE - &dict.arch_log_no, &dict.arch_log_no, -#endif /* UNIV_LOG_ARCHIVE */ - &dict.lsn, &dict.lsn); + dict.file, &dict.flags, &dict.id, &dict.lsn, &dict.lsn); /* Validate this single-table-tablespace with SYS_TABLES, but do not compare the DATA_DIR flag, in case the @@ -3914,11 +3876,7 @@ fil_validate_single_table_tablespace( fsp_open_info* fsp) /*!< in/out: tablespace info */ { fil_read_first_page( - fsp->file, FALSE, &fsp->flags, &fsp->id, -#ifdef UNIV_LOG_ARCHIVE - &fsp->arch_log_no, &fsp->arch_log_no, -#endif /* UNIV_LOG_ARCHIVE */ - &fsp->lsn, &fsp->lsn); + fsp->file, &fsp->flags, &fsp->id, &fsp->lsn, &fsp->lsn); if (fsp->id == ULINT_UNDEFINED || fsp->id == 0) { fprintf(stderr, @@ -4841,14 +4799,14 @@ fil_extend_space_to_desired_size( *actual_size = space->size; #ifndef UNIV_HOTBACKUP - if (space_id == 0) { + if (space_id == TRX_SYS_SPACE) { ulint pages_per_mb = (1024 * 1024) / page_size; /* Keep the last data file size info up to date, rounded to full megabytes */ - srv_data_file_sizes[srv_n_data_files - 1] - = (node->size / pages_per_mb) * pages_per_mb; + srv_sys_space.set_last_file_size( + (node->size / pages_per_mb) * pages_per_mb); } #endif /* !UNIV_HOTBACKUP */ @@ -5649,13 +5607,12 @@ fil_validate(void) fil_space_t* space; fil_node_t* fil_node; ulint n_open = 0; - ulint i; mutex_enter(&fil_system->mutex); /* Look for spaces in the hash table */ - for (i = 0; i < hash_get_n_cells(fil_system->spaces); i++) { + for (ulint i = 0; i < hash_get_n_cells(fil_system->spaces); i++) { for (space = static_cast( HASH_GET_FIRST(fil_system->spaces, i)); diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 50952e235355..ff2a36d432ff 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -48,7 +48,7 @@ Created 11/29/1995 Heikki Tuuri # include "log0log.h" #endif /* UNIV_HOTBACKUP */ #include "dict0mem.h" -#include "srv0start.h" +#include "srv0space.h" #ifndef UNIV_HOTBACKUP @@ -943,7 +943,7 @@ fsp_try_extend_data_file( *actual_increase = 0; - if (space == 0 && !srv_auto_extend_last_data_file) { + if (space == 0 && !srv_sys_space.can_auto_extend_last_file()) { /* We print the error message only once to avoid spamming the error log. Note that we don't need @@ -967,27 +967,10 @@ fsp_try_extend_data_file( old_size = size; - if (space == 0) { - if (!srv_last_file_size_max) { - size_increase = SRV_AUTO_EXTEND_INCREMENT; - } else { - if (srv_last_file_size_max - < srv_data_file_sizes[srv_n_data_files - 1]) { + if (space == TRX_SYS_SPACE) { - fprintf(stderr, - "InnoDB: Error: Last data file size" - " is %lu, max size allowed %lu\n", - (ulong) srv_data_file_sizes[ - srv_n_data_files - 1], - (ulong) srv_last_file_size_max); - } + size_increase = srv_sys_space.get_increment(); - size_increase = srv_last_file_size_max - - srv_data_file_sizes[srv_n_data_files - 1]; - if (size_increase > SRV_AUTO_EXTEND_INCREMENT) { - size_increase = SRV_AUTO_EXTEND_INCREMENT; - } - } } else { /* We extend single-table tablespaces first one extent at a time, but 4 at a time for bigger tablespaces. It is @@ -1108,7 +1091,8 @@ fsp_fill_free_list( ut_a(zip_size <= UNIV_ZIP_SIZE_MAX); ut_a(!zip_size || zip_size >= UNIV_ZIP_SIZE_MIN); - if (space == 0 && srv_auto_extend_last_data_file + if (space == TRX_SYS_SPACE + && srv_sys_space.can_auto_extend_last_file() && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) { /* Try to increase the last data file size */ @@ -1116,7 +1100,8 @@ fsp_fill_free_list( size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); } - if (space != 0 && !init_space + if (space != 0 + && !init_space && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) { /* Try to increase the .ibd file size */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7c0cd5e895ae..d0b098be2707 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -52,8 +52,9 @@ this program; if not, write to the Free Software Foundation, Inc., #include "btr0sea.h" #include "os0file.h" #include "os0thread.h" -#include "srv0start.h" #include "srv0srv.h" +#include "srv0start.h" +#include "srv0space.h" #include "trx0roll.h" #include "trx0trx.h" @@ -187,9 +188,6 @@ static my_bool innobase_stats_on_metadata = TRUE; static my_bool innobase_large_prefix = FALSE; static my_bool innodb_optimize_fulltext_only = FALSE; -static char* internal_innobase_data_file_path = NULL; -static char* internal_innobase_temp_data_file_path = NULL; - static char* innodb_version_str = (char*) INNODB_VERSION_STR; static char* fts_server_stopword_table = NULL; @@ -2804,6 +2802,21 @@ ha_innobase::init_table_handle_for_HANDLER(void) reset_template(); } +/*********************************************************************//** +Free any resources that were allocated and return failure. */ +static +int +innobase_init_abort() +/*=================*/ +{ + DBUG_ENTER("innobase_init_abort"); + + srv_sys_space.shutdown(); + srv_tmp_space.shutdown(); + + DBUG_RETURN(1); +} + /*********************************************************************//** Opens an InnoDB database. @return 0 on success, error code on failure */ @@ -2815,7 +2828,6 @@ innobase_init( { static char current_dir[3]; /*!< Set if using current lib */ int err; - bool ret; char *default_path; uint format_id; ulong num_pll_degree; @@ -2874,8 +2886,7 @@ innobase_init( test_filename)) { sql_print_error("tablename encoding has been changed"); - - goto error; + DBUG_RETURN(innobase_init_abort()); } #endif /* DBUG_OFF */ @@ -2886,7 +2897,7 @@ innobase_init( "innobase_buffer_pool_size can't be over 4GB" " on 32-bit systems"); - goto error; + DBUG_RETURN(innobase_init_abort()); } } @@ -2914,68 +2925,40 @@ innobase_init( /* Set InnoDB initialization parameters according to the values read from MySQL .cnf file */ - /*--------------- Data files -------------------------*/ - /* The default dir for data files is the datadir of MySQL */ - srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir : - default_path); + srv_data_home = innobase_data_home_dir + ? innobase_data_home_dir : default_path; - /* Set default InnoDB data file size to 12 MB and let it be - auto-extending. Thus users can use InnoDB in >= 4.0 without having - to specify any startup options. */ + /*--------------- Shared tablespaces -------------------------*/ - if (!innobase_data_file_path) { - innobase_data_file_path = (char*) "ibdata1:12M:autoextend"; - } - - /* Since InnoDB edits the argument in the next call, we make another - copy of it: */ - internal_innobase_data_file_path = my_strdup(innobase_data_file_path, - MYF(MY_FAE)); + /* Set default InnoDB temp data file size to 12 MB and let it be + auto-extending. */ + if (!innobase_data_file_path) { + innobase_data_file_path = (char*) "ibdata1:12M:autoextend"; + } - ret = (bool) srv_parse_data_file_paths_and_sizes( - internal_innobase_data_file_path); - if (ret == FALSE) { - sql_print_error( - "InnoDB: syntax error in innodb_data_file_path"); -mem_free_and_error: - srv_free_paths_and_sizes(); - if (internal_innobase_data_file_path) { - my_free(internal_innobase_data_file_path); - } - goto mem_free_and_error2; - } + srv_sys_space.set_space_id(TRX_SYS_SPACE); - /*--------------- Temp Data files -------------------------*/ + /* Supports raw devices */ + if (!srv_sys_space.parse(innobase_data_file_path, true)) { + DBUG_RETURN(innobase_init_abort()); + } /* Set default InnoDB temp data file size to 12 MB and let it be auto-extending. */ if (!innobase_temp_data_file_path) { - innobase_temp_data_file_path = - (char*) "ibdatatmp1:12M:autoextend"; + innobase_temp_data_file_path = (char*) "ibtmp:12M:autoextend"; } - /* Since InnoDB edits the argument in the next call, we make another - copy of it: */ - - internal_innobase_temp_data_file_path = my_strdup( - innobase_temp_data_file_path, MYF(MY_FAE)); + /* We set the temporary tablspace id later, after recovery. */ - ret = srv_temp_tablespace.init_params( - internal_innobase_temp_data_file_path); - if (ret == false) { - sql_print_error( - "InnoDB: syntax error in innodb_temp_data_file_path"); -mem_free_and_error2: - srv_free_paths_and_sizes(); - if (internal_innobase_temp_data_file_path) { - my_free(internal_innobase_temp_data_file_path); - } - goto error; - } + /* Doesn't support raw devices. */ + if (!srv_tmp_space.parse(innobase_temp_data_file_path, false)) { + DBUG_RETURN(innobase_init_abort()); + } /* -------------- All log files ---------------------------*/ @@ -3002,7 +2985,7 @@ innobase_init( sql_print_error("syntax error in innodb_log_group_home_dir, " "or a wrong number of mirrored log groups"); - goto mem_free_and_error; + DBUG_RETURN(innobase_init_abort()); } /* Validate the file format by animal name */ @@ -3015,7 +2998,7 @@ innobase_init( sql_print_error("InnoDB: wrong innodb_file_format."); - goto mem_free_and_error; + DBUG_RETURN(innobase_init_abort()); } } else { /* Set it to the default file format id. Though this @@ -3058,7 +3041,7 @@ innobase_init( trx_sys_file_format_id_to_name( UNIV_FORMAT_MAX)); - goto mem_free_and_error; + DBUG_RETURN(innobase_init_abort()); } /* Remember stopword table name supplied at startup */ @@ -3084,7 +3067,7 @@ innobase_init( sql_print_error("InnoDB: invalid value " "innodb_change_buffering=%s", innobase_change_buffering); - goto mem_free_and_error; + DBUG_RETURN(innobase_init_abort()); } innobase_change_buffering_inited_ok: @@ -3144,13 +3127,13 @@ innobase_init( if (!srv_page_size_shift) { sql_print_error("InnoDB: Invalid page size=%lu.\n", srv_page_size); - goto mem_free_and_error; + DBUG_RETURN(innobase_init_abort()); } + if (UNIV_PAGE_SIZE_DEF != srv_page_size) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: innodb-page-size has been changed" - " from the default value %d to %lu.\n", + ib_logf(IB_LOG_LEVEL_WARN, + "innodb-page-size has been changed " + "from the default value %d to %lu.", UNIV_PAGE_SIZE_DEF, srv_page_size); } @@ -3164,8 +3147,9 @@ innobase_init( = (long) (innobase_buffer_pool_size / (128 * 1024 * 1024)); } -#endif -} +#endif /* _WIN32 */ + } + srv_buf_pool_size = (ulint) innobase_buffer_pool_size; srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances; @@ -3174,24 +3158,20 @@ innobase_init( if (innobase_additional_mem_pool_size != 8*1024*1024L /* the default */ ) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: Using " - "innodb_additional_mem_pool_size is DEPRECATED. " + ib_logf(IB_LOG_LEVEL_WARN, + "Using innodb_additional_mem_pool_size is DEPRECATED. " "This option may be removed in future releases, " "together with the option innodb_use_sys_malloc " "and with the InnoDB's internal memory " - "allocator.\n"); + "allocator."); } if (!srv_use_sys_malloc ) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: Setting " - "innodb_use_sys_malloc to FALSE is DEPRECATED. " + ib_logf(IB_LOG_LEVEL_WARN, + "Setting innodb_use_sys_malloc to FALSE is DEPRECATED. " "This option may be removed in future releases, " "together with the InnoDB's internal memory " - "allocator.\n"); + "allocator."); } srv_n_file_io_threads = (ulint) innobase_file_io_threads; @@ -3205,13 +3185,11 @@ innobase_init( ? true : false; if (!innobase_use_checksums) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: Setting " - "innodb_checksums to OFF is DEPRECATED. " + ib_logf(IB_LOG_LEVEL_WARN, + "Setting innodb_checksums to OFF is DEPRECATED. " "This option may be removed in future releases. " "You should set innodb_checksum_algorithm=NONE " - "instead.\n"); + "instead."); srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_NONE; } @@ -3225,13 +3203,11 @@ innobase_init( srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog; if (innobase_locks_unsafe_for_binlog) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: Using " - "innodb_locks_unsafe_for_binlog is DEPRECATED. " + ib_logf(IB_LOG_LEVEL_WARN, + "Using innodb_locks_unsafe_for_binlog is DEPRECATED. " "This option may be removed in future releases. " "Please use READ COMMITTED transaction isolation " - "level instead, see " REFMAN "set-transaction.html.\n"); + "level instead, see " REFMAN "set-transaction.html."); } if (innobase_open_files < 10) { @@ -3314,7 +3290,7 @@ innobase_init( err = innobase_start_or_create_for_mysql(); if (err != DB_SUCCESS) { - goto mem_free_and_error; + DBUG_RETURN(innobase_init_abort()); } /* Adjust the innodb_undo_logs config object */ @@ -3361,9 +3337,7 @@ innobase_init( /* Turn on monitor counters that are default on */ srv_mon_default_on(); - DBUG_RETURN(FALSE); -error: - DBUG_RETURN(TRUE); + DBUG_RETURN(0); } /*******************************************************************//** @@ -3389,11 +3363,14 @@ innobase_end( innodb_inited = 0; hash_table_free(innobase_open_tables); innobase_open_tables = NULL; + if (innobase_shutdown_for_mysql() != DB_SUCCESS) { err = 1; } - srv_free_paths_and_sizes(); - my_free(internal_innobase_data_file_path); + + srv_sys_space.shutdown(); + srv_tmp_space.shutdown(); + mysql_mutex_destroy(&innobase_share_mutex); mysql_mutex_destroy(&commit_threads_m); mysql_mutex_destroy(&commit_cond_m); @@ -9783,8 +9760,11 @@ ha_innobase::discard_or_import_tablespace( dict_table = prebuilt->table; - if (dict_table->space == TRX_SYS_SPACE - || dict_table->space == srv_temp_tablespace.m_temp_tablespace_id) { + if (dict_table->space == srv_sys_space.space_id() + || dict_table->space == srv_tmp_space.space_id()) { + + // FIXME: This error code has to change. It should now be + // ER_TABLE_IN_SHARED_TABLESPACE ib_senderrf( prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR, ER_TABLE_IN_SYSTEM_TABLESPACE, @@ -15719,7 +15699,8 @@ static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_ "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.", NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024); -static MYSQL_SYSVAR_ULONG(autoextend_increment, srv_auto_extend_increment, +static MYSQL_SYSVAR_ULONG(autoextend_increment, + srv_sys_space.m_auto_extend_increment, PLUGIN_VAR_RQCMDARG, "Data file autoextend increment in megabytes", NULL, NULL, 64L, 1L, 1000L, 0); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 0aa65f029494..6bfa3f4b46c5 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -38,7 +38,7 @@ Smart ALTER TABLE #include "rem0types.h" #include "row0log.h" #include "row0merge.h" -#include "srv0srv.h" +#include "srv0space.h" #include "trx0trx.h" #include "trx0roll.h" #include "ha_prototypes.h" @@ -266,7 +266,7 @@ ha_innobase::check_if_supported_inplace_alter( if (srv_read_only_mode) { DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); - } else if (srv_created_new_raw || srv_force_recovery) { + } else if (srv_sys_space.created_new_raw() || srv_force_recovery) { DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 56fda8b39b14..7660f41b5b53 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -359,24 +359,15 @@ fil_write_flushed_lsn_to_data_files( lsn_t lsn, /*!< in: lsn to write */ ulint arch_log_no); /*!< in: latest archived log file number */ /*******************************************************************//** -Reads the flushed lsn, arch no, and tablespace flag fields from a data +Reads the flushed lsn and tablespace flag fields from a data file at database startup. */ UNIV_INTERN void fil_read_first_page( /*================*/ os_file_t data_file, /*!< in: open data file */ - ibool one_read_already, /*!< in: TRUE if min and max - parameters below already - contain sensible data */ ulint* flags, /*!< out: tablespace flags */ ulint* space_id, /*!< out: tablespace ID */ -#ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< out: min of archived - log numbers in data files */ - ulint* max_arch_log_no, /*!< out: max of archived - log numbers in data files */ -#endif /* UNIV_LOG_ARCHIVE */ lsn_t* min_flushed_lsn, /*!< out: min of flushed lsn values in data files */ lsn_t* max_flushed_lsn); /*!< out: max of flushed diff --git a/storage/innobase/include/srv0space.h b/storage/innobase/include/srv0space.h new file mode 100644 index 000000000000..86fd0e864e06 --- /dev/null +++ b/storage/innobase/include/srv0space.h @@ -0,0 +1,450 @@ +/***************************************************************************** + +Copyright (c) 2012, 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/srv0space.h +Multi file shared tablespace implementation. + +Created 2012-11-16 by Sunny Bains. +*******************************************************/ + +#ifndef srv0space_h +#define srv0space_h + +#include "srv0srv.h" +#include "os0file.h" + +/** Data structure that contains the information about shared tablespaces. +Currently this can be the system tablespace or a temporary table tablespace */ +class Tablespace { + + /** Types of raw partitions in innodb_data_file_path */ + enum device_t { + SRV_NOT_RAW = 0, /*!< Not a raw partition */ + SRV_NEW_RAW, /*!< A 'newraw' partition, only to be + initialized */ + SRV_OLD_RAW /*!< An initialized raw partition */ + }; + + struct file_t { + + file_t(const char* name, ulint size) + : + m_name(strdup(name)), + m_size(size), + m_type(SRV_NOT_RAW), + m_handle(~0), + m_exists(), + m_open_flags(OS_FILE_OPEN) + { + /* No op */ + } + + ~file_t() + { + shutdown(); + } + + file_t(const file_t& file) + : + m_name(strdup(file.m_name)), + m_size(file.m_size), + m_type(file.m_type), + m_handle(file.m_handle), + m_exists(file.m_exists), + m_open_flags(file.m_open_flags) + { + /* No op */ + } + + file_t& operator=(const file_t& file) + { + m_name = strdup(file.m_name); + m_size = file.m_size; + m_type = file.m_type; + m_handle = file.m_handle; + m_exists = file.m_exists; + m_open_flags = file.m_open_flags; + + return(*this); + } + + void shutdown() + { + ut_a(m_handle == ~0); + + if (m_name != 0) { + ::free(m_name); + m_name = 0; + } + } + + /** Temp data files names */ + char* m_name; + + /** size in database pages */ + ulint m_size; + + /** The type of the data file */ + device_t m_type; + + /** Open file handle */ + os_file_t m_handle; + + /** true if file already existed on startup */ + bool m_exists; + + /** Flags to use for opening the data file */ + os_file_create_t m_open_flags; + }; + + typedef std::vector files_t; + +public: + Tablespace() + : + m_space_id(ULINT_UNDEFINED), + m_files(), + m_auto_extend_last_file(), + m_last_file_size_max(), + m_created_new_raw(), + m_auto_extend_increment() + { + } + + ~Tablespace() + { + shutdown(); + ut_ad(m_files.empty()); + ut_ad(m_space_id == ULINT_UNDEFINED); + } + + void set_space_id(ulint space_id) + { + ut_a(m_space_id == ULINT_UNDEFINED); + m_space_id = space_id; + } + + /** + 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(const char* filepath, bool supports_raw); + + /** + Check the data file specification. + @param create_new_db - true if a new database is to be created + @return DB_SUCCESS if all OK else error code */ + dberr_t check_file_spec(ibool* create_new_db); + + /** + Free the memory allocated by parse() */ + void shutdown(); + + /** Normalize the file size, convert to extents. */ + void normalize() + { + files_t::iterator end = m_files.end(); + + for (files_t::iterator it = m_files.begin(); it != end; ++it) { + + it->m_size *= (1024 * 1024) / UNIV_PAGE_SIZE; + } + + m_last_file_size_max *= (1024 * 1024) / UNIV_PAGE_SIZE; + } + + /* @return the space id of this tablespace. */ + ulint space_id() const + { + return(m_space_id); + } + + /** @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 size - the size to set */ + void set_last_file_size(ulint size) + { + ut_a(!m_files.empty()); + m_files.back().m_size = size; + } + + /** + @return ULINT_UNDEFINED if the size is invalid else the sum of sizes */ + ulint get_sum_of_sizes() const; + + /** @return next increment size */ + ulint get_increment() const + { + ulint increment; + + if (m_last_file_size_max == 0) { + increment = get_autoextend_increment(); + } else { + if (!is_valid_size()) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Last data file size is %lu, max " + "size allowed %lu", + last_file_size(), + m_last_file_size_max); + } + + increment = m_last_file_size_max - last_file_size(); + } + + if (increment > get_autoextend_increment()) { + increment = get_autoextend_increment(); + } + + return(increment); + } + + /** + Open or create the data files. + + @param create_new_db - true if new database should be + @param min_flushed_lsn - min of flushed LSN + @param max_flushed_lsn - max of flushed LSN + @param sum_of_new_sizes - sum of sizes of new files added + @return DB_SUCCESS or error code */ + dberr_t open(ulint* sum_of_new_sizes); + + /** + Read the flush lsn values and check the header flags. + + @param file - file control information + @param name - physical filename + @param min_flushed_lsn - min of flushed lsn values in data files + @param max_flushed_lsn - max of flushed lsn values in data files + @return DB_SUCCESS if all OK */ + dberr_t read_lsn_and_check_flags( + lsn_t* min_flushed_lsn, + lsn_t* max_flushed_lsn); + +private: + /** @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 true if the last file size is valid. */ + bool is_valid_size() const + { + return(m_last_file_size_max >= last_file_size()); + } + + /** @return the autoextend increment in pages. */ + ulint get_autoextend_increment() const + { + return(m_auto_extend_increment + * ((1024 * 1024) / UNIV_PAGE_SIZE)); + } + + bool is_raw_device(const file_t& file) const + { + return(file.m_type != SRV_NOT_RAW); + } + + /** @return true if configured to use raw devices */ + bool has_raw_device() const + { + files_t::const_iterator end = m_files.end(); + + for (files_t::const_iterator it = m_files.begin(); + it != end; + ++it) { + + if (is_raw_device(*it)) { + return(true); + } + } + + return(false); + } + + /** @return true if the filename exists in the data files */ + bool find(const char* filename) const + { + files_t::const_iterator end = m_files.end(); + + for (files_t::const_iterator it = m_files.begin(); + it != end; + ++it) { + + if (innobase_strcasecmp(filename, it->m_name) == 0) { + return(true); + } + } + + return(false); + } + + /** + Note that the data file was not found. + @return DB_SUCESS or error code */ + dberr_t file_not_found(file_t& file, ulint i, ibool* create_new_db); + + /** + Note that the data file was found. */ + void file_found(file_t& file, ulint i); + + /** + Create a data file. + @param file - control info of file to be created. + @param name - physical filename + @return DB_SUCCESS or error code */ + dberr_t create(file_t& file, const char* name); + + /** + Create a data file. + @param file - control info of file to be created. + @param name - physical filename on FS + @return DB_SUCCESS or error code */ + dberr_t create_file(file_t& file, const char* name); + + /** + Set the size of the file. + @param file - data file spec + @param name - physical file name + @return DB_SUCCESS or error code */ + dberr_t set_size(file_t& file, const char* name); + + /** + Open a data file. + @param file - data file spec + @param name - physical file name + @return DB_SUCCESS or error code */ + dberr_t open_file(file_t& file, const char* name); + + /** + Open/create a data file. + @param file - data file spec + @param name - physical file name + @return DB_SUCCESS or error code */ + dberr_t open_data_file(file_t& file, const char* name); + + /** + Check if a file can be opened in the correct mode. + @param file - file control information + @return DB_SUCCESS or error code. */ + dberr_t check_file_status(const file_t& file) const; + + /** + Verify the size of the physical file + @param file - file control info + @param name - physical filename on FS + @return DB_SUCCESS if OK else error code. */ + dberr_t check_size(file_t& file, const char* name); + + /** + Make physical filename from control info. + @param name - destination buffer + @param size - max size of name + @param file - control information */ + void make_name(const file_t& file, char* name, ulint size) const; + + /** + Convert a numeric string that optionally ends in G or M, to a number + containing megabytes. + @param str - string with a quantity in bytes + @param megs - out the number in megabytes + @return next character in string */ + static char* parse_units( + char* ptr, + ulint* megs) + { + char* endp; + + *megs = strtoul(ptr, &endp, 10); + + ptr = endp; + + switch (*ptr) { + case 'G': case 'g': + *megs *= 1024; + /* fall through */ + case 'M': case 'm': + ++ptr; + break; + default: + *megs /= 1024 * 1024; + break; + } + + return(ptr); + } + + /** Check if two shared tablespaces have common data file names. + @param space1 - space to check + @param space2 - space to check + @return true if they have the same data filenames and paths */ + static bool intersection( + const Tablespace& space1, + const Tablespace& space2); + + // Disable copying + Tablespace(const Tablespace&); + Tablespace& operator=(const Tablespace&); + + /** This is dynamically allocated on each start of server. */ + ulint m_space_id; + + /** Data file information */ + files_t m_files; + + /** 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; + +public: + /* We have to make this public because it is a config variable. */ + + /** If the last data file is auto-extended, we add this + many pages to it at a time */ + ulong m_auto_extend_increment; +}; + +/** The control info of the system tablespace. */ +extern Tablespace srv_sys_space; + +/** The control info of a temporary table shared tablespace. */ +extern Tablespace srv_tmp_space; +#endif /* srv0space_h */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index f548b2a883ea..63f88cc424cd 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -52,6 +52,8 @@ Created 10/10/1995 Heikki Tuuri #include "buf0checksum.h" #include "ut0counter.h" +#include + /* Global counters used inside InnoDB. */ struct srv_stats_t { typedef ib_counter_t lsn_ctr_1_t; @@ -127,97 +129,6 @@ struct srv_stats_t { ulint_ctr_64_t n_rows_inserted; }; -struct srv_temp_tablespace_t { - -public: - srv_temp_tablespace_t() : - m_temp_tablespace_id(0), - m_n_temp_data_files(0), - m_temp_data_file_names(NULL), - m_temp_data_file_sizes(NULL), - m_auto_extend_last_temp_data_file(false), - m_last_temp_data_file_size_max(0), - m_temp_data_auto_extend_increment(8), - m_temp_data_file_raw_type(NULL), - m_temp_data_created_new_raw(false) { - } - - /** - Parse the input params and populate member variables. - @return true on successfull parse else false*/ - bool init_params( - char* str); /*!< in: parse and obtain init value */ - -protected: - srv_temp_tablespace_t(const srv_temp_tablespace_t& rSource); - srv_temp_tablespace_t& operator=( - const srv_temp_tablespace_t& rSource); - -private: - /** - Convert a numeric string that optionally ends in G or M, to a number - containing megabytes. - @return next character in string */ - char* parse_megabytes( - char* str, /*!< in: string with a quantity in bytes */ - ulint* megs) /*!< out: the number in megabytes */ - { - char* endp; - ulint size; - - size = strtoul(str, &endp, 10); - - str = endp; - - switch (*str) { - case 'G': case 'g': - size *= 1024; - /* fall through */ - case 'M': case 'm': - str++; - break; - default: - size /= 1024 * 1024; - break; - } - - *megs = size; - return(str); - } - -public: - /** This is dynamically allocated on each start of server. */ - ulint m_temp_tablespace_id; - - /** Number of temp data files specified by user that together - creates temp tablespace */ - ulint m_n_temp_data_files; - - /** Temp data files names */ - char** m_temp_data_file_names; - - /** size in database pages */ - ulint* m_temp_data_file_sizes; - - /** if TRUE, then we auto-extend the last data file */ - bool m_auto_extend_last_temp_data_file; - - /** if != 0, this tells the max size auto-extending may increase the - last data file size */ - ulint m_last_temp_data_file_size_max; - - /** If the last data file is auto-extended, we add this - many pages to it at a time */ - ulong m_temp_data_auto_extend_increment; - - /** Capture raw type for each file/partition. */ - ulint* m_temp_data_file_raw_type; - - /** 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_temp_data_created_new_raw; -}; - extern const char* srv_main_thread_op_info; /** Prefix used by MySQL to indicate pre-5.1 table name encoding */ @@ -246,8 +157,7 @@ extern char srv_disable_sort_file_cache; /* If the last data file is auto-extended, we add this many pages to it at a time */ -#define SRV_AUTO_EXTEND_INCREMENT \ - (srv_auto_extend_increment * ((1024 * 1024) / UNIV_PAGE_SIZE)) +#define SRV_AUTO_EXTEND_INCREMENT (srv_sys_space.get_autoextend_increment()) /* Mutex for locking srv_monitor_file. Not created if srv_read_only_mode */ extern ib_mutex_t srv_monitor_file_mutex; @@ -325,23 +235,9 @@ extern ulint srv_undo_tablespaces_open; /* The number of undo segments to use */ extern ulong srv_undo_logs; -extern ulint srv_n_data_files; -extern char** srv_data_file_names; -extern ulint* srv_data_file_sizes; -extern ulint* srv_data_file_is_raw_partition; - -extern ibool srv_auto_extend_last_data_file; -extern ulint srv_last_file_size_max; - -extern srv_temp_tablespace_t srv_temp_tablespace; - extern char* srv_log_group_home_dir; #ifndef UNIV_HOTBACKUP -extern ulong srv_auto_extend_increment; - -extern ibool srv_created_new_raw; - /** Maximum number of srv_n_log_files, or innodb_log_files_in_group */ #define SRV_N_LOG_FILES_MAX 100 extern ulong srv_n_log_files; @@ -568,14 +464,6 @@ do { \ #endif /* !UNIV_HOTBACKUP */ -/** Types of raw partitions in innodb_data_file_path */ -enum { - SRV_NOT_RAW = 0, /*!< Not a raw partition */ - SRV_NEW_RAW, /*!< A 'newraw' partition, only to be - initialized */ - SRV_OLD_RAW /*!< An initialized raw partition */ -}; - /** Alternatives for the file flush option in Unix; see the InnoDB manual about what these mean */ enum { diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h index 5f709bbd0cab..c20d27848097 100644 --- a/storage/innobase/include/srv0start.h +++ b/storage/innobase/include/srv0start.h @@ -44,15 +44,6 @@ srv_normalize_path_for_win( /*=======================*/ char* str); /*!< in/out: null-terminated character string */ /*********************************************************************//** -Reads the data files and their sizes from a character string given in -the .cnf file. -@return TRUE if ok, FALSE on parse error */ -UNIV_INTERN -ibool -srv_parse_data_file_paths_and_sizes( -/*================================*/ - char* str); /*!< in/out: the data file path string */ -/*********************************************************************//** Parse temporary tablespace configuration. @return true if ok, false on parse error */ UNIV_INTERN diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 3bc9b93f13dc..87ab1a1e900e 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -58,7 +58,7 @@ Created 9/17/2000 Heikki Tuuri #include "ibuf0ibuf.h" #include "fts0fts.h" #include "fts0types.h" -#include "srv0start.h" +#include "srv0space.h" #include "row0import.h" #include "m_string.h" #include "my_sys.h" @@ -1275,7 +1275,7 @@ row_insert_for_mysql( mem_analyze_corruption(prebuilt); ut_error; - } else if (srv_created_new_raw || srv_force_recovery) { + } else if (srv_sys_space.created_new_raw() || srv_force_recovery) { fputs("InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" @@ -1659,7 +1659,7 @@ row_update_for_mysql( ut_error; } - if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) { + if (srv_sys_space.created_new_raw() || srv_force_recovery) { fputs("InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" @@ -2142,7 +2142,7 @@ row_create_table_for_mysql( goto err_exit; ); - if (srv_created_new_raw) { + if (srv_sys_space.created_new_raw()) { fputs("InnoDB: A new raw disk partition was initialized:\n" "InnoDB: we do not allow database modifications" " by the user.\n" @@ -2251,7 +2251,7 @@ row_create_table_for_mysql( err = trx->error_state; if (table->space != TRX_SYS_SPACE - && table->space != srv_temp_tablespace.m_temp_tablespace_id) { + && table->space != srv_tmp_space.space_id()) { ut_a(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_USE_TABLESPACE)); /* Update SYS_TABLESPACES and SYS_DATAFILES if a new @@ -3215,7 +3215,7 @@ row_truncate_table_for_mysql( ut_ad(table); - if (srv_created_new_raw) { + if (srv_sys_space.created_new_raw()) { fputs("InnoDB: A new raw disk partition was initialized:\n" "InnoDB: we do not allow database modifications" " by the user.\n" @@ -3678,7 +3678,7 @@ row_drop_table_for_mysql( ut_a(name != NULL); - if (srv_created_new_raw) { + if (srv_sys_space.created_new_raw()) { fputs("InnoDB: A new raw disk partition was initialized:\n" "InnoDB: we do not allow database modifications" " by the user.\n" @@ -4194,7 +4194,7 @@ row_drop_table_for_mysql( if (err == DB_SUCCESS && space_id != TRX_SYS_SPACE - && space_id != srv_temp_tablespace.m_temp_tablespace_id) { + && space_id != srv_tmp_space.space_id()) { if (!is_temp && !fil_space_for_table_exists_in_mem( space_id, tablename, FALSE, @@ -4204,7 +4204,8 @@ row_drop_table_for_mysql( err = DB_SUCCESS; if (print_msg) { - char msg_tablename[MAX_FULL_NAME_LEN + 1]; + char msg_tablename[ + MAX_FULL_NAME_LEN + 1]; innobase_format_name( msg_tablename, sizeof(tablename), @@ -4674,7 +4675,7 @@ row_rename_table_for_mysql( ut_a(old_name != NULL); ut_a(new_name != NULL); - if (srv_created_new_raw || srv_force_recovery) { + if (srv_sys_space.created_new_raw() || srv_force_recovery) { fputs("InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" diff --git a/storage/innobase/srv/srv0space.cc b/storage/innobase/srv/srv0space.cc new file mode 100644 index 000000000000..359b296ba13e --- /dev/null +++ b/storage/innobase/srv/srv0space.cc @@ -0,0 +1,911 @@ +/***************************************************************************** + +Copyright (c) 2012, 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 srv/srv0space.cc +Multi file shared tablespace implementation. + +Created 2012-11-16 by Sunny Bains. +*******************************************************/ + +#include "srv0space.h" +#include "srv0start.h" +#include "fil0fil.h" +#include "fsp0fsp.h" + +/** The control info of the system tablespace. */ +UNIV_INTERN Tablespace srv_sys_space; + +/** The control info of a temporary table shared tablespace. */ +UNIV_INTERN Tablespace srv_tmp_space; + +// FIXME: Get rid of the name parameter, move to file_t + +/** +Parse the input params and populate member variables. +@param home_dir - MySQL data home directory +@param filepath - path to data files +@return true on success parse */ +UNIV_INTERN +bool +Tablespace::parse(const char* filepath, bool supports_raw) +{ + char* path; + ulint size; + char* input_str; + ulint n_files = 0; + + ut_ad(m_last_file_size_max == 0); + ut_ad(m_auto_extend_last_file == false); + + char* str = strdup(filepath); + + input_str = str; + + /*---------------------- PASS 1 ---------------------------*/ + /* First calculate the number of data files and check syntax: + path:size[M | G];path:size[M | G]... . Note that a Windows path may + contain a drive name and a ':'. */ + while (*str != '\0') { + path = str; + + while ((*str != ':' && *str != '\0') + || (*str == ':' + && (*(str + 1) == '\\' || *(str + 1) == '/' + || *(str + 1) == ':'))) { + str++; + } + + if (*str == '\0') { + ::free(str); + return(false); + } + + str++; + + str = parse_units(str, &size); + + if (0 == strncmp(str, ":autoextend", + (sizeof ":autoextend") - 1)) { + + str += (sizeof ":autoextend") - 1; + + if (0 == strncmp(str, ":max:", + (sizeof ":max:") - 1)) { + + str += (sizeof ":max:") - 1; + + str = parse_units(str, &size); + } + + if (*str != '\0') { + ::free(str); + return(false); + } + } + + if (strlen(str) >= 6 + && *str == 'n' + && *(str + 1) == 'e' + && *(str + 2) == 'w') { + + if (!supports_raw) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Tablespace doesn't support raw " + "devices"); + + ::free(str); + return(false); + } + + str += 3; + } + + if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { + str += 3; + + if (!supports_raw) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Tablespace doesn't support raw " + "devices"); + + ::free(str); + return(false); + } + } + + if (size == 0) { + ::free(str); + return(false); + } + + ++n_files; + + if (*str == ';') { + str++; + } else if (*str != '\0') { + ::free(str); + return(false); + } + } + + if (n_files == 0) { + /* file_path must contain at least one data file definition */ + ::free(str); + return(false); + } + + /*---------------------- PASS 2 ---------------------------*/ + /* Then store the actual values to our arrays */ + str = input_str; + + while (*str != '\0') { + path = str; + + /* Note that we must step over the ':' in a Windows path; + a Windows path normally looks like C:\ibdata\ibdata1:1G, but + a Windows raw partition may have a specification like + \\.\C::1Gnewraw or \\.\PHYSICALDRIVE2:1Gnewraw */ + + while ((*str != ':' && *str != '\0') + || (*str == ':' + && (*(str + 1) == '\\' || *(str + 1) == '/' + || *(str + 1) == ':'))) { + str++; + } + + if (*str == ':') { + /* Make path a null-terminated string */ + *str = '\0'; + str++; + } + + str = parse_units(str, &size); + + if (0 == strncmp(str, ":autoextend", + (sizeof ":autoextend") - 1)) { + + m_auto_extend_last_file = true; + + str += (sizeof ":autoextend") - 1; + + if (0 == strncmp(str, ":max:", + (sizeof ":max:") - 1)) { + + str += (sizeof ":max:") - 1; + + str = parse_units(str, &m_last_file_size_max); + } + + if (*str != '\0') { + ::free(str); + return(false); + } + } + + m_files.push_back(file_t(path, size)); + + if (strlen(str) >= 6 + && *str == 'n' + && *(str + 1) == 'e' + && *(str + 2) == 'w') { + + ut_a(supports_raw); + + str += 3; + + m_files.back().m_type = SRV_NEW_RAW; + } + + if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { + + ut_a(supports_raw); + + str += 3; + + if (m_files.back().m_type == SRV_NOT_RAW) { + m_files.back().m_type = SRV_OLD_RAW; + } + } + + if (*str == ';') { + ++str; + } + } + + ut_ad(n_files == m_files.size()); + + return(true); +} + +/** Check if two shared tablespaces have common data file names. +@param space1 - space to check +@param space2 - space to check +@return true if they have the same data filenames and paths */ +bool +Tablespace::intersection(const Tablespace& space1, const Tablespace& space2) +{ + // FIXME: This test may not be sufficient, if relative paths are + // used. I think we should do a stat and check the full path and + // do a better compare. + files_t::const_iterator end = space1.m_files.end(); + + for (files_t::const_iterator it = space1.m_files.begin(); + it != end; + ++it) { + + if (space2.find(it->m_name)) { + + return(true); + } + } + + return(false); +} + +/** +Frees the memory allocated by the parse method. */ +void +Tablespace::shutdown() +{ + files_t::iterator end = m_files.end(); + + for (files_t::iterator it = m_files.begin(); it != end; ++it) { + it->shutdown(); + } + + m_files.clear(); + + m_space_id = ULINT_UNDEFINED; + + m_created_new_raw = 0; + m_last_file_size_max = 0; + m_auto_extend_last_file = 0; + m_auto_extend_increment = 0; +} + +/** @return ULINT_UNDEFINED if the size is invalid else the sum of sizes */ +ulint +Tablespace::get_sum_of_sizes() const +{ + ulint sum = 0; + + files_t::const_iterator end = m_files.end(); + + for (files_t::const_iterator it = m_files.begin(); it != end; ++it) { + +#ifndef __WIN__ + if (sizeof(off_t) < 5 + && it->m_size >= (1UL << (32UL - UNIV_PAGE_SIZE_SHIFT))) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "File size must be < 4 GB " + "with this MySQL binary."); + + ib_logf(IB_LOG_LEVEL_ERROR, + "Operating system combination, in some " + "OS's < 2 GB"); + + return(ULINT_UNDEFINED); + } +#endif /* __WIN__ */ + sum += it->m_size; + } + + return(sum); +} + +/** +Create/open a data file. +@param file - control info of file to be created. +@param name - physical filename on FS +@return DB_SUCCESS or error code */ +dberr_t +Tablespace::open_data_file(file_t& file, const char* name) +{ + ibool success; + + file.m_handle = os_file_create( + innodb_file_data_key, name, file.m_open_flags, + OS_FILE_NORMAL, OS_DATA_FILE, &success); + + if (!success) { + + os_file_get_last_error(true); + + ib_logf(IB_LOG_LEVEL_ERROR, "Can't open \"%s\"", name); + + return(DB_ERROR); + } + + return(DB_SUCCESS); +} + +/** +Verify the size of the physical file. +@param file - control info of file to be created. +@param name - physical filename on FS +@return DB_SUCCESS if OK else error code. */ +dberr_t +Tablespace::check_size(file_t& file, const char* name) +{ + ulint size = os_file_get_size(file.m_handle); + ut_a(size != (os_offset_t) -1); + + /* Round size downward to megabytes */ + ulint rounded_size_pages = (ulint) (size >> UNIV_PAGE_SIZE_SHIFT); + + if (&file == &m_files.back() && m_auto_extend_last_file) { + + if (file.m_size > rounded_size_pages + || (m_last_file_size_max > 0 + && m_last_file_size_max < rounded_size_pages)) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "auto-extending data file %s is of a " + "different size %lu pages (rounded " + "down to MB) than specified in the .cnf " + "file: initial %lu pages, max %lu " + "(relevant if non-zero) pages!", + name, + rounded_size_pages, + file.m_size, + m_last_file_size_max); + + return(DB_ERROR); + } + + file.m_size = rounded_size_pages; + } + + if (rounded_size_pages != file.m_size) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Data file %s is of a different " + "size %lu pages (rounded down to MB) " + "than specified in the .cnf file " + "%lu pages!", + name, rounded_size_pages, file.m_size); + + return(DB_ERROR); + } + + return(DB_SUCCESS); +} + +/** +Make physical filename from control info. +@param name - destination buffer +@param size - max size of name +@param file - control information */ +void +Tablespace::make_name(const file_t& file, char* name, ulint size) const +{ + ulint dirnamelen = strlen(srv_data_home); + + ut_a(dirnamelen + strlen(file.m_name) < size - 1); + + memcpy(name, srv_data_home, dirnamelen); + + /* Add a path separator if needed. */ + if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { + name[dirnamelen++] = SRV_PATH_SEPARATOR; + } + + strcpy(name + dirnamelen, file.m_name); + + srv_normalize_path_for_win(name); +} + +/** +Set the size of the file. +@param file - data file spec +@param name - physical file name +@return DB_SUCCESS or error code */ +dberr_t +Tablespace::set_size(file_t& file, const char* name) +{ + ut_a(!srv_read_only_mode); + + /* We created the data file and now write it full of zeros */ + + ib_logf(IB_LOG_LEVEL_INFO, + "Setting file \"%s\" size to %lu MB", + name, (file.m_size >> (20 - UNIV_PAGE_SIZE_SHIFT))); + + ib_logf(IB_LOG_LEVEL_INFO, + "Database physically writes the file full: wait ..."); + + ibool success = os_file_set_size( + name, file.m_handle, + (os_offset_t) file.m_size << UNIV_PAGE_SIZE_SHIFT); + + if (!success) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "During create of \"%s\": probably out of " + "disk space", name); + + return(DB_ERROR); + } + + return(DB_SUCCESS); +} + +/** +Create a data file. +@param file - control info of file to be created. +@param name - physical filename +@return DB_SUCCESS or error code */ +dberr_t +Tablespace::create_file(file_t& file, const char* name) +{ + dberr_t err; + + ut_a(!file.m_exists); + ut_a(!srv_read_only_mode); + + switch (file.m_type) { + case SRV_NEW_RAW: + + /* The partition is opened, not created; then it is + written over */ + m_created_new_raw = true; + + /* Fall through. */ + + case SRV_OLD_RAW: + + srv_start_raw_disk_in_use = TRUE; + + /* Fall through. */ + + case SRV_NOT_RAW: + err = open_data_file(file, name); + break; + } + + + if (err == DB_SUCCESS && file.m_type != SRV_OLD_RAW) { + err = set_size(file, name); + } + + return(err); +} + +/** +Open a data file. +@param file - data file spec +@param name - physical file name +@return DB_SUCCESS or error code */ +dberr_t +Tablespace::open_file(file_t& file, const char* name) +{ + dberr_t err = DB_SUCCESS; + + ut_a(file.m_exists); + + switch (file.m_type) { + case SRV_NEW_RAW: + /* The partition is opened, not created; then it is + written over */ + m_created_new_raw = true; + + case SRV_OLD_RAW: + srv_start_raw_disk_in_use = TRUE; + + if (srv_read_only_mode) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Can't open a raw device when " + "--innodb-read-only is set"); + + return(DB_ERROR); + } + + /* Fall through */ + + case SRV_NOT_RAW: + err = open_data_file(file, name); + + if (err != DB_SUCCESS) { + return(err); + } + break; + } + + if (file.m_type != SRV_OLD_RAW) { + err = check_size(file, name); + } + + return(err); +} + +/** +Read the flush lsn values and check the header flags. + +@param file - file control information +@param name - physical filename +@param min_flushed_lsn - min of flushed lsn values in data files +@param max_flushed_lsn - max of flushed lsn values in data files +@return DB_SUCCESS if all OK */ +dberr_t +Tablespace::read_lsn_and_check_flags( + lsn_t* min_flushed_lsn, + lsn_t* max_flushed_lsn) +{ + /* Only relevant for the system tablespace. */ + ut_ad(m_space_id == TRX_SYS_SPACE); + + *max_flushed_lsn = 0; + *min_flushed_lsn = LSN_MAX; + + files_t::iterator end = m_files.end(); + + for (files_t::iterator it = m_files.begin(); it != end; ++it) { + + ulint flags; + ulint space; + char name[1000]; + + ut_a(it->m_exists); + ut_a(it->m_handle == ~0); + + make_name(*it, name, sizeof(name)); + + dberr_t err = open_data_file(*it, name); + + if (err != DB_SUCCESS) { + return(DB_ERROR); + } + + fil_read_first_page( + it->m_handle, &flags, &space, + min_flushed_lsn, max_flushed_lsn); + + ibool success = os_file_close(it->m_handle); + ut_a(success); + + it->m_handle = ~0; + + /* The first file of the system tablespace must have space + ID = TRX_SYS_SPACE. The FSP_SPACE_ID field in files greater + than ibdata1 are unreliable. */ + + ut_a(space == TRX_SYS_SPACE); + + /* Check the flags for the first system tablespace file only. */ + if (UNIV_PAGE_SIZE != fsp_flags_get_page_size(flags)) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Data file \"%s\" uses page size %lu, " + "but the start-up parameter is " + "--innodb-page-size=%lu", + name, fsp_flags_get_page_size(flags), + UNIV_PAGE_SIZE); + + return(DB_ERROR); + } + } + + return(DB_SUCCESS); +} + +/** +Check if a file can be opened in the correct mode. +@param file - file control information +@return DB_SUCCESS or error code. */ +dberr_t +Tablespace::check_file_status(const file_t& file) const +{ + char name[10000]; + + make_name(file, name, sizeof(name)); + + os_file_stat_t stat; + + memset(&stat, 0x0, sizeof(stat)); + + dberr_t err = os_file_get_status(name, &stat, true); + + /* File exists but we can't read the rw-permission settings. */ + switch (err) { + case DB_FAIL: + ib_logf(IB_LOG_LEVEL_ERROR, + "os_file_get_status() failed on \"%s\". " + "Can't determine file permissions", name); + + err = DB_ERROR; + break; + + case DB_SUCCESS: + + /* Note: stat.rw_perm is only valid for "regular" files */ + + if (stat.type == OS_FILE_TYPE_FILE) { + + if (!stat.rw_perm) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "The system tablespace must be %s", + !srv_read_only_mode + ? "writable" : "readable"); + + err = DB_ERROR; + } + + } else { + /* Not a regular file, bail out. */ + + ib_logf(IB_LOG_LEVEL_ERROR, + "\"%s\" not a regular file.", name); + + err = DB_ERROR; + } + break; + + case DB_NOT_FOUND: + break; + + default: + ut_ad(0); + } + + return(err); +} + +/** +Note that the data file was not found. +@return DB_SUCESS or error code */ +dberr_t +Tablespace::file_not_found(file_t& file, ulint i, ibool* create_new_db) +{ + file.m_exists = false; + + if (srv_read_only_mode) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Can't create file \"%s\" when " + "--innodb-read-only is set", + file.m_name); + + return(DB_ERROR); + + } else if (i == 0) { + + /* First data file. */ + ut_a(!*create_new_db); + *create_new_db = TRUE; + + ib_logf(IB_LOG_LEVEL_INFO, + "The first specified data file \"%s\" " + "did not exist%s", + file.m_name, + (m_space_id == TRX_SYS_SPACE) + ? " : a new database to be created!" + : ""); + + } else if (i == (m_files.size() - 1)) { + + /* Last data file. */ + ib_logf(IB_LOG_LEVEL_INFO, + "Data file \"%s\" did not exist: new " + "to be created", file.m_name); + + } else if (*create_new_db) { + + /* Other data files. */ + ib_logf(IB_LOG_LEVEL_ERROR, + "You can add a new data file at the " + "end but not in the middle. Data file " + "\"%s\" not found.", + file.m_name); + + return(DB_ERROR); + } else { + ib_logf(IB_LOG_LEVEL_INFO, + "Need to create new data file \"%s\"", + file.m_name); + } + + /* Set the file create mode. */ + switch(file.m_type) { + case SRV_NOT_RAW: + file.m_open_flags = OS_FILE_CREATE; + break; + + case SRV_NEW_RAW: + case SRV_OLD_RAW: + file.m_open_flags = OS_FILE_OPEN_RAW; + break; + } + + return(DB_SUCCESS); +} + +/** +Note that the data file was found. */ +void +Tablespace::file_found(file_t& file, ulint i) +{ + /* Note that the file exists and can be opened + in the appropriate mode. */ + file.m_exists = true; + + /* Set the file open mode */ + switch(file.m_type) { + case SRV_NOT_RAW: + case SRV_NEW_RAW: + file.m_open_flags = + (i == 0) ? OS_FILE_OPEN_RETRY : OS_FILE_OPEN; + break; + + case SRV_OLD_RAW: + file.m_open_flags = OS_FILE_OPEN_RAW; + break; + } +} + +/** +Check the data file specification. +@param create_new_db - true if a new database is to be created +@return DB_SUCCESS if all OK else error code */ +dberr_t +Tablespace::check_file_spec(ibool* create_new_db) +{ + srv_normalize_path_for_win(srv_data_home); + + *create_new_db = FALSE; + + if (m_files.size() >= 1000) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Can only have < 1000 data files, you have " + "defined %lu", + m_files.size()); + + return(DB_ERROR); + } + + // FIXME: Check for duplicate data file names + + dberr_t err; + + ut_a(!m_files.empty()); + + /* If there is more than one data file and the last data file + doesn't exist, that is OK. We allow adding of new data files. */ + + for (ulint i = 0; i < m_files.size(); ++i) { + + err = check_file_status(m_files[i]); + + if (err == DB_NOT_FOUND) { + + err = file_not_found(m_files[i], i, create_new_db); + + if (err != DB_SUCCESS) { + break; + } + + } else if (err != DB_SUCCESS) { + + ut_a(err != DB_FAIL); + break; + + } else if (*create_new_db) { + + ut_ad(m_files[0].m_exists); + + ib_logf(IB_LOG_LEVEL_ERROR, + "First data file \"%s\" of tablespace not " + "found but one of the other data files \"%s\" " + "exists.", + m_files[0].m_name, m_files[i].m_name); + + err = DB_ERROR; + break; + + } else { + file_found(m_files[i], i); + } + } + + return(err); +} + +/** +Opens/Creates the data files if they don't exist. + +@param create_new_db - TRUE if new database should be created +@param min_flushed_lsn - min of flushed lsn values in data files +@param max_flushed_lsn - max of flushed lsn values in data files +@param sum_of_new_sizes - sum of sizes of the new files added +@return DB_SUCCESS or error code */ +UNIV_INTERN +dberr_t +Tablespace::open(ulint* sum_of_new_sizes) +{ + dberr_t err; + + ut_ad(!m_files.empty()); + + if (sum_of_new_sizes) { + *sum_of_new_sizes = 0; + } + + for (ulint i = 0; i < m_files.size(); ++i) { + char name[10000]; + + make_name(m_files[i], name, sizeof(name)); + + if (m_files[i].m_exists) { + err = open_file(m_files[i], name); + } else { + err = create_file(m_files[i], name); + + if (sum_of_new_sizes) { + *sum_of_new_sizes += m_files[i].m_size; + } + + /* Set the correct open flags now that we have + successfully created the file. */ + if (err == DB_SUCCESS) { + file_found(m_files[i], i); + } + } + + if (err != DB_SUCCESS) { + break; + } + + /* We can close the handle now and open the tablespace + the proper way. */ + ibool success = os_file_close(m_files[i].m_handle); + ut_a(success); + + m_files[i].m_handle = ~0; + m_files[i].m_exists = true; + + if (i == 0) { + ulint flags; + + flags = fsp_flags_set_page_size(0, UNIV_PAGE_SIZE); + + /* Create the tablespace entry for the multi-file + tablespace in the tablespace manager. */ + fil_space_create( + name, m_space_id, flags, FIL_TABLESPACE); + } + + ut_a(fil_validate()); + + /* Open the data file. */ + char* filename = fil_node_create( + name, m_files[i].m_size, + m_space_id, m_files[i].m_type != SRV_NOT_RAW); + + if (filename == 0) { + err = DB_ERROR; + break; + } + } + + return(err); +} diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 69ad71cbff32..1e5cf377b780 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -60,6 +60,7 @@ Created 10/8/1995 Heikki Tuuri #include "dict0load.h" #include "dict0boot.h" #include "dict0stats_bg.h" /* dict_stats_event */ +#include "srv0space.h" #include "srv0start.h" #include "row0mysql.h" #include "ha_prototypes.h" @@ -160,29 +161,6 @@ for tasks like IO than for storing idle event objects. */ UNIV_INTERN ibool srv_use_native_conditions = FALSE; #endif /* __WIN__ */ -/*------------------------- DATA FILES ------------------------ */ -UNIV_INTERN ulint srv_n_data_files = 0; -UNIV_INTERN char** srv_data_file_names = NULL; -/* size in database pages */ -UNIV_INTERN ulint* srv_data_file_sizes = NULL; - -/* if TRUE, then we auto-extend the last data file */ -UNIV_INTERN ibool srv_auto_extend_last_data_file = FALSE; -/* if != 0, this tells the max size auto-extending may increase the -last data file size */ -UNIV_INTERN ulint srv_last_file_size_max = 0; -/* If the last data file is auto-extended, we add this -many pages to it at a time */ -UNIV_INTERN ulong srv_auto_extend_increment = 8; -UNIV_INTERN ulint* srv_data_file_is_raw_partition = NULL; - -/* If the following is TRUE we do not allow inserts etc. This protects -the user from forgetting the 'newraw' keyword to my.cnf */ -UNIV_INTERN ibool srv_created_new_raw = FALSE; - -/*----------------------- TEMP DATA FILES ---------------------- */ -UNIV_INTERN srv_temp_tablespace_t srv_temp_tablespace; - /*------------------------- LOG FILES ------------------------ */ UNIV_INTERN char* srv_log_group_home_dir = NULL; @@ -1032,34 +1010,13 @@ void srv_normalize_init_values(void) /*===========================*/ { - ulint n; - ulint i; - - n = srv_n_data_files; - - for (i = 0; i < n; i++) { - srv_data_file_sizes[i] = srv_data_file_sizes[i] - * ((1024 * 1024) / UNIV_PAGE_SIZE); - } - - n = srv_temp_tablespace.m_n_temp_data_files; - - for (i = 0; i < n; i++) { - srv_temp_tablespace.m_temp_data_file_sizes[i] = - srv_temp_tablespace.m_temp_data_file_sizes[i] - * ((1024 * 1024) / UNIV_PAGE_SIZE); - } - - srv_last_file_size_max = srv_last_file_size_max - * ((1024 * 1024) / UNIV_PAGE_SIZE); + srv_sys_space.normalize(); - srv_temp_tablespace.m_last_temp_data_file_size_max = - srv_temp_tablespace.m_last_temp_data_file_size_max - * ((1024 * 1024) / UNIV_PAGE_SIZE); + srv_tmp_space.normalize(); - srv_log_file_size = srv_log_file_size / UNIV_PAGE_SIZE; + srv_log_file_size /= UNIV_PAGE_SIZE; - srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE; + srv_log_buffer_size /= UNIV_PAGE_SIZE; srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE); } @@ -2847,210 +2804,3 @@ srv_purge_wakeup(void) } } -/**********************************************************************//** -Parse the input params and populate member variables. -@return true on successfull parse else false*/ -UNIV_INTERN -bool -srv_temp_tablespace_t::init_params( -/*===============================*/ - char* str) /*!< in: parse and obtain init value */ -{ - char* input_str; - char* path; - ulint size; - ulint i = 0; - - m_auto_extend_last_temp_data_file = false; - m_last_temp_data_file_size_max = 0; - m_temp_data_file_names = NULL; - m_temp_data_file_sizes = NULL; - m_temp_data_file_raw_type = NULL; - - input_str = str; - - /*---------------------- PASS 1 ---------------------------*/ - /* First calculate the number of data files and check syntax: - path:size[M | G];path:size[M | G]... . Note that a Windows path may - contain a drive name and a ':'. */ - while (*str != '\0') { - path = str; - - while ((*str != ':' && *str != '\0') - || (*str == ':' - && (*(str + 1) == '\\' || *(str + 1) == '/' - || *(str + 1) == ':'))) { - str++; - } - - if (*str == '\0') { - return(false); - } - - str++; - - str = parse_megabytes(str, &size); - - if (0 == strncmp(str, ":autoextend", - (sizeof ":autoextend") - 1)) { - - str += (sizeof ":autoextend") - 1; - - if (0 == strncmp(str, ":max:", - (sizeof ":max:") - 1)) { - - str += (sizeof ":max:") - 1; - - str = parse_megabytes(str, &size); - } - - if (*str != '\0') { - - return(false); - } - } - - if (strlen(str) >= 6 - && *str == 'n' - && *(str + 1) == 'e' - && *(str + 2) == 'w') { - str += 3; - } - - if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { - str += 3; - } - - if (size == 0) { - return(false); - } - - i++; - - if (*str == ';') { - str++; - } else if (*str != '\0') { - - return(false); - } - } - - if (i == 0) { - /* If innodb_temp_data_file_path was defined it must contain - at least one data file definition */ - return(false); - } - - m_temp_data_file_names = static_cast( - malloc(i * - sizeof *srv_temp_tablespace.m_temp_data_file_names)); - - m_temp_data_file_sizes = static_cast( - malloc(i * - sizeof *srv_temp_tablespace.m_temp_data_file_sizes)); - - m_temp_data_file_raw_type= static_cast( - malloc(i * sizeof *m_temp_data_file_raw_type)); - - srv_temp_tablespace.m_n_temp_data_files = i; - - /*---------------------- PASS 2 ---------------------------*/ - /* Then store the actual values to our arrays */ - str = input_str; - i = 0; - - while (*str != '\0') { - path = str; - - /* Note that we must step over the ':' in a Windows path; - a Windows path normally looks like C:\ibdata\ibdata1:1G, but - a Windows raw partition may have a specification like - \\.\C::1Gnewraw or \\.\PHYSICALDRIVE2:1Gnewraw */ - - while ((*str != ':' && *str != '\0') - || (*str == ':' - && (*(str + 1) == '\\' || *(str + 1) == '/' - || *(str + 1) == ':'))) { - str++; - } - - if (*str == ':') { - /* Make path a null-terminated string */ - *str = '\0'; - str++; - } - - str = parse_megabytes(str, &size); - - m_temp_data_file_names[i] = path; - m_temp_data_file_sizes[i] = size; - - if (0 == strncmp(str, ":autoextend", - (sizeof ":autoextend") - 1)) { - - m_auto_extend_last_temp_data_file = true; - - str += (sizeof ":autoextend") - 1; - - if (0 == strncmp(str, ":max:", - (sizeof ":max:") - 1)) { - - str += (sizeof ":max:") - 1; - - str = parse_megabytes( - str, &m_last_temp_data_file_size_max); - } - - if (*str != '\0') { - - return(false); - } - } - - (m_temp_data_file_raw_type)[i] = 0; - - if (strlen(str) >= 6 - && *str == 'n' - && *(str + 1) == 'e' - && *(str + 2) == 'w') { - str += 3; - (m_temp_data_file_raw_type)[i] = SRV_NEW_RAW; - } - - if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { - str += 3; - - if ((m_temp_data_file_raw_type)[i] == 0) { - (m_temp_data_file_raw_type)[i] = SRV_OLD_RAW; - } - } - - i++; - - if (*str == ';') { - str++; - } - } - - /* Ensure temp-data-files are not same as data-files */ - for (ulint k1 = 0; k1 < m_n_temp_data_files; k1++) { - char* temp_data_fname = m_temp_data_file_names[k1]; - for (ulint k2 = 0; k2 < srv_n_data_files; k2++) { - char* data_fname = srv_data_file_names[k2]; - if(innobase_strcasecmp( - temp_data_fname, data_fname) == 0) { - return(false); - } - } - } - - /* Disable raw device for temp-tablespace */ - for (ulint k = 0; k < m_n_temp_data_files; k++) { - if ((m_temp_data_file_raw_type)[k] != SRV_NOT_RAW) { - return(false); - } - } - - return(true); -} - diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index fc1e63eba564..d3c028a4e754 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -63,6 +63,7 @@ Created 2/16/1996 Heikki Tuuri #include "ibuf0ibuf.h" #include "srv0start.h" #include "srv0srv.h" +#include "srv0space.h" #ifndef UNIV_HOTBACKUP # include "trx0rseg.h" # include "os0proc.h" @@ -158,40 +159,6 @@ UNIV_INTERN mysql_pfs_key_t srv_master_thread_key; UNIV_INTERN mysql_pfs_key_t srv_purge_thread_key; #endif /* UNIV_PFS_THREAD */ -/*********************************************************************//** -Convert a numeric string that optionally ends in G or M, to a number -containing megabytes. -@return next character in string */ -static -char* -srv_parse_megabytes( -/*================*/ - char* str, /*!< in: string containing a quantity in bytes */ - ulint* megs) /*!< out: the number in megabytes */ -{ - char* endp; - ulint size; - - size = strtoul(str, &endp, 10); - - str = endp; - - switch (*str) { - case 'G': case 'g': - size *= 1024; - /* fall through */ - case 'M': case 'm': - str++; - break; - default: - size /= 1024 * 1024; - break; - } - - *megs = size; - return(str); -} - /*********************************************************************//** Check if a file can be opened in read-write mode. @return true if it doesn't exist or can be opened in rw mode. */ @@ -249,232 +216,6 @@ srv_file_check_mode( return(true); } -/*********************************************************************//** -Reads the data files and their sizes from a character string given in -the .cnf file. -@return TRUE if ok, FALSE on parse error */ -UNIV_INTERN -ibool -srv_parse_data_file_paths_and_sizes( -/*================================*/ - char* str) /*!< in/out: the data file path string */ -{ - char* input_str; - char* path; - ulint size; - ulint i = 0; - - srv_auto_extend_last_data_file = FALSE; - srv_last_file_size_max = 0; - srv_data_file_names = NULL; - srv_data_file_sizes = NULL; - srv_data_file_is_raw_partition = NULL; - - input_str = str; - - /* First calculate the number of data files and check syntax: - path:size[M | G];path:size[M | G]... . Note that a Windows path may - contain a drive name and a ':'. */ - - while (*str != '\0') { - path = str; - - while ((*str != ':' && *str != '\0') - || (*str == ':' - && (*(str + 1) == '\\' || *(str + 1) == '/' - || *(str + 1) == ':'))) { - str++; - } - - if (*str == '\0') { - return(FALSE); - } - - str++; - - str = srv_parse_megabytes(str, &size); - - if (0 == strncmp(str, ":autoextend", - (sizeof ":autoextend") - 1)) { - - str += (sizeof ":autoextend") - 1; - - if (0 == strncmp(str, ":max:", - (sizeof ":max:") - 1)) { - - str += (sizeof ":max:") - 1; - - str = srv_parse_megabytes(str, &size); - } - - if (*str != '\0') { - - return(FALSE); - } - } - - if (strlen(str) >= 6 - && *str == 'n' - && *(str + 1) == 'e' - && *(str + 2) == 'w') { - str += 3; - } - - if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { - str += 3; - } - - if (size == 0) { - return(FALSE); - } - - i++; - - if (*str == ';') { - str++; - } else if (*str != '\0') { - - return(FALSE); - } - } - - if (i == 0) { - /* If innodb_data_file_path was defined it must contain - at least one data file definition */ - - return(FALSE); - } - - srv_data_file_names = static_cast( - malloc(i * sizeof *srv_data_file_names)); - - srv_data_file_sizes = static_cast( - malloc(i * sizeof *srv_data_file_sizes)); - - srv_data_file_is_raw_partition = static_cast( - malloc(i * sizeof *srv_data_file_is_raw_partition)); - - srv_n_data_files = i; - - /* Then store the actual values to our arrays */ - - str = input_str; - i = 0; - - while (*str != '\0') { - path = str; - - /* Note that we must step over the ':' in a Windows path; - a Windows path normally looks like C:\ibdata\ibdata1:1G, but - a Windows raw partition may have a specification like - \\.\C::1Gnewraw or \\.\PHYSICALDRIVE2:1Gnewraw */ - - while ((*str != ':' && *str != '\0') - || (*str == ':' - && (*(str + 1) == '\\' || *(str + 1) == '/' - || *(str + 1) == ':'))) { - str++; - } - - if (*str == ':') { - /* Make path a null-terminated string */ - *str = '\0'; - str++; - } - - str = srv_parse_megabytes(str, &size); - - srv_data_file_names[i] = path; - srv_data_file_sizes[i] = size; - - if (0 == strncmp(str, ":autoextend", - (sizeof ":autoextend") - 1)) { - - srv_auto_extend_last_data_file = TRUE; - - str += (sizeof ":autoextend") - 1; - - if (0 == strncmp(str, ":max:", - (sizeof ":max:") - 1)) { - - str += (sizeof ":max:") - 1; - - str = srv_parse_megabytes( - str, &srv_last_file_size_max); - } - - if (*str != '\0') { - - return(FALSE); - } - } - - (srv_data_file_is_raw_partition)[i] = 0; - - if (strlen(str) >= 6 - && *str == 'n' - && *(str + 1) == 'e' - && *(str + 2) == 'w') { - str += 3; - (srv_data_file_is_raw_partition)[i] = SRV_NEW_RAW; - } - - if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { - str += 3; - - if ((srv_data_file_is_raw_partition)[i] == 0) { - (srv_data_file_is_raw_partition)[i] = SRV_OLD_RAW; - } - } - - i++; - - if (*str == ';') { - str++; - } - } - - return(TRUE); -} - -/*********************************************************************//** -Frees the memory allocated by srv_parse_data_file_paths_and_sizes() -and srv_parse_log_group_home_dirs(). */ -UNIV_INTERN -void -srv_free_paths_and_sizes(void) -/*==========================*/ -{ - if (srv_data_file_names) { - free(srv_data_file_names); - srv_data_file_names = NULL; - } - if (srv_data_file_sizes) { - free(srv_data_file_sizes); - srv_data_file_sizes = NULL; - } - - if (srv_data_file_is_raw_partition) { - free(srv_data_file_is_raw_partition); - srv_data_file_is_raw_partition = NULL; - } - - if (srv_temp_tablespace.m_temp_data_file_names) { - free(srv_temp_tablespace.m_temp_data_file_names); - srv_temp_tablespace.m_temp_data_file_names = NULL; - } - - if (srv_temp_tablespace.m_temp_data_file_sizes) { - free(srv_temp_tablespace.m_temp_data_file_sizes); - srv_temp_tablespace.m_temp_data_file_sizes = NULL; - } - - if (srv_temp_tablespace.m_temp_data_file_raw_type) { - free(srv_temp_tablespace.m_temp_data_file_raw_type); - srv_temp_tablespace.m_temp_data_file_raw_type = NULL; - } -} - #ifndef UNIV_HOTBACKUP /********************************************************************//** I/o-handler thread function. @@ -776,474 +517,6 @@ open_log_file( return(DB_SUCCESS); } -/*********************************************************************//** -Creates or opens database data files and closes them. -@return DB_SUCCESS or error code */ -static __attribute__((nonnull, warn_unused_result)) -dberr_t -open_or_create_data_files( -/*======================*/ - ibool* create_new_db, /*!< out: TRUE if new database should be - created */ -#ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no,/*!< out: min of archived log - numbers in data files */ - ulint* max_arch_log_no,/*!< out: max of archived log - numbers in data files */ -#endif /* UNIV_LOG_ARCHIVE */ - lsn_t* min_flushed_lsn,/*!< out: min of flushed lsn - values in data files */ - lsn_t* max_flushed_lsn,/*!< out: max of flushed lsn - values in data files */ - ulint* sum_of_new_sizes)/*!< out: sum of sizes of the - new files added */ -{ - ibool ret; - ulint i; - ibool one_opened = FALSE; - ibool one_created = FALSE; - os_offset_t size; - ulint flags; - ulint space; - ulint rounded_size_pages; - char name[10000]; - - if (srv_n_data_files >= 1000) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "Can only have < 1000 data files, you have " - "defined %lu", (ulong) srv_n_data_files); - - return(DB_ERROR); - } - - *sum_of_new_sizes = 0; - - *create_new_db = FALSE; - - srv_normalize_path_for_win(srv_data_home); - - for (i = 0; i < srv_n_data_files; i++) { - ulint dirnamelen; - - srv_normalize_path_for_win(srv_data_file_names[i]); - dirnamelen = strlen(srv_data_home); - - ut_a(dirnamelen + strlen(srv_data_file_names[i]) - < (sizeof name) - 1); - - memcpy(name, srv_data_home, dirnamelen); - - /* Add a path separator if needed. */ - if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { - name[dirnamelen++] = SRV_PATH_SEPARATOR; - } - - strcpy(name + dirnamelen, srv_data_file_names[i]); - - /* Note: It will return true if the file doesn' exist. */ - - if (!srv_file_check_mode(name)) { - - return(DB_FAIL); - - } else if (srv_data_file_is_raw_partition[i] == 0) { - - /* First we try to create the file: if it already - exists, ret will get value FALSE */ - - files[i] = os_file_create( - innodb_file_data_key, name, OS_FILE_CREATE, - OS_FILE_NORMAL, OS_DATA_FILE, &ret); - - if (srv_read_only_mode) { - - if (ret) { - goto size_check; - } - - ib_logf(IB_LOG_LEVEL_ERROR, - "Opening %s failed!", name); - - return(DB_ERROR); - - } else if (!ret - && os_file_get_last_error(false) - != OS_FILE_ALREADY_EXISTS -#ifdef UNIV_AIX - /* AIX 5.1 after security patch ML7 may have - errno set to 0 here, which causes our - function to return 100; work around that - AIX problem */ - && os_file_get_last_error(false) != 100 -#endif /* UNIV_AIX */ - ) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Creating or opening %s failed!", - name); - - return(DB_ERROR); - } - - } else if (srv_data_file_is_raw_partition[i] == SRV_NEW_RAW) { - - ut_a(!srv_read_only_mode); - - /* The partition is opened, not created; then it is - written over */ - - srv_start_raw_disk_in_use = TRUE; - srv_created_new_raw = TRUE; - - files[i] = os_file_create( - innodb_file_data_key, name, OS_FILE_OPEN_RAW, - OS_FILE_NORMAL, OS_DATA_FILE, &ret); - - if (!ret) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Error in opening %s", name); - - return(DB_ERROR); - } - } else if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) { - srv_start_raw_disk_in_use = TRUE; - - ret = FALSE; - } else { - ut_a(0); - } - - if (ret == FALSE) { - /* We open the data file */ - - if (one_created) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Data files can only be added at " - "the end of a tablespace, but " - "data file %s existed beforehand.", - name); - return(DB_ERROR); - } - if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) { - ut_a(!srv_read_only_mode); - files[i] = os_file_create( - innodb_file_data_key, - name, OS_FILE_OPEN_RAW, - OS_FILE_NORMAL, OS_DATA_FILE, &ret); - } else if (i == 0) { - files[i] = os_file_create( - innodb_file_data_key, - name, OS_FILE_OPEN_RETRY, - OS_FILE_NORMAL, OS_DATA_FILE, &ret); - } else { - files[i] = os_file_create( - innodb_file_data_key, - name, OS_FILE_OPEN, OS_FILE_NORMAL, - OS_DATA_FILE, &ret); - } - - if (!ret) { - - os_file_get_last_error(true); - - ib_logf(IB_LOG_LEVEL_ERROR, - "Can't open '%s'", name); - - return(DB_ERROR); - } - - if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) { - - goto skip_size_check; - } - -size_check: - size = os_file_get_size(files[i]); - ut_a(size != (os_offset_t) -1); - /* Round size downward to megabytes */ - - rounded_size_pages = (ulint) - (size >> UNIV_PAGE_SIZE_SHIFT); - - if (i == srv_n_data_files - 1 - && srv_auto_extend_last_data_file) { - - if (srv_data_file_sizes[i] > rounded_size_pages - || (srv_last_file_size_max > 0 - && srv_last_file_size_max - < rounded_size_pages)) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "auto-extending " - "data file %s is " - "of a different size " - "%lu pages (rounded " - "down to MB) than specified " - "in the .cnf file: " - "initial %lu pages, " - "max %lu (relevant if " - "non-zero) pages!", - name, - (ulong) rounded_size_pages, - (ulong) srv_data_file_sizes[i], - (ulong) - srv_last_file_size_max); - - return(DB_ERROR); - } - - srv_data_file_sizes[i] = rounded_size_pages; - } - - if (rounded_size_pages != srv_data_file_sizes[i]) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "Data file %s is of a different " - "size %lu pages (rounded down to MB) " - "than specified in the .cnf file " - "%lu pages!", - name, - (ulong) rounded_size_pages, - (ulong) srv_data_file_sizes[i]); - - return(DB_ERROR); - } -skip_size_check: - fil_read_first_page( - files[i], one_opened, &flags, &space, -#ifdef UNIV_LOG_ARCHIVE - min_arch_log_no, max_arch_log_no, -#endif /* UNIV_LOG_ARCHIVE */ - min_flushed_lsn, max_flushed_lsn); - - /* The first file of the system tablespace must - have space ID = TRX_SYS_SPACE. The FSP_SPACE_ID - field in files greater than ibdata1 are unreliable. */ - ut_a(one_opened || space == TRX_SYS_SPACE); - - /* Check the flags for the first system tablespace - file only. */ - if (!one_opened - && UNIV_PAGE_SIZE - != fsp_flags_get_page_size(flags)) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "Data file \"%s\" uses page size %lu," - "but the start-up parameter " - "is --innodb-page-size=%lu", - name, - fsp_flags_get_page_size(flags), - UNIV_PAGE_SIZE); - - return(DB_ERROR); - } - - one_opened = TRUE; - } else if (!srv_read_only_mode) { - /* We created the data file and now write it full of - zeros */ - - one_created = TRUE; - - if (i > 0) { - ib_logf(IB_LOG_LEVEL_INFO, - "Data file %s did not" - " exist: new to be created", - name); - } else { - ib_logf(IB_LOG_LEVEL_INFO, - "The first specified " - "data file %s did not exist: " - "a new database to be created!", - name); - - *create_new_db = TRUE; - } - - ib_logf(IB_LOG_LEVEL_INFO, - "Setting file %s size to %lu MB", - name, - (ulong) (srv_data_file_sizes[i] - >> (20 - UNIV_PAGE_SIZE_SHIFT))); - - ib_logf(IB_LOG_LEVEL_INFO, - "Database physically writes the" - " file full: wait..."); - - ret = os_file_set_size( - name, files[i], - (os_offset_t) srv_data_file_sizes[i] - << UNIV_PAGE_SIZE_SHIFT); - - if (!ret) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Error in creating %s: " - "probably out of disk space", - name); - - return(DB_ERROR); - } - - *sum_of_new_sizes += srv_data_file_sizes[i]; - } - - ret = os_file_close(files[i]); - ut_a(ret); - - if (i == 0) { - flags = fsp_flags_set_page_size(0, UNIV_PAGE_SIZE); - fil_space_create(name, 0, flags, FIL_TABLESPACE); - } - - ut_a(fil_validate()); - - if (!fil_node_create(name, srv_data_file_sizes[i], 0, - srv_data_file_is_raw_partition[i] != 0)) { - return(DB_ERROR); - } - } - - return(DB_SUCCESS); -} - -/*********************************************************************//** -Creates or opens database temp data files and closes them. -@return DB_SUCCESS or error code */ -static -dberr_t -open_or_create_temp_data_files() -/*============================*/ -{ - ibool ret; - ulint flags; - ulint size_of_temp_tablespace = 0; - - if (srv_read_only_mode) { - return(DB_SUCCESS); - } - - if (srv_temp_tablespace.m_n_temp_data_files >= 1000) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "Can only have < 1000 temp data files, you have " - "defined %lu", - (ulong) srv_temp_tablespace.m_n_temp_data_files); - - return(DB_ERROR); - } - - srv_normalize_path_for_win(srv_data_home); - - for (ulint i = 0; i < srv_temp_tablespace.m_n_temp_data_files; i++) { - char name[10000]; - ulint dirnamelen; - - srv_normalize_path_for_win( - srv_temp_tablespace.m_temp_data_file_names[i]); - dirnamelen = strlen(srv_data_home); - - ut_a(dirnamelen + - strlen(srv_temp_tablespace.m_temp_data_file_names[i]) - < (sizeof name) - 1); - - memcpy(name, srv_data_home, dirnamelen); - - /* Add a path separator if needed. */ - if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { - name[dirnamelen++] = SRV_PATH_SEPARATOR; - } - - strcpy(name + dirnamelen, - srv_temp_tablespace.m_temp_data_file_names[i]); - - /* remove existing file always as we re-create temp-talbespace - on restart */ - os_file_delete_if_exists(name); - - /* First we try to create the file: if it already - exists, ret will get value FALSE. */ - files[i] = os_file_create( - innodb_file_data_key, name, OS_FILE_CREATE, - OS_FILE_NORMAL, OS_DATA_TEMP_FILE, &ret); - if (!ret - && os_file_get_last_error(false) - != OS_FILE_ALREADY_EXISTS -#ifdef UNIV_AIX - /* AIX 5.1 after security patch ML7 may have - errno set to 0 here, which causes our - function to return 100; work around that - AIX problem */ - && os_file_get_last_error(false) != 100 -#endif /* UNIV_AIX */ - ) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Creating or opening %s failed!", - name); - - return(DB_ERROR); - } - - /* We created the data file and now write it full of zeros */ - ib_logf(IB_LOG_LEVEL_INFO, - "Created tablespace %s for temporary tables, " - "initial size is %lu MB. Wait while database " - "physically writes the file full....", - name, - (ulong) (srv_temp_tablespace.m_temp_data_file_sizes[i] - >> (20 - UNIV_PAGE_SIZE_SHIFT))); - - ret = os_file_set_size( - name, files[i], - (os_offset_t) - srv_temp_tablespace.m_temp_data_file_sizes[i] - << UNIV_PAGE_SIZE_SHIFT); - - size_of_temp_tablespace += - srv_temp_tablespace.m_temp_data_file_sizes[i]; - - if (!ret) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Error in creating %s: " - "probably out of disk space", - name); - - return(DB_ERROR); - } - - if (i == 0) { - flags = fsp_flags_set_page_size(0, UNIV_PAGE_SIZE); - dict_hdr_get_new_id( - NULL, NULL, - &srv_temp_tablespace.m_temp_tablespace_id); - fil_space_create( - name, - srv_temp_tablespace.m_temp_tablespace_id, - flags, FIL_TABLESPACE); - } - - ut_a(fil_validate()); - - if (!fil_node_create( - name, srv_temp_tablespace.m_temp_data_file_sizes[i], - srv_temp_tablespace.m_temp_tablespace_id, FALSE)) { - return(DB_ERROR); - } - } - - { - mtr_t mtr; - - mtr_start(&mtr); - - fsp_header_init(srv_temp_tablespace.m_temp_tablespace_id, - size_of_temp_tablespace, &mtr); - - mtr_commit(&mtr); - } - - return(DB_SUCCESS); -} - /*********************************************************************//** Create undo tablespace. @return DB_SUCCESS or error code */ @@ -1314,7 +587,6 @@ srv_undo_tablespace_create( return(err); } - /*********************************************************************//** Open an undo tablespace. @return DB_SUCCESS or error code */ @@ -1616,6 +888,62 @@ srv_start_wait_for_purge_to_start() } } +/******************************************************************** +Create the temporary file tablespace. +@return DB_SUCCESS or error code. */ +static +dberr_t +srv_open_tmp_tablespace( +/*====================*/ + Tablespace* tmp_space) /*!< in/out: Tablespace */ +{ + if (srv_read_only_mode) { + return(DB_SUCCESS); + } + + ibool create_new_temp_space; + ulint temp_space_id = ULINT_UNDEFINED; + + dict_hdr_get_new_id(NULL, NULL, &temp_space_id); + + tmp_space->set_space_id(temp_space_id); + + dberr_t err = tmp_space->check_file_spec(&create_new_temp_space); + + if (err == DB_FAIL) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "The system temp tablespace must be writable!"); + + err = DB_ERROR; + + } else if (err != DB_SUCCESS) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Could not create the system temp tablespace."); + + } else if ((err = tmp_space->open(0)) != DB_SUCCESS) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Unable to create shared temporary tablespace"); + + } else { + + mtr_t mtr; + ulint size = tmp_space->get_sum_of_sizes(); + + ut_a(tmp_space->space_id() == temp_space_id + && temp_space_id != ULINT_UNDEFINED); + + mtr_start(&mtr); + + fsp_header_init(tmp_space->space_id(), size, &mtr); + + mtr_commit(&mtr); + } + + return(err); +} /******************************************************************** Starts InnoDB and creates a new database if database files are not found and the user wants. @@ -1626,13 +954,12 @@ innobase_start_or_create_for_mysql(void) /*====================================*/ { ibool create_new_db; - lsn_t min_flushed_lsn; - lsn_t max_flushed_lsn; + lsn_t min_flushed_lsn = 0; + lsn_t max_flushed_lsn = 0; #ifdef UNIV_LOG_ARCHIVE ulint min_arch_log_no; ulint max_arch_log_no; #endif /* UNIV_LOG_ARCHIVE */ - ulint sum_of_new_sizes; ulint sum_of_data_file_sizes; ulint tablespace_size_in_header; dberr_t err; @@ -2108,49 +1435,33 @@ innobase_start_or_create_for_mysql(void) return(DB_ERROR); } - sum_of_new_sizes = 0; + srv_normalize_path_for_win(srv_data_home); - for (i = 0; i < srv_n_data_files; i++) { -#ifndef __WIN__ - if (sizeof(off_t) < 5 - && srv_data_file_sizes[i] - >= (ulint) (1 << (32 - UNIV_PAGE_SIZE_SHIFT))) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: file size must be < 4 GB" - " with this MySQL binary\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: and operating system combination," - " in some OS's < 2 GB\n"); + ulint sum_of_new_sizes; - return(DB_ERROR); - } -#endif - sum_of_new_sizes += srv_data_file_sizes[i]; - } + sum_of_new_sizes = srv_sys_space.get_sum_of_sizes(); + + if (sum_of_new_sizes == ULINT_UNDEFINED) { + return(DB_ERROR); + } else if (sum_of_new_sizes < 10485760 / UNIV_PAGE_SIZE) { - if (sum_of_new_sizes < 10485760 / UNIV_PAGE_SIZE) { ib_logf(IB_LOG_LEVEL_ERROR, "Tablespace size must be at least 10 MB"); return(DB_ERROR); } - err = open_or_create_data_files(&create_new_db, -#ifdef UNIV_LOG_ARCHIVE - &min_arch_log_no, &max_arch_log_no, -#endif /* UNIV_LOG_ARCHIVE */ - &min_flushed_lsn, &max_flushed_lsn, - &sum_of_new_sizes); - if (err == DB_FAIL) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "The system tablespace must be writable!"); + /* Check if the data files exist or not. */ + err = srv_sys_space.check_file_spec(&create_new_db); + if (err != DB_SUCCESS) { return(DB_ERROR); + } - } else if (err != DB_SUCCESS) { + /* Open or create the data files. */ + err = srv_sys_space.open(&sum_of_new_sizes); + + if (err != DB_SUCCESS) { ib_logf(IB_LOG_LEVEL_ERROR, "Could not open or create the system tablespace. If " @@ -2166,10 +1477,13 @@ innobase_start_or_create_for_mysql(void) return(err); } -#ifdef UNIV_LOG_ARCHIVE - srv_normalize_path_for_win(srv_arch_dir); - srv_arch_dir = srv_add_path_separator_if_needed(srv_arch_dir); -#endif /* UNIV_LOG_ARCHIVE */ + /* Read the values from the header page. */ + err = srv_sys_space.read_lsn_and_check_flags( + &min_flushed_lsn, &max_flushed_lsn); + + if (err != DB_SUCCESS) { + return(DB_ERROR); + } dirnamelen = strlen(srv_log_group_home_dir); ut_a(dirnamelen < (sizeof logfilename) - 10 - sizeof "ib_logfile"); @@ -2190,8 +1504,8 @@ innobase_start_or_create_for_mysql(void) buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); - err = create_log_files(logfilename, dirnamelen, - max_flushed_lsn, logfile0); + err = create_log_files( + logfilename, dirnamelen, max_flushed_lsn, logfile0); if (err != DB_SUCCESS) { return(err); @@ -2643,20 +1957,9 @@ innobase_start_or_create_for_mysql(void) log_buffer_flush_to_disk(); } - /*--------------- Temp data files -------------------------*/ - err = open_or_create_temp_data_files(); - if (err == DB_FAIL) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "The system temp tablespace must be writable!"); - - return(DB_ERROR); - - } else if (err != DB_SUCCESS) { - - ib_logf(IB_LOG_LEVEL_ERROR, - "Could not create the system temp tablespace."); + err = srv_open_tmp_tablespace(&srv_tmp_space); + if (err != DB_SUCCESS) { return(err); } @@ -2794,16 +2097,14 @@ innobase_start_or_create_for_mysql(void) #ifdef UNIV_DEBUG /* buf_debug_prints = TRUE; */ #endif /* UNIV_DEBUG */ - sum_of_data_file_sizes = 0; - for (i = 0; i < srv_n_data_files; i++) { - sum_of_data_file_sizes += srv_data_file_sizes[i]; - } + sum_of_data_file_sizes = srv_sys_space.get_sum_of_sizes(); + ut_a(sum_of_new_sizes != ULINT_UNDEFINED); tablespace_size_in_header = fsp_header_get_tablespace_size(); if (!srv_read_only_mode - && !srv_auto_extend_last_data_file + && !srv_sys_space.can_auto_extend_last_file() && sum_of_data_file_sizes != tablespace_size_in_header) { ut_print_timestamp(stderr); @@ -2847,7 +2148,7 @@ innobase_start_or_create_for_mysql(void) } if (!srv_read_only_mode - && srv_auto_extend_last_data_file + && srv_sys_space.can_auto_extend_last_file() && sum_of_data_file_sizes < tablespace_size_in_header) { ut_print_timestamp(stderr);