mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
025ddfea28
innobase/dict/dict0crea.c: Remove unneeded prototypes for static functions Remove unused parameters from some functions Replace some assertions with compile-time checks dict_create_add_foreigns_to_dictionary(): allocate space dynamically for the SQL, and quote quotes innobase/dict/dict0dict.c: Remove unnecessary prototypes for static functions dict_tables_have_same_db(): Remove length limitation dict_remove_db_name(): Use strchr() dict_get_db_name_len(): Use strchr() Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() Remove unnecessary strlen() calls Allocate space dynamically for generated strings dict_scan_id(): allow quotes within quoted strings innobase/dict/dict0load.c: Remove unnecessary strlen() calls Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() innobase/dict/dict0mem.c: Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() innobase/eval/eval0eval.c: Make TO_CHAR() work with any machine word width innobase/fil/fil0fil.c: Replace mem_alloc()+strlen()+strcpy() with mem_strdup() innobase/ibuf/ibuf0ibuf.c: Make some global variables static Add #ifdef UNIV_IBUF_DEBUG around debug statements innobase/include/data0data.h: Add #ifdef UNIV_DEBUG around dtuple_validate() innobase/include/data0data.ic: Replace = with == in ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N) innobase/include/dict0dict.h: Add const qualifiers innobase/include/lock0lock.h: Add UL suffixes to unsigned long masks innobase/include/log0log.h: Remove unused parameter "type" of log_group_write_buf() innobase/include/mem0mem.h: Add mem_strdup(), mem_strdupl(), mem_strdupq(), mem_heap_strdup(), and mem_heap_strdupl() innobase/include/mem0mem.ic: Add mem_strdup(), mem_strdupl(), mem_strdupq(), mem_heap_strdup(), and mem_heap_strdupl() innobase/include/row0uins.h: Remove unused parameter "thr" of row_undo_ins() innobase/include/row0undo.h: Remvoe unused parameter "thr" of row_undo_search_clust_to_pcur() innobase/include/ut0byte.h: Add const qualifier to ut_cpy_in_lower_case() Remove parameter "len" of ut_cmp_in_lower_case() innobase/include/ut0mem.h: Add ut_strlenq(), ut_strcpyq() and ut_memcpyq() innobase/include/ut0mem.ic: Add ut_strlenq() innobase/include/ut0ut.h: Declare ut_sprintf() as a printf-style function innobase/lock/lock0lock.c: lock_clust_rec_modify_check_and_lock(): Remove unused variable "trx" innobase/log/log0log.c: Remove unused parameters innobase/log/log0recv.c: Remove parameter "type" from log_group_write_buf() innobase/mem/mem0mem.c: Simplify the initialization of block->init_block innobase/mtr/mtr0log.c: Add a debug assertion to mlog_parse_initial_log_record() innobase/page/page0cur.c: Add debug assertion to page_cur_insert_rec_write_log() Remove hard-coded buffer size in page_cur_parse_insert_rec() innobase/page/page0page.c: Remove unneeded variable rec innobase/pars/pars0opt.c: Correct a potential buffer overflow innobase/pars/pars0pars.c: Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() innobase/row/row0ins.c: Replace parameter "thr" with "trx" in row_ins_foreign_report_add_err() Remove unnecessary strlen() call Use strchr() innobase/row/row0mysql.c: Add row_mysql_is_recovered_tmp_table() Add row_mysql_is_system_table() Compare reserved table names with exact match Use strstr() and strchr() and mem_strdupl() Compute space needed for generated SQL, and allocate it dynamically innobase/row/row0purge.c: Remove unused parameters "thr" innobase/row/row0row.c: Simplify row_get_clust_rec() innobase/row/row0uins.c: Remove unused parameters "thr" innobase/row/row0umod.c: Remove unused variable "index" row_undo_mod_del_unmark_sec_and_undo_update(): Remove parameter "node" and variable "rec" Remove unused parameters "thr" innobase/row/row0undo.c: Remove unused parameters "thr" innobase/srv/srv0srv.c: Replace UT_NOT_USED() with __attribute__((unused)) innobase/srv/srv0start.c: Remove unnecessary strlen() calls Remove unused parameter "create_new_db" of open_or_create_log_file() innobase/trx/trx0roll.c: Replace mem_alloc()+strlen()+memcpy() with mem_strdup() innobase/trx/trx0sys.c: Remove unnecessary strlen() call innobase/ut/ut0byte.c: Add const qualifier to ut_cpy_in_lower_case() Remove parameter "len" of ut_cmp_in_lower_case() innobase/ut/ut0mem.c: Add ut_strlenq() and ut_memcpyq() sql/ha_innodb.cc: Remove parameter "len" of ut_cmp_in_lower_case()
1540 lines
38 KiB
C
1540 lines
38 KiB
C
/************************************************************************
|
|
Starts the InnoDB database server
|
|
|
|
(c) 1996-2000 Innobase Oy
|
|
|
|
Created 2/16/1996 Heikki Tuuri
|
|
*************************************************************************/
|
|
|
|
#include "os0proc.h"
|
|
#include "sync0sync.h"
|
|
#include "ut0mem.h"
|
|
#include "mem0mem.h"
|
|
#include "mem0pool.h"
|
|
#include "data0data.h"
|
|
#include "data0type.h"
|
|
#include "dict0dict.h"
|
|
#include "buf0buf.h"
|
|
#include "buf0flu.h"
|
|
#include "buf0rea.h"
|
|
#include "os0file.h"
|
|
#include "os0thread.h"
|
|
#include "fil0fil.h"
|
|
#include "fsp0fsp.h"
|
|
#include "rem0rec.h"
|
|
#include "rem0cmp.h"
|
|
#include "mtr0mtr.h"
|
|
#include "log0log.h"
|
|
#include "log0recv.h"
|
|
#include "page0page.h"
|
|
#include "page0cur.h"
|
|
#include "trx0trx.h"
|
|
#include "dict0boot.h"
|
|
#include "trx0sys.h"
|
|
#include "dict0crea.h"
|
|
#include "btr0btr.h"
|
|
#include "btr0pcur.h"
|
|
#include "btr0cur.h"
|
|
#include "btr0sea.h"
|
|
#include "rem0rec.h"
|
|
#include "srv0srv.h"
|
|
#include "que0que.h"
|
|
#include "usr0sess.h"
|
|
#include "lock0lock.h"
|
|
#include "trx0roll.h"
|
|
#include "trx0purge.h"
|
|
#include "row0ins.h"
|
|
#include "row0sel.h"
|
|
#include "row0upd.h"
|
|
#include "row0row.h"
|
|
#include "row0mysql.h"
|
|
#include "lock0lock.h"
|
|
#include "ibuf0ibuf.h"
|
|
#include "pars0pars.h"
|
|
#include "btr0sea.h"
|
|
#include "srv0start.h"
|
|
#include "que0que.h"
|
|
|
|
ibool srv_start_has_been_called = FALSE;
|
|
|
|
ulint srv_sizeof_trx_t_in_ha_innodb_cc;
|
|
|
|
ibool srv_startup_is_before_trx_rollback_phase = FALSE;
|
|
ibool srv_is_being_started = FALSE;
|
|
ibool srv_was_started = FALSE;
|
|
|
|
/* At a shutdown the value first climbs to SRV_SHUTDOWN_CLEANUP
|
|
and then to SRV_SHUTDOWN_LAST_PHASE */
|
|
ulint srv_shutdown_state = 0;
|
|
|
|
ibool measure_cont = FALSE;
|
|
|
|
os_file_t files[1000];
|
|
|
|
mutex_t ios_mutex;
|
|
ulint ios;
|
|
|
|
ulint n[SRV_MAX_N_IO_THREADS + 5];
|
|
os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5];
|
|
|
|
/* We use this mutex to test the return value of pthread_mutex_trylock
|
|
on successful locking. HP-UX does NOT return 0, though Linux et al do. */
|
|
os_fast_mutex_t srv_os_test_mutex;
|
|
|
|
ibool srv_os_test_mutex_is_locked = FALSE;
|
|
|
|
#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
|
|
#define SRV_MAX_N_PENDING_SYNC_IOS 100
|
|
|
|
/* The following limit may be too big in some old operating systems:
|
|
we may get an assertion failure in os0file.c */
|
|
|
|
#define SRV_MAX_N_OPEN_FILES 500
|
|
|
|
#define SRV_LOG_SPACE_FIRST_ID 1000000000
|
|
|
|
/*************************************************************************
|
|
Reads the data files and their sizes from a character string given in
|
|
the .cnf file. */
|
|
|
|
ibool
|
|
srv_parse_data_file_paths_and_sizes(
|
|
/*================================*/
|
|
/* out: TRUE if ok, FALSE if parsing
|
|
error */
|
|
char* str, /* in: the data file path string */
|
|
char*** data_file_names, /* out, own: array of data file
|
|
names */
|
|
ulint** data_file_sizes, /* out, own: array of data file sizes
|
|
in megabytes */
|
|
ulint** data_file_is_raw_partition,/* out, own: array of flags
|
|
showing which data files are raw
|
|
partitions */
|
|
ulint* n_data_files, /* out: number of data files */
|
|
ibool* is_auto_extending, /* out: TRUE if the last data file is
|
|
auto-extending */
|
|
ulint* max_auto_extend_size) /* out: max auto extend size for the
|
|
last file if specified, 0 if not */
|
|
{
|
|
char* input_str;
|
|
char* endp;
|
|
char* path;
|
|
ulint size;
|
|
ulint i = 0;
|
|
|
|
*is_auto_extending = FALSE;
|
|
*max_auto_extend_size = 0;
|
|
|
|
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++;
|
|
}
|
|
|
|
if (*str == '\0') {
|
|
return(FALSE);
|
|
}
|
|
|
|
str++;
|
|
|
|
size = strtoul(str, &endp, 10);
|
|
|
|
str = endp;
|
|
|
|
if (*str != 'M' && *str != 'G') {
|
|
size = size / (1024 * 1024);
|
|
} else if (*str == 'G') {
|
|
size = size * 1024;
|
|
str++;
|
|
} else {
|
|
str++;
|
|
}
|
|
|
|
if (0 == memcmp(str, ":autoextend", (sizeof ":autoextend") - 1)) {
|
|
|
|
str += (sizeof ":autoextend") - 1;
|
|
|
|
if (0 == memcmp(str, ":max:", (sizeof ":max:") - 1)) {
|
|
|
|
str += (sizeof ":max:") - 1;
|
|
|
|
size = strtoul(str, &endp, 10);
|
|
|
|
str = endp;
|
|
|
|
if (*str != 'M' && *str != 'G') {
|
|
size = size / (1024 * 1024);
|
|
} else if (*str == 'G') {
|
|
size = size * 1024;
|
|
str++;
|
|
} else {
|
|
str++;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
*data_file_names = (char**)ut_malloc(i * sizeof(void*));
|
|
*data_file_sizes = (ulint*)ut_malloc(i * sizeof(ulint));
|
|
*data_file_is_raw_partition = (ulint*)ut_malloc(i * sizeof(ulint));
|
|
|
|
*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 ignore the ':' in a Windows path */
|
|
|
|
while ((*str != ':' && *str != '\0')
|
|
|| (*str == ':'
|
|
&& (*(str + 1) == '\\' || *(str + 1) == '/'))) {
|
|
str++;
|
|
}
|
|
|
|
if (*str == ':') {
|
|
/* Make path a null-terminated string */
|
|
*str = '\0';
|
|
str++;
|
|
}
|
|
|
|
size = strtoul(str, &endp, 10);
|
|
|
|
str = endp;
|
|
|
|
if ((*str != 'M') && (*str != 'G')) {
|
|
size = size / (1024 * 1024);
|
|
} else if (*str == 'G') {
|
|
size = size * 1024;
|
|
str++;
|
|
} else {
|
|
str++;
|
|
}
|
|
|
|
(*data_file_names)[i] = path;
|
|
(*data_file_sizes)[i] = size;
|
|
|
|
if (0 == memcmp(str, ":autoextend", (sizeof ":autoextend") - 1)) {
|
|
|
|
*is_auto_extending = TRUE;
|
|
|
|
str += (sizeof ":autoextend") - 1;
|
|
|
|
if (0 == memcmp(str, ":max:", (sizeof ":max:") - 1)) {
|
|
|
|
str += (sizeof ":max:") - 1;
|
|
|
|
size = strtoul(str, &endp, 10);
|
|
|
|
str = endp;
|
|
|
|
if (*str != 'M' && *str != 'G') {
|
|
size = size / (1024 * 1024);
|
|
} else if (*str == 'G') {
|
|
size = size * 1024;
|
|
str++;
|
|
} else {
|
|
str++;
|
|
}
|
|
|
|
*max_auto_extend_size = size;
|
|
}
|
|
|
|
if (*str != '\0') {
|
|
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
(*data_file_is_raw_partition)[i] = 0;
|
|
|
|
if (strlen(str) >= 6
|
|
&& *str == 'n'
|
|
&& *(str + 1) == 'e'
|
|
&& *(str + 2) == 'w') {
|
|
str += 3;
|
|
(*data_file_is_raw_partition)[i] = SRV_NEW_RAW;
|
|
}
|
|
|
|
if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') {
|
|
str += 3;
|
|
|
|
if ((*data_file_is_raw_partition)[i] == 0) {
|
|
(*data_file_is_raw_partition)[i] = SRV_OLD_RAW;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
|
|
if (*str == ';') {
|
|
str++;
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Reads log group home directories from a character string given in
|
|
the .cnf file. */
|
|
|
|
ibool
|
|
srv_parse_log_group_home_dirs(
|
|
/*==========================*/
|
|
/* out: TRUE if ok, FALSE if parsing
|
|
error */
|
|
char* str, /* in: character string */
|
|
char*** log_group_home_dirs) /* out, own: log group home dirs */
|
|
{
|
|
char* input_str;
|
|
char* path;
|
|
ulint i = 0;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
*log_group_home_dirs = (char**) ut_malloc(i * sizeof(void*));
|
|
|
|
/* 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++;
|
|
}
|
|
|
|
(*log_group_home_dirs)[i] = path;
|
|
|
|
i++;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/************************************************************************
|
|
I/o-handler thread function. */
|
|
static
|
|
|
|
#ifndef __WIN__
|
|
void*
|
|
#else
|
|
ulint
|
|
#endif
|
|
io_handler_thread(
|
|
/*==============*/
|
|
void* arg)
|
|
{
|
|
ulint segment;
|
|
ulint i;
|
|
|
|
segment = *((ulint*)arg);
|
|
|
|
#ifdef UNIV_DEBUG_THREAD_CREATION
|
|
printf("Io handler thread %lu starts, id %lu\n", segment,
|
|
os_thread_pf(os_thread_get_curr_id()));
|
|
#endif
|
|
for (i = 0;; i++) {
|
|
fil_aio_wait(segment);
|
|
|
|
mutex_enter(&ios_mutex);
|
|
ios++;
|
|
mutex_exit(&ios_mutex);
|
|
}
|
|
|
|
/* We count the number of threads in os_thread_exit(). A created
|
|
thread should always use that to exit and not use return() to exit.
|
|
The thread actually never comes here because it is exited in an
|
|
os_event_wait(). */
|
|
|
|
os_thread_exit(NULL);
|
|
|
|
#ifndef __WIN__
|
|
return(NULL);
|
|
#else
|
|
return(0);
|
|
#endif
|
|
}
|
|
|
|
#ifdef __WIN__
|
|
#define SRV_PATH_SEPARATOR '\\'
|
|
#else
|
|
#define SRV_PATH_SEPARATOR '/'
|
|
#endif
|
|
|
|
/*************************************************************************
|
|
Normalizes a directory path for Windows: converts slashes to backslashes. */
|
|
|
|
void
|
|
srv_normalize_path_for_win(
|
|
/*=======================*/
|
|
char* str __attribute__((unused))) /* in/out: null-terminated character string */
|
|
{
|
|
#ifdef __WIN__
|
|
for (; *str; str++) {
|
|
|
|
if (*str == '/') {
|
|
*str = '\\';
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*************************************************************************
|
|
Adds a slash or a backslash to the end of a string if it is missing
|
|
and the string is not empty. */
|
|
|
|
static
|
|
char*
|
|
srv_add_path_separator_if_needed(
|
|
/*=============================*/
|
|
/* out: string which has the separator if the
|
|
string is not empty */
|
|
char* str) /* in: null-terminated character string */
|
|
{
|
|
char* out_str;
|
|
ulint len = ut_strlen(str);
|
|
|
|
if (len == 0 || str[len - 1] == SRV_PATH_SEPARATOR) {
|
|
|
|
return(str);
|
|
}
|
|
|
|
out_str = ut_malloc(len + 2);
|
|
memcpy(out_str, str, len);
|
|
out_str[len] = SRV_PATH_SEPARATOR;
|
|
out_str[len + 1] = 0;
|
|
|
|
return(out_str);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Calculates the low 32 bits when a file size which is given as a number
|
|
database pages is converted to the number of bytes. */
|
|
static
|
|
ulint
|
|
srv_calc_low32(
|
|
/*===========*/
|
|
/* out: low 32 bytes of file size when
|
|
expressed in bytes */
|
|
ulint file_size) /* in: file size in database pages */
|
|
{
|
|
return(0xFFFFFFFF & (file_size << UNIV_PAGE_SIZE_SHIFT));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Calculates the high 32 bits when a file size which is given as a number
|
|
database pages is converted to the number of bytes. */
|
|
static
|
|
ulint
|
|
srv_calc_high32(
|
|
/*============*/
|
|
/* out: high 32 bytes of file size when
|
|
expressed in bytes */
|
|
ulint file_size) /* in: file size in database pages */
|
|
{
|
|
return(file_size >> (32 - UNIV_PAGE_SIZE_SHIFT));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Creates or opens the log files and closes them. */
|
|
static
|
|
ulint
|
|
open_or_create_log_file(
|
|
/*====================*/
|
|
/* out: DB_SUCCESS or error code */
|
|
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 */
|
|
{
|
|
ibool ret;
|
|
ulint arch_space_id;
|
|
ulint size;
|
|
ulint size_high;
|
|
char name[10000];
|
|
|
|
*log_file_created = FALSE;
|
|
|
|
srv_normalize_path_for_win(srv_log_group_home_dirs[k]);
|
|
srv_log_group_home_dirs[k] = srv_add_path_separator_if_needed(
|
|
srv_log_group_home_dirs[k]);
|
|
|
|
sprintf(name, "%s%s%lu", srv_log_group_home_dirs[k], "ib_logfile", i);
|
|
|
|
files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL,
|
|
OS_LOG_FILE, &ret);
|
|
if (ret == FALSE) {
|
|
if (os_file_get_last_error() != OS_FILE_ALREADY_EXISTS) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in creating or opening %s\n", name);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
files[i] = os_file_create(name, OS_FILE_OPEN, OS_FILE_AIO,
|
|
OS_LOG_FILE, &ret);
|
|
if (!ret) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in opening %s\n", name);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
ret = os_file_get_size(files[i], &size, &size_high);
|
|
ut_a(ret);
|
|
|
|
if (size != srv_calc_low32(srv_log_file_size)
|
|
|| size_high != srv_calc_high32(srv_log_file_size)) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: log file %s is of different size %lu %lu bytes\n"
|
|
"InnoDB: than specified in the .cnf file %lu %lu bytes!\n",
|
|
name, size_high, size,
|
|
srv_calc_high32(srv_log_file_size),
|
|
srv_calc_low32(srv_log_file_size));
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
} else {
|
|
*log_file_created = TRUE;
|
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr,
|
|
" InnoDB: Log file %s did not exist: new to be created\n",
|
|
name);
|
|
if (log_file_has_been_opened) {
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n",
|
|
name, srv_log_file_size
|
|
>> (20 - UNIV_PAGE_SIZE_SHIFT));
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Database physically writes the file full: wait...\n");
|
|
|
|
ret = os_file_set_size(name, files[i],
|
|
srv_calc_low32(srv_log_file_size),
|
|
srv_calc_high32(srv_log_file_size));
|
|
if (!ret) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in creating %s: probably out of disk space\n",
|
|
name);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
}
|
|
|
|
ret = os_file_close(files[i]);
|
|
ut_a(ret);
|
|
|
|
if (i == 0) {
|
|
/* Create in memory the file space object
|
|
which is for this log group */
|
|
|
|
fil_space_create(name,
|
|
2 * k + SRV_LOG_SPACE_FIRST_ID, FIL_LOG);
|
|
}
|
|
|
|
ut_a(fil_validate());
|
|
|
|
fil_node_create(name, srv_log_file_size,
|
|
2 * k + SRV_LOG_SPACE_FIRST_ID);
|
|
|
|
/* If this is the first log group, create the file space object
|
|
for archived logs */
|
|
|
|
if (k == 0 && i == 0) {
|
|
arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID;
|
|
|
|
fil_space_create((char*) "arch_log_space", arch_space_id, FIL_LOG);
|
|
} else {
|
|
arch_space_id = ULINT_UNDEFINED;
|
|
}
|
|
|
|
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,
|
|
arch_space_id);
|
|
}
|
|
|
|
return(DB_SUCCESS);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Creates or opens database data files and closes them. */
|
|
static
|
|
ulint
|
|
open_or_create_data_files(
|
|
/*======================*/
|
|
/* out: DB_SUCCESS or error code */
|
|
ibool* create_new_db, /* out: TRUE if new database should be
|
|
created */
|
|
dulint* min_flushed_lsn,/* out: min of flushed lsn values in data
|
|
files */
|
|
ulint* min_arch_log_no,/* out: min of archived log numbers in data
|
|
files */
|
|
dulint* max_flushed_lsn,/* out: */
|
|
ulint* max_arch_log_no,/* out: */
|
|
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;
|
|
ulint size;
|
|
ulint size_high;
|
|
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",
|
|
srv_n_data_files);
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
*sum_of_new_sizes = 0;
|
|
|
|
*create_new_db = FALSE;
|
|
|
|
srv_normalize_path_for_win(srv_data_home);
|
|
srv_data_home = srv_add_path_separator_if_needed(srv_data_home);
|
|
|
|
for (i = 0; i < srv_n_data_files; i++) {
|
|
srv_normalize_path_for_win(srv_data_file_names[i]);
|
|
|
|
sprintf(name, "%s%s", srv_data_home, srv_data_file_names[i]);
|
|
|
|
files[i] = os_file_create(name, OS_FILE_CREATE,
|
|
OS_FILE_NORMAL, OS_DATA_FILE, &ret);
|
|
|
|
if (srv_data_file_is_raw_partition[i] == SRV_NEW_RAW) {
|
|
/* The partition is opened, not created; then it is
|
|
written over */
|
|
|
|
srv_created_new_raw = TRUE;
|
|
|
|
files[i] = os_file_create(
|
|
name, OS_FILE_OPEN, OS_FILE_NORMAL,
|
|
OS_DATA_FILE, &ret);
|
|
if (!ret) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in opening %s\n", name);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
} else if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) {
|
|
ret = FALSE;
|
|
}
|
|
|
|
if (ret == FALSE) {
|
|
if (srv_data_file_is_raw_partition[i] != SRV_OLD_RAW
|
|
&& os_file_get_last_error() !=
|
|
OS_FILE_ALREADY_EXISTS) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in creating or opening %s\n",
|
|
name);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
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",
|
|
name);
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
files[i] = os_file_create(
|
|
name, OS_FILE_OPEN, OS_FILE_NORMAL,
|
|
OS_DATA_FILE, &ret);
|
|
if (!ret) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in opening %s\n", name);
|
|
os_file_get_last_error();
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
if (srv_data_file_is_raw_partition[i] != SRV_OLD_RAW) {
|
|
|
|
ret = os_file_get_size(files[i], &size,
|
|
&size_high);
|
|
ut_a(ret);
|
|
/* Round size downward to megabytes */
|
|
|
|
rounded_size_pages = (size / (1024 * 1024)
|
|
+ 4096 * size_high)
|
|
<< (20 - 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)) {
|
|
|
|
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",
|
|
name, rounded_size_pages,
|
|
srv_data_file_sizes[i], 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]) {
|
|
|
|
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", name,
|
|
rounded_size_pages,
|
|
srv_data_file_sizes[i]);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
}
|
|
|
|
fil_read_flushed_lsn_and_arch_log_no(files[i],
|
|
one_opened,
|
|
min_flushed_lsn, min_arch_log_no,
|
|
max_flushed_lsn, max_arch_log_no);
|
|
one_opened = TRUE;
|
|
} else {
|
|
one_created = TRUE;
|
|
|
|
if (i > 0) {
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr,
|
|
" InnoDB: Data file %s did not exist: new to be created\n",
|
|
name);
|
|
} else {
|
|
fprintf(stderr,
|
|
"InnoDB: The first specified data file %s did not exist:\n"
|
|
"InnoDB: a new database to be created!\n", name);
|
|
*create_new_db = TRUE;
|
|
}
|
|
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr,
|
|
" InnoDB: Setting file %s size to %lu MB\n",
|
|
name, (srv_data_file_sizes[i]
|
|
>> (20 - UNIV_PAGE_SIZE_SHIFT)));
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Database physically writes the file full: wait...\n");
|
|
|
|
ret = os_file_set_size(name, files[i],
|
|
srv_calc_low32(srv_data_file_sizes[i]),
|
|
srv_calc_high32(srv_data_file_sizes[i]));
|
|
|
|
if (!ret) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error in creating %s: probably out of disk space\n", name);
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
*sum_of_new_sizes = *sum_of_new_sizes
|
|
+ srv_data_file_sizes[i];
|
|
}
|
|
|
|
ret = os_file_close(files[i]);
|
|
ut_a(ret);
|
|
|
|
if (i == 0) {
|
|
fil_space_create(name, 0, FIL_TABLESPACE);
|
|
}
|
|
|
|
ut_a(fil_validate());
|
|
|
|
fil_node_create(name, srv_data_file_sizes[i], 0);
|
|
}
|
|
|
|
ios = 0;
|
|
|
|
mutex_create(&ios_mutex);
|
|
mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK);
|
|
|
|
return(DB_SUCCESS);
|
|
}
|
|
|
|
/********************************************************************
|
|
Starts InnoDB and creates a new database if database files
|
|
are not found and the user wants. Server parameters are
|
|
read from a file of name "srv_init" in the ib_home directory. */
|
|
|
|
int
|
|
innobase_start_or_create_for_mysql(void)
|
|
/*====================================*/
|
|
/* out: DB_SUCCESS or error code */
|
|
{
|
|
ibool create_new_db;
|
|
ibool log_file_created;
|
|
ibool log_created = FALSE;
|
|
ibool log_opened = FALSE;
|
|
dulint min_flushed_lsn;
|
|
dulint max_flushed_lsn;
|
|
ulint min_arch_log_no;
|
|
ulint max_arch_log_no;
|
|
ibool start_archive;
|
|
ulint sum_of_new_sizes;
|
|
ulint sum_of_data_file_sizes;
|
|
ulint tablespace_size_in_header;
|
|
ulint err;
|
|
ulint i;
|
|
ulint k;
|
|
mtr_t mtr;
|
|
|
|
#ifdef UNIV_DEBUG
|
|
fprintf(stderr,
|
|
"InnoDB: !!!!!!!!!!!!!! UNIV_DEBUG switched on !!!!!!!!!!!!!!!\n");
|
|
#endif
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
fprintf(stderr,
|
|
"InnoDB: !!!!!!!!!!!!!! UNIV_SYNC_DEBUG switched on !!!!!!!!!!!!!!!\n");
|
|
#endif
|
|
|
|
#ifdef UNIV_SEARCH_DEBUG
|
|
fprintf(stderr,
|
|
"InnoDB: !!!!!!!!!!!!!! UNIV_SEARCH_DEBUG switched on !!!!!!!!!!!!!!!\n");
|
|
#endif
|
|
|
|
#ifdef UNIV_MEM_DEBUG
|
|
fprintf(stderr,
|
|
"InnoDB: !!!!!!!!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!!!!!!!\n");
|
|
#endif
|
|
|
|
if (srv_sizeof_trx_t_in_ha_innodb_cc != (ulint)sizeof(trx_t)) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: trx_t size is %lu in ha_innodb.cc but %lu in srv0start.c\n"
|
|
"InnoDB: Check that pthread_mutex_t is defined in the same way in these\n"
|
|
"InnoDB: compilation modules. Cannot continue.\n",
|
|
srv_sizeof_trx_t_in_ha_innodb_cc, (ulint)sizeof(trx_t));
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
/* 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
|
|
second time during the process lifetime. */
|
|
|
|
if (srv_start_has_been_called) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error:startup called second time during the process lifetime.\n"
|
|
"InnoDB: In the MySQL Embedded Server Library you cannot call server_init()\n"
|
|
"InnoDB: more than once during the process lifetime.\n");
|
|
}
|
|
|
|
srv_start_has_been_called = TRUE;
|
|
|
|
log_do_write = TRUE;
|
|
/* yydebug = TRUE; */
|
|
|
|
srv_is_being_started = TRUE;
|
|
srv_startup_is_before_trx_rollback_phase = TRUE;
|
|
os_aio_use_native_aio = FALSE;
|
|
|
|
#ifdef __WIN__
|
|
if (os_get_os_version() == OS_WIN95
|
|
|| os_get_os_version() == OS_WIN31
|
|
|| os_get_os_version() == OS_WINNT) {
|
|
|
|
/* On Win 95, 98, ME, Win32 subsystem for Windows 3.1,
|
|
and NT use simulated aio. In NT Windows provides async i/o,
|
|
but when run in conjunction with InnoDB Hot Backup, it seemed
|
|
to corrupt the data files. */
|
|
|
|
os_aio_use_native_aio = FALSE;
|
|
} else {
|
|
/* On Win 2000 and XP use async i/o */
|
|
os_aio_use_native_aio = TRUE;
|
|
}
|
|
#endif
|
|
if (srv_file_flush_method_str == NULL) {
|
|
/* These are the default options */
|
|
|
|
srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
|
|
|
|
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
|
|
#ifndef __WIN__
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
(char*)"fdatasync")) {
|
|
srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
|
|
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
(char*)"O_DSYNC")) {
|
|
srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
|
|
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
(char*)"O_DIRECT")) {
|
|
srv_unix_file_flush_method = SRV_UNIX_O_DIRECT;
|
|
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
(char*)"littlesync")) {
|
|
srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
|
|
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
(char*)"nosync")) {
|
|
srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
|
|
#else
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
(char*)"normal")) {
|
|
srv_win_file_flush_method = SRV_WIN_IO_NORMAL;
|
|
os_aio_use_native_aio = FALSE;
|
|
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str, "unbuffered")) {
|
|
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
|
|
os_aio_use_native_aio = FALSE;
|
|
|
|
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
|
"async_unbuffered")) {
|
|
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
|
|
#endif
|
|
} else {
|
|
fprintf(stderr,
|
|
"InnoDB: Unrecognized value %s for innodb_flush_method\n",
|
|
srv_file_flush_method_str);
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
/* Set the maximum number of threads which can wait for a semaphore
|
|
inside InnoDB */
|
|
#if defined(__WIN__) || defined(__NETWARE__)
|
|
|
|
/* Create less event semaphores because Win 98/ME had difficulty creating
|
|
40000 event semaphores.
|
|
Comment from Novell, Inc.: also, these just take a lot of memory on
|
|
NetWare. */
|
|
srv_max_n_threads = 1000;
|
|
#else
|
|
if (srv_pool_size >= 8 * 1024 * 1024) {
|
|
/* Here we still have srv_pool_size counted
|
|
in bytes, srv_boot converts the value to
|
|
pages; if buffer pool is less than 8 MB,
|
|
assume fewer threads. */
|
|
srv_max_n_threads = 10000;
|
|
} else {
|
|
srv_max_n_threads = 1000; /* saves several MB of memory,
|
|
especially in 64-bit
|
|
computers */
|
|
}
|
|
#endif
|
|
err = srv_boot();
|
|
|
|
if (err != DB_SUCCESS) {
|
|
|
|
return((int) err);
|
|
}
|
|
|
|
/* Restrict the maximum number of file i/o threads */
|
|
if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) {
|
|
|
|
srv_n_file_io_threads = SRV_MAX_N_IO_THREADS;
|
|
}
|
|
|
|
if (!os_aio_use_native_aio) {
|
|
/* In simulated aio we currently have use only for 4 threads */
|
|
|
|
srv_n_file_io_threads = 4;
|
|
|
|
os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD
|
|
* srv_n_file_io_threads,
|
|
srv_n_file_io_threads,
|
|
SRV_MAX_N_PENDING_SYNC_IOS);
|
|
} else {
|
|
os_aio_init(SRV_N_PENDING_IOS_PER_THREAD
|
|
* srv_n_file_io_threads,
|
|
srv_n_file_io_threads,
|
|
SRV_MAX_N_PENDING_SYNC_IOS);
|
|
}
|
|
|
|
fil_init(SRV_MAX_N_OPEN_FILES);
|
|
|
|
buf_pool_init(srv_pool_size, srv_pool_size);
|
|
|
|
fsp_init();
|
|
log_init();
|
|
|
|
lock_sys_create(srv_lock_table_size);
|
|
|
|
/* Create i/o-handler threads: */
|
|
|
|
for (i = 0; i < srv_n_file_io_threads; i++) {
|
|
n[i] = i;
|
|
|
|
os_thread_create(io_handler_thread, n + i, thread_ids + i);
|
|
}
|
|
|
|
if (0 != ut_strcmp(srv_log_group_home_dirs[0], srv_arch_dir)) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: you must set the log group home dir in my.cnf the\n"
|
|
"InnoDB: same as log arch dir.\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
if (srv_n_log_files * srv_log_file_size >= 262144) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: combined size of log files must be < 4 GB\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
sum_of_new_sizes = 0;
|
|
|
|
for (i = 0; i < srv_n_data_files; i++) {
|
|
#ifndef __WIN__
|
|
if (sizeof(off_t) < 5 && srv_data_file_sizes[i] >= 262144) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: file size must be < 4 GB with this MySQL binary\n"
|
|
"InnoDB: and operating system combination, in some OS's < 2 GB\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
#endif
|
|
sum_of_new_sizes += srv_data_file_sizes[i];
|
|
}
|
|
|
|
if (sum_of_new_sizes < 640) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: tablespace size must be at least 10 MB\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
err = open_or_create_data_files(&create_new_db,
|
|
&min_flushed_lsn, &min_arch_log_no,
|
|
&max_flushed_lsn, &max_arch_log_no,
|
|
&sum_of_new_sizes);
|
|
if (err != DB_SUCCESS) {
|
|
fprintf(stderr,
|
|
"InnoDB: Could not open or create data files.\n"
|
|
"InnoDB: If you tried to add new data files, and it failed here,\n"
|
|
"InnoDB: you should now edit innodb_data_file_path in my.cnf back\n"
|
|
"InnoDB: to what it was, and remove the new ibdata files InnoDB created\n"
|
|
"InnoDB: in this failed attempt. InnoDB only wrote those files full of\n"
|
|
"InnoDB: zeros, but did not yet use them in any way. But be careful: do not\n"
|
|
"InnoDB: remove old data files which contain your precious data!\n");
|
|
|
|
return((int) err);
|
|
}
|
|
|
|
if (!create_new_db) {
|
|
/* If we are using the doublewrite method, we will
|
|
check if there are half-written pages in data files,
|
|
and restore them from the doublewrite buffer if
|
|
possible */
|
|
|
|
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
|
|
|
|
trx_sys_doublewrite_restore_corrupt_pages();
|
|
}
|
|
}
|
|
|
|
srv_normalize_path_for_win(srv_arch_dir);
|
|
srv_arch_dir = srv_add_path_separator_if_needed(srv_arch_dir);
|
|
|
|
for (k = 0; k < srv_n_log_groups; k++) {
|
|
|
|
for (i = 0; i < srv_n_log_files; i++) {
|
|
|
|
err = open_or_create_log_file(&log_file_created,
|
|
log_opened, k, i);
|
|
if (err != DB_SUCCESS) {
|
|
|
|
return((int) err);
|
|
}
|
|
|
|
if (log_file_created) {
|
|
log_created = TRUE;
|
|
} else {
|
|
log_opened = TRUE;
|
|
}
|
|
|
|
if ((log_opened && create_new_db)
|
|
|| (log_opened && log_created)) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: all log files must be created at the same time.\n"
|
|
"InnoDB: All log files must be created also in database creation.\n"
|
|
"InnoDB: If you want bigger or smaller log files, shut down the\n"
|
|
"InnoDB: database and make sure there were no errors in shutdown.\n"
|
|
"InnoDB: Then delete the existing log files. Edit the .cnf file\n"
|
|
"InnoDB: and start the database again.\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (log_created && !create_new_db && !srv_archive_recovery) {
|
|
|
|
if (ut_dulint_cmp(max_flushed_lsn, min_flushed_lsn) != 0
|
|
|| max_arch_log_no != min_arch_log_no) {
|
|
fprintf(stderr,
|
|
"InnoDB: Cannot initialize created log files because\n"
|
|
"InnoDB: data files were not in sync with each other\n"
|
|
"InnoDB: or the data files are corrupt.\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
if (ut_dulint_cmp(max_flushed_lsn, ut_dulint_create(0, 1000))
|
|
< 0) {
|
|
fprintf(stderr,
|
|
"InnoDB: Cannot initialize created log files because\n"
|
|
"InnoDB: data files are corrupt, or new data files were\n"
|
|
"InnoDB: created when the database was started previous\n"
|
|
"InnoDB: time but the database was not shut down\n"
|
|
"InnoDB: normally after that.\n");
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
mutex_enter(&(log_sys->mutex));
|
|
|
|
recv_reset_logs(max_flushed_lsn, max_arch_log_no + 1, TRUE);
|
|
|
|
mutex_exit(&(log_sys->mutex));
|
|
}
|
|
|
|
if (create_new_db) {
|
|
mtr_start(&mtr);
|
|
|
|
fsp_header_init(0, sum_of_new_sizes, &mtr);
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
trx_sys_create();
|
|
dict_create();
|
|
srv_startup_is_before_trx_rollback_phase = FALSE;
|
|
|
|
} else if (srv_archive_recovery) {
|
|
fprintf(stderr,
|
|
"InnoDB: Starting archive recovery from a backup...\n");
|
|
|
|
err = recv_recovery_from_archive_start(
|
|
min_flushed_lsn,
|
|
srv_archive_recovery_limit_lsn,
|
|
min_arch_log_no);
|
|
if (err != DB_SUCCESS) {
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
/* Since ibuf init is in dict_boot, and ibuf is needed
|
|
in any disk i/o, first call dict_boot */
|
|
|
|
dict_boot();
|
|
|
|
trx_sys_init_at_db_start();
|
|
|
|
srv_startup_is_before_trx_rollback_phase = FALSE;
|
|
|
|
/* Initialize the fsp free limit global variable in the log
|
|
system */
|
|
fsp_header_get_free_limit(0);
|
|
|
|
recv_recovery_from_archive_finish();
|
|
} else {
|
|
/* We always try to do a recovery, even if the database had
|
|
been shut down normally */
|
|
|
|
err = recv_recovery_from_checkpoint_start(LOG_CHECKPOINT,
|
|
ut_dulint_max,
|
|
min_flushed_lsn,
|
|
max_flushed_lsn);
|
|
if (err != DB_SUCCESS) {
|
|
|
|
return(DB_ERROR);
|
|
}
|
|
|
|
/* Since ibuf init is in dict_boot, and ibuf is needed
|
|
in any disk i/o, first call dict_boot */
|
|
|
|
dict_boot();
|
|
trx_sys_init_at_db_start();
|
|
|
|
/* The following needs trx lists which are initialized in
|
|
trx_sys_init_at_db_start */
|
|
|
|
srv_startup_is_before_trx_rollback_phase = FALSE;
|
|
|
|
/* Initialize the fsp free limit global variable in the log
|
|
system */
|
|
fsp_header_get_free_limit(0);
|
|
|
|
recv_recovery_from_checkpoint_finish();
|
|
}
|
|
|
|
if (!create_new_db && sum_of_new_sizes > 0) {
|
|
/* New data file(s) were added */
|
|
mtr_start(&mtr);
|
|
|
|
fsp_header_inc_size(0, sum_of_new_sizes, &mtr);
|
|
|
|
mtr_commit(&mtr);
|
|
}
|
|
|
|
if (recv_needed_recovery) {
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr,
|
|
" InnoDB: Flushing modified pages from the buffer pool...\n");
|
|
}
|
|
|
|
log_make_checkpoint_at(ut_dulint_max, TRUE);
|
|
|
|
if (!srv_log_archive_on) {
|
|
ut_a(DB_SUCCESS == log_archive_noarchivelog());
|
|
} else {
|
|
mutex_enter(&(log_sys->mutex));
|
|
|
|
start_archive = FALSE;
|
|
|
|
if (log_sys->archiving_state == LOG_ARCH_OFF) {
|
|
start_archive = TRUE;
|
|
}
|
|
|
|
mutex_exit(&(log_sys->mutex));
|
|
|
|
if (start_archive) {
|
|
ut_a(DB_SUCCESS == log_archive_archivelog());
|
|
}
|
|
}
|
|
|
|
if (srv_measure_contention) {
|
|
/* os_thread_create(&test_measure_cont, NULL, thread_ids +
|
|
SRV_MAX_N_IO_THREADS); */
|
|
}
|
|
|
|
/* fprintf(stderr, "Max allowed record size %lu\n",
|
|
page_get_free_space_of_empty() / 2); */
|
|
|
|
/* Create the thread which watches the timeouts for lock waits
|
|
and prints InnoDB monitor info */
|
|
|
|
os_thread_create(&srv_lock_timeout_and_monitor_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);
|
|
srv_was_started = TRUE;
|
|
srv_is_being_started = FALSE;
|
|
|
|
sync_order_checks_on = TRUE;
|
|
|
|
if (srv_use_doublewrite_buf && trx_doublewrite == NULL) {
|
|
trx_sys_create_doublewrite_buf();
|
|
}
|
|
|
|
err = dict_create_or_check_foreign_constraint_tables();
|
|
|
|
if (err != DB_SUCCESS) {
|
|
return((int)DB_ERROR);
|
|
}
|
|
|
|
/* Create the master thread which monitors the database
|
|
server, and does purge and other utility operations */
|
|
|
|
os_thread_create(&srv_master_thread, NULL, thread_ids + 1 +
|
|
SRV_MAX_N_IO_THREADS);
|
|
/* buf_debug_prints = TRUE; */
|
|
|
|
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];
|
|
}
|
|
|
|
tablespace_size_in_header = fsp_header_get_tablespace_size(0);
|
|
|
|
if (!srv_auto_extend_last_data_file
|
|
&& sum_of_data_file_sizes != tablespace_size_in_header) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: tablespace size stored in header is %lu pages, but\n"
|
|
"InnoDB: the sum of data file sizes is %lu pages\n",
|
|
tablespace_size_in_header, sum_of_data_file_sizes);
|
|
}
|
|
|
|
if (srv_auto_extend_last_data_file
|
|
&& sum_of_data_file_sizes < tablespace_size_in_header) {
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Error: tablespace size stored in header is %lu pages, but\n"
|
|
"InnoDB: the sum of data file sizes is only %lu pages\n",
|
|
tablespace_size_in_header, sum_of_data_file_sizes);
|
|
}
|
|
|
|
/* Check that os_fast_mutexes work as exptected */
|
|
os_fast_mutex_init(&srv_os_test_mutex);
|
|
|
|
if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) {
|
|
fprintf(stderr,
|
|
"InnoDB: Error: pthread_mutex_trylock returns an unexpected value on\n"
|
|
"InnoDB: success! Cannot continue.\n");
|
|
exit(1);
|
|
}
|
|
|
|
os_fast_mutex_unlock(&srv_os_test_mutex);
|
|
|
|
os_fast_mutex_lock(&srv_os_test_mutex);
|
|
|
|
os_fast_mutex_unlock(&srv_os_test_mutex);
|
|
|
|
os_fast_mutex_free(&srv_os_test_mutex);
|
|
|
|
/***********************************************************/
|
|
/* Do NOT merge to the 4.1 code base! */
|
|
if (trx_sys_downgrading_from_4_1_1) {
|
|
fprintf(stderr,
|
|
"InnoDB: You are downgrading from an InnoDB version which allows multiple\n"
|
|
"InnoDB: tablespaces. Wait that purge and insert buffer merge run to\n"
|
|
"InnoDB: completion...\n");
|
|
for (;;) {
|
|
os_thread_sleep(10000000);
|
|
|
|
if (0 == strcmp(srv_main_thread_op_info,
|
|
"waiting for server activity")) {
|
|
break;
|
|
}
|
|
}
|
|
fprintf(stderr,
|
|
"InnoDB: Full purge and insert buffer merge completed.\n");
|
|
|
|
trx_sys_mark_downgraded_from_4_1_1();
|
|
|
|
fprintf(stderr,
|
|
"InnoDB: Downgraded from >= 4.1.1 to 4.0\n");
|
|
}
|
|
/***********************************************************/
|
|
|
|
if (srv_print_verbose_log) {
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr, " InnoDB: Started\n");
|
|
}
|
|
|
|
if (srv_force_recovery > 0) {
|
|
fprintf(stderr,
|
|
"InnoDB: !!! innodb_force_recovery is set to %lu !!!\n",
|
|
srv_force_recovery);
|
|
}
|
|
|
|
fflush(stderr);
|
|
|
|
return((int) DB_SUCCESS);
|
|
}
|
|
|
|
/********************************************************************
|
|
Shuts down the InnoDB database. */
|
|
|
|
int
|
|
innobase_shutdown_for_mysql(void)
|
|
/*=============================*/
|
|
/* out: DB_SUCCESS or error code */
|
|
{
|
|
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");
|
|
fprintf(stderr,
|
|
" InnoDB: or created database!\n");
|
|
}
|
|
|
|
return(DB_SUCCESS);
|
|
}
|
|
|
|
/* 1. Flush buffer pool to disk, write the current lsn to
|
|
the tablespace header(s), and copy all log data to archive.
|
|
The step 1 is the real InnoDB shutdown. The remaining steps
|
|
just free data structures after the shutdown. */
|
|
|
|
logs_empty_and_mark_files_at_shutdown();
|
|
|
|
if (srv_conc_n_threads != 0) {
|
|
fprintf(stderr,
|
|
"InnoDB: Warning: query counter shows %ld queries still\n"
|
|
"InnoDB: inside InnoDB at shutdown\n",
|
|
srv_conc_n_threads);
|
|
}
|
|
|
|
/* 2. Make all threads created by InnoDB to exit */
|
|
|
|
srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
|
|
|
|
/* All threads end up waiting for certain events. Put those events
|
|
to the signaled state. Then the threads will exit themselves in
|
|
os_thread_event_wait(). */
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
/* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM
|
|
HERE OR EARLIER */
|
|
|
|
/* 1. Let the lock timeout thread exit */
|
|
os_event_set(srv_lock_timeout_thread_event);
|
|
|
|
/* 2. srv error monitor thread exits automatically, no need
|
|
to do anything here */
|
|
|
|
/* 3. We wake the master thread so that it exits */
|
|
srv_wake_master_thread();
|
|
|
|
/* 4. Exit the i/o threads */
|
|
|
|
os_aio_wake_all_threads_at_shutdown();
|
|
|
|
os_mutex_enter(os_sync_mutex);
|
|
|
|
if (os_thread_count == 0) {
|
|
/* All the threads have exited or are just exiting;
|
|
NOTE that the threads may not have completed their
|
|
exit yet. Should we use pthread_join() to make sure
|
|
they have exited? Now we just sleep 0.1 seconds and
|
|
hope that is enough! */
|
|
|
|
os_mutex_exit(os_sync_mutex);
|
|
|
|
os_thread_sleep(100000);
|
|
|
|
break;
|
|
}
|
|
|
|
os_mutex_exit(os_sync_mutex);
|
|
|
|
os_thread_sleep(100000);
|
|
}
|
|
|
|
if (i == 1000) {
|
|
fprintf(stderr,
|
|
"InnoDB: Warning: %lu threads created by InnoDB had not exited at shutdown!\n",
|
|
os_thread_count);
|
|
}
|
|
|
|
/* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
|
|
them */
|
|
|
|
sync_close();
|
|
|
|
/* 4. Free the os_conc_mutex and all os_events and os_mutexes */
|
|
|
|
srv_free();
|
|
os_sync_free();
|
|
|
|
/* 5. Free all allocated memory and the os_fast_mutex created in
|
|
ut0mem.c */
|
|
|
|
ut_free_all_mem();
|
|
|
|
if (os_thread_count != 0
|
|
|| 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",
|
|
os_thread_count, os_event_count, os_mutex_count,
|
|
os_fast_mutex_count);
|
|
}
|
|
|
|
if (srv_print_verbose_log) {
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr, " InnoDB: Shutdown completed\n");
|
|
}
|
|
|
|
return((int) DB_SUCCESS);
|
|
}
|