diff options
author | Michael Widenius <monty@askmonty.org> | 2013-03-26 00:03:13 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2013-03-26 00:03:13 +0200 |
commit | 068c61978e3a81836d52b8caf11e044290159ad1 (patch) | |
tree | 2cbca861ab2cebe3bd99379ca9668bb483ca0d2a /storage/innobase/srv/srv0start.cc | |
parent | 35bc8f9f4353b64da215e52ff6f1612a8ce66f43 (diff) | |
download | mariadb-git-068c61978e3a81836d52b8caf11e044290159ad1.tar.gz |
Temporary commit of 10.0-merge
Diffstat (limited to 'storage/innobase/srv/srv0start.cc')
-rw-r--r-- | storage/innobase/srv/srv0start.cc | 1765 |
1 files changed, 1071 insertions, 694 deletions
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 9d1600cff23..efe9f094c0d 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -71,6 +71,7 @@ Created 2/16/1996 Heikki Tuuri # include "buf0rea.h" # include "dict0boot.h" # include "dict0load.h" +# include "dict0stats_bg.h" # include "que0que.h" # include "usr0sess.h" # include "lock0lock.h" @@ -87,9 +88,9 @@ Created 2/16/1996 Heikki Tuuri # include "row0row.h" # include "row0mysql.h" # include "btr0pcur.h" -# include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ -# include "zlib.h" /* for ZLIB_VERSION */ -# include "buf0dblwr.h" +# include "os0sync.h" +# include "zlib.h" +# include "ut0crc32.h" /** Log sequence number immediately after startup */ UNIV_INTERN lsn_t srv_start_lsn; @@ -188,6 +189,63 @@ srv_parse_megabytes( } /*********************************************************************//** +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. */ +static +bool +srv_file_check_mode( +/*================*/ + const char* name) /*!< in: filename to check */ +{ + os_file_stat_t stat; + + memset(&stat, 0x0, sizeof(stat)); + + dberr_t err = os_file_get_status(name, &stat, true); + + if (err == DB_FAIL) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "os_file_get_status() failed on '%s'. Can't determine " + "file permissions", name); + + return(false); + + } else if (err == DB_SUCCESS) { + + /* Note: stat.rw_perm is only valid of files */ + + if (stat.type == OS_FILE_TYPE_FILE) { + if (!stat.rw_perm) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "%s can't be opened in %s mode", + srv_read_only_mode + ? "read-write" : "read", + name); + + return(false); + } + } else { + /* Not a regular file, bail out. */ + + ib_logf(IB_LOG_LEVEL_ERROR, + "'%s' not a regular file.", name); + + return(false); + } + } else { + + /* This is OK. If the file create fails on RO media, there + is nothing we can do. */ + + ut_a(err == DB_NOT_FOUND); + } + + 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 */ @@ -376,79 +434,6 @@ srv_parse_data_file_paths_and_sizes( } /*********************************************************************//** -Reads log group home directories from a character string given in -the .cnf file. -@return TRUE if ok, FALSE on parse error */ -UNIV_INTERN -ibool -srv_parse_log_group_home_dirs( -/*==========================*/ - char* str) /*!< in/out: character string */ -{ - char* input_str; - char* path; - ulint i = 0; - - srv_log_group_home_dirs = NULL; - - input_str = str; - - /* First calculate the number of directories and check syntax: - path;path;... */ - - while (*str != '\0') { - path = str; - - while (*str != ';' && *str != '\0') { - str++; - } - - i++; - - if (*str == ';') { - str++; - } else if (*str != '\0') { - - return(FALSE); - } - } - - if (i != 1) { - /* If innodb_log_group_home_dir was defined it must - contain exactly one path definition under current MySQL */ - - return(FALSE); - } - - srv_log_group_home_dirs = static_cast<char**>( - malloc(i * sizeof *srv_log_group_home_dirs)); - - /* Then store the actual values to our array */ - - str = input_str; - i = 0; - - while (*str != '\0') { - path = str; - - while (*str != ';' && *str != '\0') { - str++; - } - - if (*str == ';') { - *str = '\0'; - str++; - } - - srv_log_group_home_dirs[i] = path; - - i++; - } - - return(TRUE); -} - -/*********************************************************************//** Frees the memory allocated by srv_parse_data_file_paths_and_sizes() and srv_parse_log_group_home_dirs(). */ UNIV_INTERN @@ -462,8 +447,6 @@ srv_free_paths_and_sizes(void) srv_data_file_sizes = NULL; free(srv_data_file_is_raw_partition); srv_data_file_is_raw_partition = NULL; - free(srv_log_group_home_dirs); - srv_log_group_home_dirs = NULL; } #ifndef UNIV_HOTBACKUP @@ -526,175 +509,230 @@ srv_normalize_path_for_win( #ifndef UNIV_HOTBACKUP /*********************************************************************//** -Creates or opens the log files and closes them. +Creates a log file. @return DB_SUCCESS or error code */ -static -ulint -open_or_create_log_file( -/*====================*/ - ibool create_new_db, /*!< in: TRUE if we should create a - new database */ - ibool* log_file_created, /*!< out: TRUE if new log file - created */ - ibool log_file_has_been_opened,/*!< in: TRUE if a log file has been - opened before: then it is an error - to try to create another log file */ - ulint k, /*!< in: log group number */ - ulint i) /*!< in: log file number in group */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t +create_log_file( +/*============*/ + os_file_t* file, /*!< out: file handle */ + const char* name) /*!< in: log file name */ { ibool ret; - os_offset_t size; - char name[10000]; - ulint dirnamelen; - UT_NOT_USED(create_new_db); + *file = os_file_create( + innodb_file_log_key, name, + OS_FILE_CREATE, OS_FILE_NORMAL, OS_LOG_FILE, &ret); - *log_file_created = FALSE; + ib_logf(IB_LOG_LEVEL_INFO, + "Setting log file %s size to %lu MB", + name, (ulong) srv_log_file_size + >> (20 - UNIV_PAGE_SIZE_SHIFT)); - srv_normalize_path_for_win(srv_log_group_home_dirs[k]); + ret = os_file_set_size(name, *file, + (os_offset_t) srv_log_file_size + << UNIV_PAGE_SIZE_SHIFT); + if (!ret) { + ib_logf(IB_LOG_LEVEL_ERROR, "Error in creating %s", name); + return(DB_ERROR); + } - dirnamelen = strlen(srv_log_group_home_dirs[k]); - ut_a(dirnamelen < (sizeof name) - 10 - sizeof "ib_logfile"); - memcpy(name, srv_log_group_home_dirs[k], dirnamelen); + ret = os_file_close(*file); + ut_a(ret); - /* Add a path separator if needed. */ - if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { - name[dirnamelen++] = SRV_PATH_SEPARATOR; + return(DB_SUCCESS); +} + +/** Initial number of the first redo log file */ +#define INIT_LOG_FILE0 (SRV_N_LOG_FILES_MAX + 1) + +#ifdef DBUG_OFF +# define RECOVERY_CRASH(x) do {} while(0) +#else +# define RECOVERY_CRASH(x) do { \ + if (srv_force_recovery_crash == x) { \ + fprintf(stderr, "innodb_force_recovery_crash=%lu\n", \ + srv_force_recovery_crash); \ + fflush(stderr); \ + exit(3); \ + } \ +} while (0) +#endif + +/*********************************************************************//** +Creates all log files. +@return DB_SUCCESS or error code */ +static +dberr_t +create_log_files( +/*=============*/ + char* logfilename, /*!< in/out: buffer for log file name */ + size_t dirnamelen, /*!< in: length of the directory path */ + lsn_t lsn, /*!< in: FIL_PAGE_FILE_FLUSH_LSN value */ + char*& logfile0) /*!< out: name of the first log file */ +{ + if (srv_read_only_mode) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot create log files in read-only mode"); + return(DB_READ_ONLY); } - sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i); + /* Remove any old log files. */ + for (unsigned i = 0; i <= INIT_LOG_FILE0; i++) { + sprintf(logfilename + dirnamelen, "ib_logfile%u", i); - files[i] = os_file_create(innodb_file_log_key, name, - OS_FILE_CREATE, OS_FILE_NORMAL, - OS_LOG_FILE, &ret); - if (ret == FALSE) { - if (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 + /* Ignore errors about non-existent files or files + that cannot be removed. The create_log_file() will + return an error when the file exists. */ +#ifdef __WIN__ + DeleteFile((LPCTSTR) logfilename); +#else + unlink(logfilename); #endif - ) { - fprintf(stderr, - "InnoDB: Error in creating" - " or opening %s\n", name); + /* Crashing after deleting the first + file should be recoverable. The buffer + pool was clean, and we can simply create + all log files from the scratch. */ + RECOVERY_CRASH(6); + } - return(DB_ERROR); - } + ut_ad(!buf_pool_check_no_pending_io()); - files[i] = os_file_create(innodb_file_log_key, name, - OS_FILE_OPEN, OS_FILE_AIO, - OS_LOG_FILE, &ret); - if (!ret) { - fprintf(stderr, - "InnoDB: Error in opening %s\n", name); + RECOVERY_CRASH(7); - return(DB_ERROR); + for (unsigned i = 0; i < srv_n_log_files; i++) { + sprintf(logfilename + dirnamelen, + "ib_logfile%u", i ? i : INIT_LOG_FILE0); + + dberr_t err = create_log_file(&files[i], logfilename); + + if (err != DB_SUCCESS) { + return(err); } + } - size = os_file_get_size(files[i]); - ut_a(size != (os_offset_t) -1); + RECOVERY_CRASH(8); - if (UNIV_UNLIKELY(size != (os_offset_t) srv_log_file_size - << UNIV_PAGE_SIZE_SHIFT)) { + /* We did not create the first log file initially as + ib_logfile0, so that crash recovery cannot find it until it + has been completed and renamed. */ + sprintf(logfilename + dirnamelen, "ib_logfile%u", INIT_LOG_FILE0); - fprintf(stderr, - "InnoDB: Error: log file %s is" - " of different size "UINT64PF" bytes\n" - "InnoDB: than specified in the .cnf" - " file "UINT64PF" bytes!\n", - name, size, - (os_offset_t) srv_log_file_size - << UNIV_PAGE_SIZE_SHIFT); + fil_space_create( + logfilename, SRV_LOG_SPACE_FIRST_ID, + fsp_flags_set_page_size(0, UNIV_PAGE_SIZE), + FIL_LOG); + ut_a(fil_validate()); - return(DB_ERROR); + logfile0 = fil_node_create( + logfilename, (ulint) srv_log_file_size, + SRV_LOG_SPACE_FIRST_ID, FALSE); + ut_a(logfile0); + + for (unsigned i = 1; i < srv_n_log_files; i++) { + sprintf(logfilename + dirnamelen, "ib_logfile%u", i); + + if (!fil_node_create( + logfilename, + (ulint) srv_log_file_size, + SRV_LOG_SPACE_FIRST_ID, FALSE)) { + ut_error; } - } else { - *log_file_created = TRUE; + } - ut_print_timestamp(stderr); + log_group_init(0, srv_n_log_files, + srv_log_file_size * UNIV_PAGE_SIZE, + SRV_LOG_SPACE_FIRST_ID, + SRV_LOG_SPACE_FIRST_ID + 1); - fprintf(stderr, - " InnoDB: Log file %s did not exist:" - " new to be created\n", - name); - if (log_file_has_been_opened) { + fil_open_log_and_system_tablespace_files(); - return(DB_ERROR); - } + /* Create a log checkpoint. */ + mutex_enter(&log_sys->mutex); + ut_d(recv_no_log_write = FALSE); + recv_reset_logs(lsn); + mutex_exit(&log_sys->mutex); - fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n", - name, (ulong) srv_log_file_size - >> (20 - UNIV_PAGE_SIZE_SHIFT)); + return(DB_SUCCESS); +} - fprintf(stderr, - "InnoDB: Database physically writes the file" - " full: wait...\n"); +/*********************************************************************//** +Renames the first log file. */ +static +void +create_log_files_rename( +/*====================*/ + char* logfilename, /*!< in/out: buffer for log file name */ + size_t dirnamelen, /*!< in: length of the directory path */ + lsn_t lsn, /*!< in: FIL_PAGE_FILE_FLUSH_LSN value */ + char* logfile0) /*!< in/out: name of the first log file */ +{ + /* If innodb_flush_method=O_DSYNC, + we need to explicitly flush the log buffers. */ + fil_flush(SRV_LOG_SPACE_FIRST_ID); + /* Close the log files, so that we can rename + the first one. */ + fil_close_log_files(false); - ret = os_file_set_size(name, files[i], - (os_offset_t) srv_log_file_size - << UNIV_PAGE_SIZE_SHIFT); - if (!ret) { - fprintf(stderr, - "InnoDB: Error in creating %s:" - " probably out of disk space\n", - name); + /* Rename the first log file, now that a log + checkpoint has been created. */ + sprintf(logfilename + dirnamelen, "ib_logfile%u", 0); - return(DB_ERROR); - } - } + RECOVERY_CRASH(9); - ret = os_file_close(files[i]); - ut_a(ret); + ib_logf(IB_LOG_LEVEL_INFO, + "Renaming log file %s to %s", logfile0, logfilename); - if (i == 0) { - /* Create in memory the file space object - which is for this log group */ + mutex_enter(&log_sys->mutex); + ut_ad(strlen(logfile0) == 2 + strlen(logfilename)); + ibool success = os_file_rename( + innodb_file_log_key, logfile0, logfilename); + ut_a(success); - fil_space_create(name, - 2 * k + SRV_LOG_SPACE_FIRST_ID, - fsp_flags_set_page_size(0, UNIV_PAGE_SIZE), - FIL_LOG); - } + RECOVERY_CRASH(10); - ut_a(fil_validate()); + /* Replace the first file with ib_logfile0. */ + strcpy(logfile0, logfilename); + mutex_exit(&log_sys->mutex); - /* srv_log_file_size is measured in pages; if page size is 16KB, - then we have a limit of 64TB on 32 bit systems */ - ut_a(srv_log_file_size <= ULINT_MAX); + fil_open_log_and_system_tablespace_files(); - fil_node_create(name, (ulint) srv_log_file_size, - 2 * k + SRV_LOG_SPACE_FIRST_ID, FALSE); -#ifdef UNIV_LOG_ARCHIVE - /* If this is the first log group, create the file space object - for archived logs. - Under MySQL, no archiving ever done. */ + ib_logf(IB_LOG_LEVEL_WARN, "New log files created, LSN=" LSN_PF, lsn); +} - if (k == 0 && i == 0) { - arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID; +/*********************************************************************//** +Opens a log file. +@return DB_SUCCESS or error code */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t +open_log_file( +/*==========*/ + os_file_t* file, /*!< out: file handle */ + const char* name, /*!< in: log file name */ + os_offset_t* size) /*!< out: file size */ +{ + ibool ret; - fil_space_create("arch_log_space", arch_space_id, 0, FIL_LOG); - } else { - arch_space_id = ULINT_UNDEFINED; - } -#endif /* UNIV_LOG_ARCHIVE */ - if (i == 0) { - log_group_init(k, srv_n_log_files, - srv_log_file_size * UNIV_PAGE_SIZE, - 2 * k + SRV_LOG_SPACE_FIRST_ID, - SRV_LOG_SPACE_FIRST_ID + 1); /* dummy arch - space id */ + *file = os_file_create(innodb_file_log_key, name, + OS_FILE_OPEN, OS_FILE_AIO, + OS_LOG_FILE, &ret); + if (!ret) { + ib_logf(IB_LOG_LEVEL_ERROR, "Unable to open '%s'", name); + return(DB_ERROR); } + *size = os_file_get_size(*file); + + ret = os_file_close(*file); + ut_a(ret); return(DB_SUCCESS); } /*********************************************************************//** Creates or opens database data files and closes them. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t open_or_create_data_files( /*======================*/ ibool* create_new_db, /*!< out: TRUE if new database should be @@ -718,13 +756,16 @@ open_or_create_data_files( 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) { - fprintf(stderr, "InnoDB: can only have < 1000 data files\n" - "InnoDB: you have defined %lu\n", - (ulong) srv_n_data_files); + + ib_logf(IB_LOG_LEVEL_ERROR, + "Can only have < 1000 data files, you have " + "defined %lu", (ulong) srv_n_data_files); + return(DB_ERROR); } @@ -742,7 +783,9 @@ open_or_create_data_files( 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; @@ -750,46 +793,67 @@ open_or_create_data_files( strcpy(name + dirnamelen, srv_data_file_names[i]); - if (srv_data_file_is_raw_partition[i] == 0) { + /* 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); + 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; + } - if (ret == FALSE && os_file_get_last_error(FALSE) - != OS_FILE_ALREADY_EXISTS + 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 + /* 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 */ ) { - fprintf(stderr, - "InnoDB: Error in creating" - " or opening %s\n", + 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); + files[i] = os_file_create( + innodb_file_data_key, name, OS_FILE_OPEN_RAW, + OS_FILE_NORMAL, OS_DATA_FILE, &ret); + if (!ret) { - fprintf(stderr, - "InnoDB: Error in opening %s\n", name); + ib_logf(IB_LOG_LEVEL_ERROR, + "Error in opening %s", name); return(DB_ERROR); } @@ -805,17 +869,15 @@ open_or_create_data_files( /* We open the data file */ if (one_created) { - fprintf(stderr, - "InnoDB: Error: data files can only" - " be added at the end\n"); - fprintf(stderr, - "InnoDB: of a tablespace, but" - " data file %s existed beforehand.\n", + 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, @@ -833,9 +895,11 @@ open_or_create_data_files( } if (!ret) { - fprintf(stderr, - "InnoDB: Error in opening %s\n", name); - os_file_get_last_error(TRUE); + + os_file_get_last_error(true); + + ib_logf(IB_LOG_LEVEL_ERROR, + "Can't open '%s'", name); return(DB_ERROR); } @@ -845,6 +909,7 @@ open_or_create_data_files( 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 */ @@ -860,16 +925,16 @@ open_or_create_data_files( && srv_last_file_size_max < rounded_size_pages)) { - fprintf(stderr, - "InnoDB: Error: auto-extending" - " data file %s is" - " of a different size\n" - "InnoDB: %lu pages (rounded" - " down to MB) than specified" - " in the .cnf file:\n" - "InnoDB: initial %lu pages," - " max %lu (relevant if" - " non-zero) pages!\n", + 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], @@ -884,13 +949,11 @@ open_or_create_data_files( if (rounded_size_pages != srv_data_file_sizes[i]) { - fprintf(stderr, - "InnoDB: Error: data file %s" - " is of a different size\n" - "InnoDB: %lu pages" - " (rounded down to MB)\n" - "InnoDB: than specified" - " in the .cnf file %lu pages!\n", + 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]); @@ -899,63 +962,65 @@ open_or_create_data_files( } skip_size_check: fil_read_first_page( - files[i], one_opened, &flags, + 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)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: data file %s" - " uses page size %lu,\n", + 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)); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: but the start-up parameter" - " is innodb-page-size=%lu\n", + fsp_flags_get_page_size(flags), UNIV_PAGE_SIZE); return(DB_ERROR); } one_opened = TRUE; - } else { + } else if (!srv_read_only_mode) { /* We created the data file and now write it full of zeros */ one_created = TRUE; if (i > 0) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Data file %s did not" - " exist: new to be created\n", + ib_logf(IB_LOG_LEVEL_INFO, + "Data file %s did not" + " exist: new to be created", name); } else { - fprintf(stderr, - "InnoDB: The first specified" - " data file %s did not exist:\n" - "InnoDB: a new database" - " to be created!\n", name); + 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; } - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Setting file %s size to %lu MB\n", + 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))); - fprintf(stderr, - "InnoDB: Database physically writes the" - " file full: wait...\n"); + ib_logf(IB_LOG_LEVEL_INFO, + "Database physically writes the" + " file full: wait..."); ret = os_file_set_size( name, files[i], @@ -963,9 +1028,10 @@ skip_size_check: << UNIV_PAGE_SIZE_SHIFT); if (!ret) { - fprintf(stderr, - "InnoDB: Error in creating %s:" - " probably out of disk space\n", name); + ib_logf(IB_LOG_LEVEL_ERROR, + "Error in creating %s: " + "probably out of disk space", + name); return(DB_ERROR); } @@ -983,8 +1049,10 @@ skip_size_check: ut_a(fil_validate()); - fil_node_create(name, srv_data_file_sizes[i], 0, - srv_data_file_is_raw_partition[i] != 0); + 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); @@ -994,7 +1062,7 @@ skip_size_check: Create undo tablespace. @return DB_SUCCESS or error code */ static -enum db_err +dberr_t srv_undo_tablespace_create( /*=======================*/ const char* name, /*!< in: tablespace name */ @@ -1002,48 +1070,55 @@ srv_undo_tablespace_create( { os_file_t fh; ibool ret; - enum db_err err = DB_SUCCESS; + dberr_t err = DB_SUCCESS; os_file_create_subdirs_if_needed(name); fh = os_file_create( - innodb_file_data_key, name, OS_FILE_CREATE, + innodb_file_data_key, + name, + srv_read_only_mode ? OS_FILE_OPEN : OS_FILE_CREATE, OS_FILE_NORMAL, OS_DATA_FILE, &ret); - if (ret == FALSE - && os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS + if (srv_read_only_mode && ret) { + ib_logf(IB_LOG_LEVEL_INFO, + "%s opened in read-only mode", name); + } else if (ret == FALSE + && 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 + /* 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 */ ) { - fprintf(stderr, "InnoDB: Error in creating %s\n", name); + ib_logf(IB_LOG_LEVEL_ERROR, + "Can't create UNDO tablespace %s", name); err = DB_ERROR; } else { + ut_a(!srv_read_only_mode); + /* We created the data file and now write it full of zeros */ - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Data file %s did not" - " exist: new to be created\n", name); + ib_logf(IB_LOG_LEVEL_INFO, + "Data file %s did not exist: new to be created", + name); - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Setting file %s size to %lu MB\n", - name, size >> (20 - UNIV_PAGE_SIZE_SHIFT)); + ib_logf(IB_LOG_LEVEL_INFO, + "Setting file %s size to %lu MB", + name, size >> (20 - UNIV_PAGE_SIZE_SHIFT)); - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Database physically writes the" - " file full: wait...\n"); + ib_logf(IB_LOG_LEVEL_INFO, + "Database physically writes the file full: wait..."); ret = os_file_set_size(name, fh, size << UNIV_PAGE_SIZE_SHIFT); if (!ret) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error in creating %s:" - " probably out of disk space\n", name); + ib_logf(IB_LOG_LEVEL_INFO, + "Error in creating %s: probably out of " + "disk space", name); err = DB_ERROR; } @@ -1058,17 +1133,25 @@ srv_undo_tablespace_create( Open an undo tablespace. @return DB_SUCCESS or error code */ static -enum db_err +dberr_t srv_undo_tablespace_open( /*=====================*/ const char* name, /*!< in: tablespace name */ ulint space) /*!< in: tablespace id */ { os_file_t fh; - enum db_err err; + dberr_t err = DB_ERROR; ibool ret; ulint flags; + if (!srv_file_check_mode(name)) { + ib_logf(IB_LOG_LEVEL_ERROR, + "UNDO tablespaces must be %s!", + srv_read_only_mode ? "writable" : "readable"); + + return(DB_ERROR); + } + fh = os_file_create( innodb_file_data_key, name, OS_FILE_OPEN_RETRY @@ -1082,7 +1165,6 @@ srv_undo_tablespace_open( if (ret) { os_offset_t size; - os_offset_t n_pages; size = os_file_get_size(fh); ut_a(size != (os_offset_t) -1); @@ -1105,17 +1187,15 @@ srv_undo_tablespace_open( ut_a(fil_validate()); - n_pages = size / UNIV_PAGE_SIZE; + os_offset_t n_pages = size / UNIV_PAGE_SIZE; /* On 64 bit Windows ulint can be 32 bit and os_offset_t is 64 bit. It is OK to cast the n_pages to ulint because the unit has been scaled to pages and they are always 32 bit. */ - fil_node_create(name, (ulint) n_pages, space, FALSE); - - err = DB_SUCCESS; - } else { - err = DB_ERROR; + if (fil_node_create(name, (ulint) n_pages, space, FALSE)) { + err = DB_SUCCESS; + } } return(err); @@ -1125,20 +1205,25 @@ srv_undo_tablespace_open( Opens the configured number of undo tablespaces. @return DB_SUCCESS or error code */ static -enum db_err +dberr_t srv_undo_tablespaces_init( /*======================*/ ibool create_new_db, /*!< in: TRUE if new db being created */ - const ulint n_conf_tablespaces) /*!< in: configured undo + const ulint n_conf_tablespaces, /*!< in: configured undo tablespaces */ + ulint* n_opened) /*!< out: number of UNDO + tablespaces successfully + discovered and opened */ { ulint i; - enum db_err err = DB_SUCCESS; + dberr_t err = DB_SUCCESS; ulint prev_space_id = 0; ulint n_undo_tablespaces; ulint undo_tablespace_ids[TRX_SYS_N_RSEGS + 1]; + *n_opened = 0; + ut_a(n_conf_tablespaces <= TRX_SYS_N_RSEGS); memset(undo_tablespace_ids, 0x0, sizeof(undo_tablespace_ids)); @@ -1164,10 +1249,10 @@ srv_undo_tablespaces_init( name, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES); if (err != DB_SUCCESS) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Could not create " - "undo tablespace '%s'.\n", name); + + ib_logf(IB_LOG_LEVEL_ERROR, + "Could not create undo tablespace '%s'.", + name); return(err); } @@ -1217,15 +1302,16 @@ srv_undo_tablespaces_init( err = srv_undo_tablespace_open(name, undo_tablespace_ids[i]); if (err != DB_SUCCESS) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error opening undo " - "tablespace %s.\n", name); + + ib_logf(IB_LOG_LEVEL_ERROR, + "Unable to open undo tablespace '%s'.", name); return(err); } prev_space_id = undo_tablespace_ids[i]; + + ++*n_opened; } /* Open any extra unused undo tablespaces. These must be contiguous. @@ -1248,6 +1334,8 @@ srv_undo_tablespaces_init( } ++n_undo_tablespaces; + + ++*n_opened; } /* If the user says that there are fewer than what we find we @@ -1275,13 +1363,17 @@ srv_undo_tablespaces_init( "value is %lu\n", n_undo_tablespaces); return(err != DB_SUCCESS ? err : DB_ERROR); - } - if (n_undo_tablespaces > 0) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Opened %lu undo tablespaces\n", - n_conf_tablespaces); + } else if (n_undo_tablespaces > 0) { + + ib_logf(IB_LOG_LEVEL_INFO, "Opened %lu undo tablespaces", + n_undo_tablespaces); + + if (n_conf_tablespaces == 0) { + ib_logf(IB_LOG_LEVEL_WARN, + "Using the system tablespace for all UNDO " + "logging because innodb_undo_tablespaces=0"); + } } if (create_new_db) { @@ -1303,18 +1395,51 @@ srv_undo_tablespaces_init( } /******************************************************************** +Wait for the purge thread(s) to start up. */ +static +void +srv_start_wait_for_purge_to_start() +/*===============================*/ +{ + /* Wait for the purge coordinator and master thread to startup. */ + + purge_state_t state = trx_purge_state(); + + ut_a(state != PURGE_STATE_DISABLED); + + while (srv_shutdown_state == SRV_SHUTDOWN_NONE + && srv_force_recovery < SRV_FORCE_NO_BACKGROUND + && state == PURGE_STATE_INIT) { + + switch (state = trx_purge_state()) { + case PURGE_STATE_RUN: + case PURGE_STATE_STOP: + break; + + case PURGE_STATE_INIT: + ib_logf(IB_LOG_LEVEL_INFO, + "Waiting for purge to start"); + + os_thread_sleep(50000); + break; + + case PURGE_STATE_EXIT: + case PURGE_STATE_DISABLED: + ut_error; + } + } +} + +/******************************************************************** Starts InnoDB and creates a new database if database files are not found and the user wants. @return DB_SUCCESS or error code */ UNIV_INTERN -int +dberr_t innobase_start_or_create_for_mysql(void) /*====================================*/ { ibool create_new_db; - ibool log_file_created; - ibool log_created = FALSE; - ibool log_opened = FALSE; lsn_t min_flushed_lsn; lsn_t max_flushed_lsn; #ifdef UNIV_LOG_ARCHIVE @@ -1324,11 +1449,19 @@ innobase_start_or_create_for_mysql(void) ulint sum_of_new_sizes; ulint sum_of_data_file_sizes; ulint tablespace_size_in_header; - ulint err; - ulint i; + dberr_t err; + unsigned i; + ulint srv_n_log_files_found = srv_n_log_files; ulint io_limit; mtr_t mtr; ib_bh_t* ib_bh; + char logfilename[10000]; + char* logfile0 = NULL; + size_t dirnamelen; + + if (srv_read_only_mode) { + ib_logf(IB_LOG_LEVEL_INFO, "Started in read only mode"); + } #ifdef HAVE_DARWIN_THREADS # ifdef F_FULLFSYNC @@ -1422,31 +1555,34 @@ innobase_start_or_create_for_mysql(void) " InnoDB: !!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!\n"); #endif - if (UNIV_LIKELY(srv_use_sys_malloc)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: The InnoDB memory heap is disabled\n"); + if (srv_use_sys_malloc) { + ib_logf(IB_LOG_LEVEL_INFO, + "The InnoDB memory heap is disabled"); } #if defined(COMPILER_HINTS_ENABLED) - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Compiler hints enabled.\n"); + ib_logf(IB_LOG_LEVEL_INFO, + " InnoDB: Compiler hints enabled."); #endif /* defined(COMPILER_HINTS_ENABLED) */ - ut_print_timestamp(stderr); - fputs(" InnoDB: " IB_ATOMICS_STARTUP_MSG "\n", stderr); + ib_logf(IB_LOG_LEVEL_INFO, + "" IB_ATOMICS_STARTUP_MSG ""); - ut_print_timestamp(stderr); - fputs(" InnoDB: Compressed tables use zlib " ZLIB_VERSION + ib_logf(IB_LOG_LEVEL_INFO, + "Compressed tables use zlib " ZLIB_VERSION #ifdef UNIV_ZIP_DEBUG " with validation" #endif /* UNIV_ZIP_DEBUG */ - "\n" , stderr); + ); #ifdef UNIV_ZIP_COPY - ut_print_timestamp(stderr); - fputs(" InnoDB: and extra copying\n", stderr); + ib_logf(IB_LOG_LEVEL_INFO, "and extra copying"); #endif /* UNIV_ZIP_COPY */ + + ib_logf(IB_LOG_LEVEL_INFO, + "CPU %s crc32 instructions", + ut_crc32_sse2_enabled ? "supports" : "does not support"); + /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we print an error message if someone tries to start up InnoDB a @@ -1505,17 +1641,14 @@ innobase_start_or_create_for_mysql(void) #elif defined(LINUX_NATIVE_AIO) if (srv_use_native_aio) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Using Linux native AIO\n"); + ib_logf(IB_LOG_LEVEL_INFO, "Using Linux native AIO"); } #else /* Currently native AIO is supported only on windows and linux and that also when the support is compiled in. In all other cases, we ignore the setting of innodb_use_native_aio. */ srv_use_native_aio = FALSE; - -#endif +#endif /* __WIN__ */ if (srv_file_flush_method_str == NULL) { /* These are the default options */ @@ -1533,6 +1666,9 @@ innobase_start_or_create_for_mysql(void) } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DIRECT")) { srv_unix_file_flush_method = SRV_UNIX_O_DIRECT; + } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DIRECT_NO_FSYNC")) { + srv_unix_file_flush_method = SRV_UNIX_O_DIRECT_NO_FSYNC; + } else if (0 == ut_strcmp(srv_file_flush_method_str, "littlesync")) { srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC; @@ -1550,12 +1686,10 @@ innobase_start_or_create_for_mysql(void) } else if (0 == ut_strcmp(srv_file_flush_method_str, "async_unbuffered")) { srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; -#endif +#endif /* __WIN__ */ } else { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Unrecognized value %s for" - " innodb_flush_method\n", + ib_logf(IB_LOG_LEVEL_ERROR, + "Unrecognized value %s for innodb_flush_method", srv_file_flush_method_str); return(DB_ERROR); } @@ -1580,74 +1714,93 @@ innobase_start_or_create_for_mysql(void) srv_max_n_threads = 10000; } else { srv_buf_pool_instances = 1; - srv_max_n_threads = 1000; /* saves several MB of memory, - especially in 64-bit - computers */ + + /* Saves several MB of memory, especially in + 64-bit computers */ + + srv_max_n_threads = 1000; } - err = srv_boot(); + srv_boot(); - if (err != DB_SUCCESS) { + if (!srv_read_only_mode) { - return((int) err); - } + mutex_create(srv_monitor_file_mutex_key, + &srv_monitor_file_mutex, SYNC_NO_ORDER_CHECK); - mutex_create(srv_monitor_file_mutex_key, - &srv_monitor_file_mutex, SYNC_NO_ORDER_CHECK); + if (srv_innodb_status) { - if (srv_innodb_status) { + srv_monitor_file_name = static_cast<char*>( + mem_alloc( + strlen(fil_path_to_mysql_datadir) + + 20 + sizeof "/innodb_status.")); - srv_monitor_file_name = static_cast<char*>( - mem_alloc( - strlen(fil_path_to_mysql_datadir) - + 20 + sizeof "/innodb_status.")); + sprintf(srv_monitor_file_name, "%s/innodb_status.%lu", + fil_path_to_mysql_datadir, + os_proc_get_number()); - sprintf(srv_monitor_file_name, "%s/innodb_status.%lu", - fil_path_to_mysql_datadir, os_proc_get_number()); - srv_monitor_file = fopen(srv_monitor_file_name, "w+"); - if (!srv_monitor_file) { - fprintf(stderr, "InnoDB: unable to create %s: %s\n", - srv_monitor_file_name, strerror(errno)); - return(DB_ERROR); + srv_monitor_file = fopen(srv_monitor_file_name, "w+"); + + if (!srv_monitor_file) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Unable to create %s: %s", + srv_monitor_file_name, + strerror(errno)); + + return(DB_ERROR); + } + } else { + srv_monitor_file_name = NULL; + srv_monitor_file = os_file_create_tmpfile(); + + if (!srv_monitor_file) { + return(DB_ERROR); + } } - } else { - srv_monitor_file_name = NULL; - srv_monitor_file = os_file_create_tmpfile(); - if (!srv_monitor_file) { + + mutex_create(srv_dict_tmpfile_mutex_key, + &srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION); + + srv_dict_tmpfile = os_file_create_tmpfile(); + + if (!srv_dict_tmpfile) { return(DB_ERROR); } - } - mutex_create(srv_dict_tmpfile_mutex_key, - &srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION); + mutex_create(srv_misc_tmpfile_mutex_key, + &srv_misc_tmpfile_mutex, SYNC_ANY_LATCH); - srv_dict_tmpfile = os_file_create_tmpfile(); - if (!srv_dict_tmpfile) { - return(DB_ERROR); - } + srv_misc_tmpfile = os_file_create_tmpfile(); - mutex_create(srv_misc_tmpfile_mutex_key, - &srv_misc_tmpfile_mutex, SYNC_ANY_LATCH); - - srv_misc_tmpfile = os_file_create_tmpfile(); - if (!srv_misc_tmpfile) { - return(DB_ERROR); + if (!srv_misc_tmpfile) { + return(DB_ERROR); + } } /* If user has set the value of innodb_file_io_threads then we'll emit a message telling the user that this parameter is now deprecated. */ if (srv_n_file_io_threads != 4) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Warning:" - " innodb_file_io_threads is deprecated." - " Please use innodb_read_io_threads and" - " innodb_write_io_threads instead\n"); + ib_logf(IB_LOG_LEVEL_WARN, + "innodb_file_io_threads is deprecated. Please use " + "innodb_read_io_threads and innodb_write_io_threads " + "instead"); } /* Now overwrite the value on srv_n_file_io_threads */ - srv_n_file_io_threads = 2 + srv_n_read_io_threads - + srv_n_write_io_threads; + srv_n_file_io_threads = srv_n_read_io_threads; + + if (!srv_read_only_mode) { + /* Add the log and ibuf IO threads. */ + srv_n_file_io_threads += 2; + srv_n_file_io_threads += srv_n_write_io_threads; + } else { + ib_logf(IB_LOG_LEVEL_INFO, + "Disabling background IO write threads."); + + srv_n_write_io_threads = 0; + } ut_a(srv_n_file_io_threads <= SRV_MAX_N_IO_THREADS); @@ -1662,56 +1815,59 @@ innobase_start_or_create_for_mysql(void) } # endif /* __WIN__ */ - os_aio_init(io_limit, - srv_n_read_io_threads, - srv_n_write_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + if (!os_aio_init(io_limit, + srv_n_read_io_threads, + srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS)) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Fatal : Cannot initialize AIO sub-system"); + + return(DB_ERROR); + } fil_init(srv_file_per_table ? 50000 : 5000, srv_max_n_open_files); - /* Print time to initialize the buffer pool */ - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Initializing buffer pool, size ="); + double size; + char unit; if (srv_buf_pool_size >= 1024 * 1024 * 1024) { - fprintf(stderr, - " %.1fG\n", - ((double) srv_buf_pool_size) / (1024 * 1024 * 1024)); + size = ((double) srv_buf_pool_size) / (1024 * 1024 * 1024); + unit = 'G'; } else { - fprintf(stderr, - " %.1fM\n", - ((double) srv_buf_pool_size) / (1024 * 1024)); + size = ((double) srv_buf_pool_size) / (1024 * 1024); + unit = 'M'; } - err = buf_pool_init(srv_buf_pool_size, srv_buf_pool_instances); + /* Print time to initialize the buffer pool */ + ib_logf(IB_LOG_LEVEL_INFO, + "Initializing buffer pool, size = %.1f%c", size, unit); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Completed initialization of buffer pool\n"); + err = buf_pool_init(srv_buf_pool_size, srv_buf_pool_instances); if (err != DB_SUCCESS) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Fatal error: cannot allocate memory" - " for the buffer pool\n"); + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot allocate memory for the buffer pool"); return(DB_ERROR); } + ib_logf(IB_LOG_LEVEL_INFO, + "Completed initialization of buffer pool"); + #ifdef UNIV_DEBUG /* We have observed deadlocks with a 5MB buffer pool but the actual lower limit could very well be a little higher. */ if (srv_buf_pool_size <= 5 * 1024 * 1024) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Warning: Small buffer pool size " - "(%luM), the flst_validate() debug function " - "can cause a deadlock if the buffer pool fills up.\n", + ib_logf(IB_LOG_LEVEL_INFO, + "Small buffer pool size (%luM), the flst_validate() " + "debug function can cause a deadlock if the " + "buffer pool fills up.", srv_buf_pool_size / 1024 / 1024); } -#endif +#endif /* UNIV_DEBUG */ fsp_init(); log_init(); @@ -1720,14 +1876,15 @@ innobase_start_or_create_for_mysql(void) /* Create i/o-handler threads: */ - for (i = 0; i < srv_n_file_io_threads; i++) { + for (ulint i = 0; i < srv_n_file_io_threads; ++i) { + n[i] = i; os_thread_create(io_handler_thread, n + i, thread_ids + i); } #ifdef UNIV_LOG_ARCHIVE - if (0 != ut_strcmp(srv_log_group_home_dirs[0], srv_arch_dir)) { + if (0 != ut_strcmp(srv_log_group_home_dir, srv_arch_dir)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error: you must set the log group home dir in my.cnf\n"); ut_print_timestamp(stderr); @@ -1738,16 +1895,14 @@ innobase_start_or_create_for_mysql(void) #endif /* UNIV_LOG_ARCHIVE */ if (srv_n_log_files * srv_log_file_size * UNIV_PAGE_SIZE - >= 549755813888ULL /* 512G */) { + >= 512ULL * 1024ULL * 1024ULL * 1024ULL) { /* log_block_convert_lsn_to_no() limits the returned block number to 1G and given that OS_FILE_LOG_BLOCK_SIZE is 512 bytes, then we have a limit of 512 GB. If that limit is to be raised, then log_block_convert_lsn_to_no() must be modified. */ - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: combined size of log files" - " must be < 512 GB\n"); + ib_logf(IB_LOG_LEVEL_ERROR, + "Combined size of log files must be < 512 GB"); return(DB_ERROR); } @@ -1759,7 +1914,6 @@ innobase_start_or_create_for_mysql(void) So next_offset must be < ULINT_MAX * UNIV_PAGE_SIZE. This means that we are limited to ULINT_MAX * UNIV_PAGE_SIZE which is 64 TB on 32 bit systems. */ - ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error: combined size of log files" " must be < %lu GB\n", @@ -1791,10 +1945,8 @@ innobase_start_or_create_for_mysql(void) } if (sum_of_new_sizes < 10485760 / UNIV_PAGE_SIZE) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: tablespace size must be" - " at least 10 MB\n"); + ib_logf(IB_LOG_LEVEL_ERROR, + "Tablespace size must be at least 10 MB"); return(DB_ERROR); } @@ -1805,36 +1957,27 @@ innobase_start_or_create_for_mysql(void) #endif /* UNIV_LOG_ARCHIVE */ &min_flushed_lsn, &max_flushed_lsn, &sum_of_new_sizes); - if (err != DB_SUCCESS) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Could not open or create data files.\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: If you tried to add new data files," - " and it failed here,\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: you should now edit innodb_data_file_path" - " in my.cnf back\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: to what it was, and remove the" - " new ibdata files InnoDB created\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: in this failed attempt. InnoDB only wrote" - " those files full of\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: zeros, but did not yet use them in any way." - " But be careful: do not\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: remove old data files" - " which contain your precious data!\n"); + if (err == DB_FAIL) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "The system tablespace must be writable!"); + + return(DB_ERROR); - return((int) err); + } else if (err != DB_SUCCESS) { + + ib_logf(IB_LOG_LEVEL_ERROR, + "Could not open or create the system tablespace. If " + "you tried to add new data files to the system " + "tablespace, and it failed here, you should now " + "edit innodb_data_file_path in my.cnf back to what " + "it was, and remove the new ibdata files InnoDB " + "created in this failed attempt. InnoDB only wrote " + "those files full of zeros, but did not yet use " + "them in any way. But be careful: do not remove " + "old data files which contain your precious data!"); + + return(err); } #ifdef UNIV_LOG_ARCHIVE @@ -1842,125 +1985,199 @@ innobase_start_or_create_for_mysql(void) srv_arch_dir = srv_add_path_separator_if_needed(srv_arch_dir); #endif /* UNIV_LOG_ARCHIVE */ - for (i = 0; i < srv_n_log_files; i++) { - err = open_or_create_log_file(create_new_db, &log_file_created, - log_opened, 0, i); - if (err != DB_SUCCESS) { + dirnamelen = strlen(srv_log_group_home_dir); + ut_a(dirnamelen < (sizeof logfilename) - 10 - sizeof "ib_logfile"); + memcpy(logfilename, srv_log_group_home_dir, dirnamelen); - return((int) err); - } + /* Add a path separator if needed. */ + if (dirnamelen && logfilename[dirnamelen - 1] != SRV_PATH_SEPARATOR) { + logfilename[dirnamelen++] = SRV_PATH_SEPARATOR; + } - if (log_file_created) { - log_created = TRUE; - } else { - log_opened = TRUE; + srv_log_file_size_requested = srv_log_file_size; + + if (create_new_db) { + bool success = buf_flush_list(ULINT_MAX, LSN_MAX, NULL); + ut_a(success); + + min_flushed_lsn = max_flushed_lsn = log_get_lsn(); + + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + + err = create_log_files(logfilename, dirnamelen, + max_flushed_lsn, logfile0); + + if (err != DB_SUCCESS) { + return(err); } - if ((log_opened && create_new_db) - || (log_opened && log_created)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: all log files must be" - " created at the same time.\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: All log files must be" - " created also in database creation.\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: If you want bigger or smaller" - " log files, shut down the\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: database and make sure there" - " were no errors in shutdown.\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Then delete the existing log files." - " Edit the .cnf file\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: and start the database again.\n"); + } else { + for (i = 0; i < SRV_N_LOG_FILES_MAX; i++) { + os_offset_t size; + os_file_stat_t stat_info; + + sprintf(logfilename + dirnamelen, + "ib_logfile%u", i); + + err = os_file_get_status( + logfilename, &stat_info, false); + + if (err == DB_NOT_FOUND) { + if (i == 0) { + if (max_flushed_lsn + != min_flushed_lsn) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot create" + " log files because" + " data files are" + " corrupt or" + " not in sync" + " with each other"); + return(DB_ERROR); + } + + if (max_flushed_lsn < (lsn_t) 1000) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot create" + " log files because" + " data files are" + " corrupt or the" + " database was not" + " shut down cleanly" + " after creating" + " the data files."); + return(DB_ERROR); + } + + err = create_log_files( + logfilename, dirnamelen, + max_flushed_lsn, logfile0); + + if (err != DB_SUCCESS) { + return(err); + } + + create_log_files_rename( + logfilename, dirnamelen, + max_flushed_lsn, logfile0); + + /* Suppress the message about + crash recovery. */ + max_flushed_lsn = min_flushed_lsn + = log_get_lsn(); + goto files_checked; + } else if (i < 2) { + /* must have at least 2 log files */ + ib_logf(IB_LOG_LEVEL_ERROR, + "Only one log file found."); + return(err); + } - return(DB_ERROR); + /* opened all files */ + break; + } + + if (!srv_file_check_mode(logfilename)) { + return(DB_ERROR); + } + + err = open_log_file(&files[i], logfilename, &size); + + if (err != DB_SUCCESS) { + return(err); + } + + ut_a(size != (os_offset_t) -1); + + if (size & ((1 << UNIV_PAGE_SIZE_SHIFT) - 1)) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Log file %s size " + UINT64PF " is not a multiple of" + " innodb_page_size", + logfilename, size); + return(DB_ERROR); + } + + size >>= UNIV_PAGE_SIZE_SHIFT; + + if (i == 0) { + srv_log_file_size = size; + } else if (size != srv_log_file_size) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Log file %s is" + " of different size "UINT64PF" bytes" + " than other log" + " files "UINT64PF" bytes!", + logfilename, + size << UNIV_PAGE_SIZE_SHIFT, + (os_offset_t) srv_log_file_size + << UNIV_PAGE_SIZE_SHIFT); + return(DB_ERROR); + } } - } - /* Open all log files and data files in the system tablespace: we - keep them open until database shutdown */ + srv_n_log_files_found = i; - fil_open_log_and_system_tablespace_files(); + /* Create the in-memory file space objects. */ - err = srv_undo_tablespaces_init(create_new_db, srv_undo_tablespaces); + sprintf(logfilename + dirnamelen, "ib_logfile%u", 0); - /* If the force recovery is set very high then we carry on regardless - of all errors. Basically this is fingers crossed mode. */ + fil_space_create(logfilename, + SRV_LOG_SPACE_FIRST_ID, + fsp_flags_set_page_size(0, UNIV_PAGE_SIZE), + FIL_LOG); - if (err != DB_SUCCESS - && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) { + ut_a(fil_validate()); - return((int) err); - } + /* srv_log_file_size is measured in pages; if page size is 16KB, + then we have a limit of 64TB on 32 bit systems */ + ut_a(srv_log_file_size <= ULINT_MAX); + + for (unsigned j = 0; j < i; j++) { + sprintf(logfilename + dirnamelen, "ib_logfile%u", j); + + if (!fil_node_create(logfilename, + (ulint) srv_log_file_size, + SRV_LOG_SPACE_FIRST_ID, FALSE)) { + return(DB_ERROR); + } + } - if (log_created && !create_new_db -#ifdef UNIV_LOG_ARCHIVE - && !srv_archive_recovery -#endif /* UNIV_LOG_ARCHIVE */ - ) { - if (max_flushed_lsn != min_flushed_lsn #ifdef UNIV_LOG_ARCHIVE - || max_arch_log_no != min_arch_log_no + /* Create the file space object for archived logs. Under + MySQL, no archiving ever done. */ + fil_space_create("arch_log_space", SRV_LOG_SPACE_FIRST_ID + 1, + 0, FIL_LOG); #endif /* UNIV_LOG_ARCHIVE */ - ) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Cannot initialize created" - " log files because\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: data files were not in sync" - " with each other\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: or the data files are corrupt.\n"); + log_group_init(0, i, srv_log_file_size * UNIV_PAGE_SIZE, + SRV_LOG_SPACE_FIRST_ID, + SRV_LOG_SPACE_FIRST_ID + 1); + } - return(DB_ERROR); - } +files_checked: + /* Open all log files and data files in the system + tablespace: we keep them open until database + shutdown */ - if (max_flushed_lsn < (lsn_t) 1000) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Cannot initialize created" - " log files because\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: data files are corrupt," - " or new data files were\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: created when the database" - " was started previous\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: time but the database" - " was not shut down\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: normally after that.\n"); + fil_open_log_and_system_tablespace_files(); - return(DB_ERROR); - } + err = srv_undo_tablespaces_init( + create_new_db, + srv_undo_tablespaces, + &srv_undo_tablespaces_open); - mutex_enter(&(log_sys->mutex)); + /* If the force recovery is set very high then we carry on regardless + of all errors. Basically this is fingers crossed mode. */ -#ifdef UNIV_LOG_ARCHIVE - /* Do not + 1 arch_log_no because we do not use log - archiving */ - recv_reset_logs(max_flushed_lsn, max_arch_log_no, TRUE); -#else - recv_reset_logs(max_flushed_lsn, TRUE); -#endif /* UNIV_LOG_ARCHIVE */ + if (err != DB_SUCCESS + && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) { - mutex_exit(&(log_sys->mutex)); + return(err); + } + + /* Initialize objects used by dict stats gathering thread, which + can also be used by recovery if it tries to drop some table */ + if (!srv_read_only_mode) { + dict_stats_thread_init(); } trx_sys_file_format_init(); @@ -1968,6 +2185,9 @@ innobase_start_or_create_for_mysql(void) trx_sys_create(); if (create_new_db) { + + ut_a(!srv_read_only_mode); + mtr_start(&mtr); fsp_header_init(0, sum_of_new_sizes, &mtr); @@ -1987,16 +2207,34 @@ innobase_start_or_create_for_mysql(void) trx_purge_sys_create(srv_n_purge_threads, ib_bh); - dict_create(); + err = dict_create(); + + if (err != DB_SUCCESS) { + return(err); + } srv_startup_is_before_trx_rollback_phase = FALSE; + bool success = buf_flush_list(ULINT_MAX, LSN_MAX, NULL); + ut_a(success); + + min_flushed_lsn = max_flushed_lsn = log_get_lsn(); + + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + + /* Stamp the LSN to the data files. */ + fil_write_flushed_lsn_to_data_files(max_flushed_lsn, 0); + + fil_flush_file_spaces(FIL_TABLESPACE); + + create_log_files_rename(logfilename, dirnamelen, + max_flushed_lsn, logfile0); #ifdef UNIV_LOG_ARCHIVE } else if (srv_archive_recovery) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Starting archive" - " recovery from a backup...\n"); + + ib_logf(IB_LOG_LEVEL_INFO, + " Starting archive recovery from a backup..."); + err = recv_recovery_from_archive_start( min_flushed_lsn, srv_archive_recovery_limit_lsn, min_arch_log_no); @@ -2007,7 +2245,11 @@ innobase_start_or_create_for_mysql(void) /* Since ibuf init is in dict_boot, and ibuf is needed in any disk i/o, first call dict_boot */ - dict_boot(); + err = dict_boot(); + + if (err != DB_SUCCESS) { + return(err); + } ib_bh = trx_sys_init_at_db_start(); @@ -2051,10 +2293,10 @@ innobase_start_or_create_for_mysql(void) /* We always try to do a recovery, even if the database had been shut down normally: this is the normal startup path */ - err = recv_recovery_from_checkpoint_start(LOG_CHECKPOINT, - IB_ULONGLONG_MAX, - min_flushed_lsn, - max_flushed_lsn); + err = recv_recovery_from_checkpoint_start( + LOG_CHECKPOINT, IB_ULONGLONG_MAX, + min_flushed_lsn, max_flushed_lsn); + if (err != DB_SUCCESS) { return(DB_ERROR); @@ -2066,7 +2308,11 @@ innobase_start_or_create_for_mysql(void) to access space 0, and the insert buffer at this stage already works for space 0. */ - dict_boot(); + err = dict_boot(); + + if (err != DB_SUCCESS) { + return(err); + } ib_bh = trx_sys_init_at_db_start(); @@ -2079,6 +2325,7 @@ innobase_start_or_create_for_mysql(void) are initialized in trx_sys_init_at_db_start(). */ recv_recovery_from_checkpoint_finish(); + if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) { /* The following call is necessary for the insert buffer to work with multiple tablespaces. We must @@ -2100,6 +2347,90 @@ innobase_start_or_create_for_mysql(void) recv_needed_recovery); } + if (!srv_force_recovery + && !recv_sys->found_corrupt_log + && (srv_log_file_size_requested != srv_log_file_size + || srv_n_log_files_found != srv_n_log_files)) { + /* Prepare to replace the redo log files. */ + + if (srv_read_only_mode) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot resize log files " + "in read-only mode."); + return(DB_READ_ONLY); + } + + /* Clean the buffer pool. */ + bool success = buf_flush_list( + ULINT_MAX, LSN_MAX, NULL); + ut_a(success); + + RECOVERY_CRASH(1); + + min_flushed_lsn = max_flushed_lsn = log_get_lsn(); + + ib_logf(IB_LOG_LEVEL_WARN, + "Resizing redo log from %u*%u to %u*%u pages" + ", LSN=" LSN_PF, + (unsigned) i, + (unsigned) srv_log_file_size, + (unsigned) srv_n_log_files, + (unsigned) srv_log_file_size_requested, + max_flushed_lsn); + + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + + RECOVERY_CRASH(2); + + /* Flush the old log files. */ + log_buffer_flush_to_disk(); + /* If innodb_flush_method=O_DSYNC, + we need to explicitly flush the log buffers. */ + fil_flush(SRV_LOG_SPACE_FIRST_ID); + + ut_ad(max_flushed_lsn == log_get_lsn()); + + /* Prohibit redo log writes from any other + threads until creating a log checkpoint at the + end of create_log_files(). */ + ut_d(recv_no_log_write = TRUE); + ut_ad(!buf_pool_check_no_pending_io()); + + RECOVERY_CRASH(3); + + /* Stamp the LSN to the data files. */ + fil_write_flushed_lsn_to_data_files( + max_flushed_lsn, 0); + + fil_flush_file_spaces(FIL_TABLESPACE); + + RECOVERY_CRASH(4); + + /* Close and free the redo log files, so that + we can replace them. */ + fil_close_log_files(true); + + RECOVERY_CRASH(5); + + /* Free the old log file space. */ + log_group_close_all(); + + ib_logf(IB_LOG_LEVEL_WARN, + "Starting to delete and rewrite log files."); + + srv_log_file_size = srv_log_file_size_requested; + + err = create_log_files(logfilename, dirnamelen, + max_flushed_lsn, logfile0); + + if (err != DB_SUCCESS) { + return(err); + } + + create_log_files_rename(logfilename, dirnamelen, + max_flushed_lsn, logfile0); + } + srv_startup_is_before_trx_rollback_phase = FALSE; recv_recovery_rollback_active(); @@ -2181,31 +2512,39 @@ innobase_start_or_create_for_mysql(void) if (srv_available_undo_logs == ULINT_UNDEFINED) { /* Can only happen if force recovery is set. */ - ut_a(srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); + ut_a(srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO + || srv_read_only_mode); srv_undo_logs = ULONG_UNDEFINED; } - /* Create the thread which watches the timeouts for lock waits */ - os_thread_create( - lock_wait_timeout_thread, - NULL, thread_ids + 2 + SRV_MAX_N_IO_THREADS); - - /* Create the thread which warns of long semaphore waits */ - os_thread_create( - srv_error_monitor_thread, - NULL, thread_ids + 3 + SRV_MAX_N_IO_THREADS); + if (!srv_read_only_mode) { + /* Create the thread which watches the timeouts + for lock waits */ + os_thread_create( + lock_wait_timeout_thread, + NULL, thread_ids + 2 + SRV_MAX_N_IO_THREADS); - /* Create the thread which prints InnoDB monitor info */ - os_thread_create( - srv_monitor_thread, - NULL, thread_ids + 4 + SRV_MAX_N_IO_THREADS); + /* Create the thread which warns of long semaphore waits */ + os_thread_create( + srv_error_monitor_thread, + NULL, thread_ids + 3 + SRV_MAX_N_IO_THREADS); - srv_is_being_started = FALSE; + /* Create the thread which prints InnoDB monitor info */ + os_thread_create( + srv_monitor_thread, + NULL, thread_ids + 4 + SRV_MAX_N_IO_THREADS); + } /* Create the SYS_FOREIGN and SYS_FOREIGN_COLS system tables */ err = dict_create_or_check_foreign_constraint_tables(); if (err != DB_SUCCESS) { - return((int)DB_ERROR); + return(err); + } + + /* Create the SYS_TABLESPACES system table */ + err = dict_create_or_check_sys_tablespace(); + if (err != DB_SUCCESS) { + return(err); } srv_is_being_started = FALSE; @@ -2215,11 +2554,15 @@ innobase_start_or_create_for_mysql(void) /* Create the master thread which does purge and other utility operations */ - os_thread_create( - srv_master_thread, - NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS)); + if (!srv_read_only_mode) { + + os_thread_create( + srv_master_thread, + NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS)); + } - if (srv_force_recovery < SRV_FORCE_NO_BACKGROUND) { + if (!srv_read_only_mode + && srv_force_recovery < SRV_FORCE_NO_BACKGROUND) { os_thread_create( srv_purge_coordinator_thread, @@ -2234,35 +2577,15 @@ innobase_start_or_create_for_mysql(void) srv_worker_thread, NULL, thread_ids + 5 + i + SRV_MAX_N_IO_THREADS); } - } - - os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL); - - /* Wait for the purge coordinator and master thread to startup. */ - - purge_state_t state = trx_purge_state(); - while (srv_shutdown_state == SRV_SHUTDOWN_NONE - && srv_force_recovery < SRV_FORCE_NO_BACKGROUND - && state == PURGE_STATE_INIT) { - - switch (state = trx_purge_state()) { - case PURGE_STATE_RUN: - case PURGE_STATE_STOP: - break; - - case PURGE_STATE_INIT: - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: " - "Waiting for the background threads to " - "start\n"); + srv_start_wait_for_purge_to_start(); - os_thread_sleep(50000); - break; + } else { + purge_sys->state = PURGE_STATE_DISABLED; + } - case PURGE_STATE_EXIT: - ut_error; - } + if (!srv_read_only_mode) { + os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL); } #ifdef UNIV_DEBUG @@ -2276,7 +2599,8 @@ innobase_start_or_create_for_mysql(void) tablespace_size_in_header = fsp_header_get_tablespace_size(); - if (!srv_auto_extend_last_data_file + if (!srv_read_only_mode + && !srv_auto_extend_last_data_file && sum_of_data_file_sizes != tablespace_size_in_header) { ut_print_timestamp(stderr); @@ -2319,7 +2643,8 @@ innobase_start_or_create_for_mysql(void) } } - if (srv_auto_extend_last_data_file + if (!srv_read_only_mode + && srv_auto_extend_last_data_file && sum_of_data_file_sizes < tablespace_size_in_header) { ut_print_timestamp(stderr); @@ -2383,23 +2708,17 @@ innobase_start_or_create_for_mysql(void) os_fast_mutex_free(&srv_os_test_mutex); if (srv_print_verbose_log) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: %s started; " - "log sequence number " LSN_PF "\n", + ib_logf(IB_LOG_LEVEL_INFO, + "%s started; log sequence number " LSN_PF "", INNODB_VERSION_STR, srv_start_lsn); } if (srv_force_recovery > 0) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: !!! innodb_force_recovery" - " is set to %lu !!!\n", + ib_logf(IB_LOG_LEVEL_INFO, + "!!! innodb_force_recovery is set to %lu !!!", (ulong) srv_force_recovery); } - fflush(stderr); - if (srv_force_recovery == 0) { /* In the insert buffer we may have even bigger tablespace id's, because we may have dropped those tablespaces, but @@ -2409,16 +2728,20 @@ innobase_start_or_create_for_mysql(void) ibuf_update_max_tablespace_id(); } - /* Create the buffer pool dump/load thread */ - os_thread_create(buf_dump_thread, NULL, NULL); + if (!srv_read_only_mode) { + /* Create the buffer pool dump/load thread */ + os_thread_create(buf_dump_thread, NULL, NULL); - srv_was_started = TRUE; + /* Create the dict stats gathering thread */ + os_thread_create(dict_stats_thread, NULL, NULL); - /* Create the thread that will optimize the FTS sub-system - in a separate background thread. */ - fts_optimize_init(); + /* Create the thread that will optimize the FTS sub-system. */ + fts_optimize_init(); + } - return((int) DB_SUCCESS); + srv_was_started = TRUE; + + return(DB_SUCCESS); } #if 0 @@ -2455,27 +2778,28 @@ srv_fts_close(void) Shuts down the InnoDB database. @return DB_SUCCESS or error code */ UNIV_INTERN -int +dberr_t innobase_shutdown_for_mysql(void) /*=============================*/ { ulint i; + if (!srv_was_started) { if (srv_is_being_started) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: shutting down" - " a not properly started\n" - "InnoDB: or created database!\n"); + ib_logf(IB_LOG_LEVEL_WARN, + "Shutting down an improperly started, " + "or created database!"); } return(DB_SUCCESS); } - /* Shutdown the FTS optimize sub system. */ - fts_optimize_start_shutdown(); + if (!srv_read_only_mode) { + /* Shutdown the FTS optimize sub system. */ + fts_optimize_start_shutdown(); - fts_optimize_end(); + fts_optimize_end(); + } /* 1. Flush the buffer pool to disk, write the current lsn to the tablespace header(s), and copy all log data to archive. @@ -2485,18 +2809,12 @@ innobase_shutdown_for_mysql(void) logs_empty_and_mark_files_at_shutdown(); if (srv_conc_get_active_threads() != 0) { - fprintf(stderr, - "InnoDB: Warning: query counter shows %ld queries" - " still\n" - "InnoDB: inside InnoDB at shutdown\n", + ib_logf(IB_LOG_LEVEL_WARN, + "Query counter shows %ld queries still " + "inside InnoDB at shutdown", srv_conc_get_active_threads()); } - /* This functionality will be used by WL#5522. */ - ut_a(trx_purge_state() == PURGE_STATE_RUN - || trx_purge_state() == PURGE_STATE_EXIT - || srv_force_recovery >= SRV_FORCE_NO_BACKGROUND); - /* 2. Make all threads created by InnoDB to exit */ srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; @@ -2509,22 +2827,28 @@ innobase_shutdown_for_mysql(void) /* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM HERE OR EARLIER */ - /* a. Let the lock timeout thread exit */ - os_event_set(srv_timeout_event); + if (!srv_read_only_mode) { + /* a. Let the lock timeout thread exit */ + os_event_set(lock_sys->timeout_event); - /* b. srv error monitor thread exits automatically, no need - to do anything here */ + /* b. srv error monitor thread exits automatically, + no need to do anything here */ - /* c. We wake the master thread so that it exits */ - srv_wake_master_thread(); + /* c. We wake the master thread so that it exits */ + srv_wake_master_thread(); - /* d. Wakeup purge threads. */ - srv_purge_wakeup(); + /* d. Wakeup purge threads. */ + srv_purge_wakeup(); + } /* e. Exit the i/o threads */ os_aio_wake_all_threads_at_shutdown(); + /* f. dict_stats_thread is signaled from + logs_empty_and_mark_files_at_shutdown() and should have + already quit or is quitting right now. */ + os_mutex_enter(os_sync_mutex); if (os_thread_count == 0) { @@ -2549,9 +2873,9 @@ innobase_shutdown_for_mysql(void) } if (i == 1000) { - fprintf(stderr, - "InnoDB: Warning: %lu threads created by InnoDB" - " had not exited at shutdown!\n", + ib_logf(IB_LOG_LEVEL_WARN, + "%lu threads created by InnoDB" + " had not exited at shutdown!", (ulong) os_thread_count); } @@ -2563,6 +2887,7 @@ innobase_shutdown_for_mysql(void) mem_free(srv_monitor_file_name); } } + if (srv_dict_tmpfile) { fclose(srv_dict_tmpfile); srv_dict_tmpfile = 0; @@ -2573,6 +2898,10 @@ innobase_shutdown_for_mysql(void) srv_misc_tmpfile = 0; } + if (!srv_read_only_mode) { + dict_stats_thread_deinit(); + } + /* This must be disabled before closing the buffer pool and closing the data dictionary. */ btr_search_disable(); @@ -2583,9 +2912,14 @@ innobase_shutdown_for_mysql(void) trx_sys_file_format_close(); trx_sys_close(); - mutex_free(&srv_monitor_file_mutex); - mutex_free(&srv_dict_tmpfile_mutex); - mutex_free(&srv_misc_tmpfile_mutex); + /* We don't create these mutexes in RO mode because we don't create + the temp files that the cover. */ + if (!srv_read_only_mode) { + mutex_free(&srv_monitor_file_mutex); + mutex_free(&srv_dict_tmpfile_mutex); + mutex_free(&srv_misc_tmpfile_mutex); + } + dict_close(); btr_search_sys_free(); @@ -2594,6 +2928,7 @@ innobase_shutdown_for_mysql(void) os_aio_free(); que_close(); row_mysql_close(); + srv_mon_free(); sync_close(); srv_free(); fil_close(); @@ -2618,11 +2953,10 @@ innobase_shutdown_for_mysql(void) || os_event_count != 0 || os_mutex_count != 0 || os_fast_mutex_count != 0) { - fprintf(stderr, - "InnoDB: Warning: some resources were not" - " cleaned up in shutdown:\n" - "InnoDB: threads %lu, events %lu," - " os_mutexes %lu, os_fast_mutexes %lu\n", + ib_logf(IB_LOG_LEVEL_WARN, + "Some resources were not cleaned up in shutdown: " + "threads %lu, events %lu, os_mutexes %lu, " + "os_fast_mutexes %lu", (ulong) os_thread_count, (ulong) os_event_count, (ulong) os_mutex_count, (ulong) os_fast_mutex_count); } @@ -2632,17 +2966,15 @@ innobase_shutdown_for_mysql(void) } if (srv_print_verbose_log) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Shutdown completed;" - " log sequence number " LSN_PF "\n", + ib_logf(IB_LOG_LEVEL_INFO, + "Shutdown completed; log sequence number " LSN_PF "", srv_shutdown_lsn); } srv_was_started = FALSE; srv_start_has_been_called = FALSE; - return((int) DB_SUCCESS); + return(DB_SUCCESS); } #endif /* !UNIV_HOTBACKUP */ @@ -2650,7 +2982,7 @@ innobase_shutdown_for_mysql(void) /******************************************************************** Signal all per-table background threads to shutdown, and wait for them to do so. */ - +UNIV_INTERN void srv_shutdown_table_bg_threads(void) /*===============================*/ @@ -2723,3 +3055,48 @@ srv_shutdown_table_bg_threads(void) table = next; } } + +/*****************************************************************//** +Get the meta-data filename from the table name. */ +UNIV_INTERN +void +srv_get_meta_data_filename( +/*=======================*/ + dict_table_t* table, /*!< in: table */ + char* filename, /*!< out: filename */ + ulint max_len) /*!< in: filename max length */ +{ + ulint len; + char* path; + char* suffix; + static const ulint suffix_len = strlen(".cfg"); + + if (DICT_TF_HAS_DATA_DIR(table->flags)) { + dict_get_and_save_data_dir_path(table, false); + ut_a(table->data_dir_path); + + path = os_file_make_remote_pathname( + table->data_dir_path, table->name, "cfg"); + } else { + path = fil_make_ibd_name(table->name, false); + } + + ut_a(path); + len = ut_strlen(path); + ut_a(max_len >= len); + + suffix = path + (len - suffix_len); + if (strncmp(suffix, ".cfg", suffix_len) == 0) { + strcpy(filename, path); + } else { + ut_ad(strncmp(suffix, ".ibd", suffix_len) == 0); + + strncpy(filename, path, len - suffix_len); + suffix = filename + (len - suffix_len); + strcpy(suffix, ".cfg"); + } + + mem_free(path); + + srv_normalize_path_for_win(filename); +} |