diff options
Diffstat (limited to 'innobase/srv/srv0start.c')
-rw-r--r-- | innobase/srv/srv0start.c | 365 |
1 files changed, 291 insertions, 74 deletions
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index ea0ed7c961e..8ff2076d5d1 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -56,6 +56,10 @@ Created 2/16/1996 Heikki Tuuri #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; @@ -157,13 +161,13 @@ srv_parse_data_file_paths_and_sizes( } if (strlen(str) >= ut_strlen(":autoextend") - && 0 == ut_memcmp(str, ":autoextend", + && 0 == ut_memcmp(str, (char*)":autoextend", ut_strlen(":autoextend"))) { str += ut_strlen(":autoextend"); if (strlen(str) >= ut_strlen(":max:") - && 0 == ut_memcmp(str, ":max:", + && 0 == ut_memcmp(str, (char*)":max:", ut_strlen(":max:"))) { str += ut_strlen(":max:"); @@ -261,7 +265,7 @@ srv_parse_data_file_paths_and_sizes( (*data_file_sizes)[i] = size; if (strlen(str) >= ut_strlen(":autoextend") - && 0 == ut_memcmp(str, ":autoextend", + && 0 == ut_memcmp(str, (char*)":autoextend", ut_strlen(":autoextend"))) { *is_auto_extending = TRUE; @@ -269,7 +273,7 @@ srv_parse_data_file_paths_and_sizes( str += ut_strlen(":autoextend"); if (strlen(str) >= ut_strlen(":max:") - && 0 == ut_memcmp(str, ":max:", + && 0 == ut_memcmp(str, (char*)":max:", ut_strlen(":max:"))) { str += ut_strlen(":max:"); @@ -410,8 +414,10 @@ io_handler_thread( segment = *((ulint*)arg); -/* printf("Io handler thread %lu starts\n", segment); */ - +#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); @@ -420,6 +426,13 @@ io_handler_thread( 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 @@ -439,7 +452,7 @@ Normalizes a directory path for Windows: converts slashes to backslashes. */ void srv_normalize_path_for_win( /*=======================*/ - char* str) /* in/out: null-terminated character string */ + char* str __attribute__((unused))) /* in/out: null-terminated character string */ { #ifdef __WIN__ ulint i; @@ -515,7 +528,7 @@ srv_calc_high32( } /************************************************************************* -Creates or opens the log files. */ +Creates or opens the log files and closes them. */ static ulint open_or_create_log_file( @@ -525,6 +538,9 @@ open_or_create_log_file( 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 */ { @@ -570,19 +586,27 @@ open_or_create_log_file( || size_high != srv_calc_high32(srv_log_file_size)) { fprintf(stderr, - "InnoDB: Error: log file %s is of different size\n" - "InnoDB: than specified in the .cnf file!\n", name); +"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)); @@ -624,7 +648,7 @@ open_or_create_log_file( if (k == 0 && i == 0) { arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID; - fil_space_create("arch_log_space", arch_space_id, FIL_LOG); + fil_space_create((char*) "arch_log_space", arch_space_id, FIL_LOG); } else { arch_space_id = ULINT_UNDEFINED; } @@ -640,7 +664,7 @@ open_or_create_log_file( } /************************************************************************* -Creates or opens database data files. */ +Creates or opens database data files and closes them. */ static ulint open_or_create_data_files( @@ -758,8 +782,13 @@ open_or_create_data_files( rounded_size_pages)) { fprintf(stderr, - "InnoDB: Error: data file %s is of a different size\n" - "InnoDB: than specified in the .cnf file!\n", name); +"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] = @@ -770,8 +799,11 @@ open_or_create_data_files( != srv_data_file_sizes[i]) { fprintf(stderr, - "InnoDB: Error: data file %s is of a different size\n" - "InnoDB: than specified in the .cnf file!\n", name); +"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); } @@ -841,6 +873,7 @@ open_or_create_data_files( return(DB_SUCCESS); } +#ifdef notdefined /********************************************************************* This thread is used to measure contention of latches. */ static @@ -912,6 +945,7 @@ test_measure_cont( return(0); } +#endif /******************************************************************** Starts InnoDB and creates a new database if database files @@ -960,36 +994,121 @@ innobase_start_or_create_for_mysql(void) "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; - if (0 == ut_strcmp(srv_unix_file_flush_method_str, "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_unix_file_flush_method_str, "O_DSYNC")) { + } 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_unix_file_flush_method_str, - "littlesync")) { + } 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_unix_file_flush_method_str, "nosync")) { + } 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_unix_file_flush_method_str); + srv_file_flush_method_str); return(DB_ERROR); } - /* - printf("srv_unix set to %lu\n", srv_unix_file_flush_method); - */ - os_aio_use_native_aio = srv_use_native_aio; + /* 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) { @@ -999,34 +1118,15 @@ innobase_start_or_create_for_mysql(void) /* 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 !(defined(WIN_ASYNC_IO) || defined(POSIX_ASYNC_IO)) - /* In simulated aio we currently have use only for 4 threads */ - - os_aio_use_native_aio = FALSE; - - srv_n_file_io_threads = 4; -#endif - -#ifdef __WIN__ - if (os_get_os_version() == OS_WIN95 - || os_get_os_version() == OS_WIN31) { + if (!os_aio_use_native_aio) { + /* In simulated aio we currently have use only for 4 threads */ - /* On Win 95, 98, ME, and Win32 subsystem for Windows 3.1 use - simulated aio */ + srv_n_file_io_threads = 4; - os_aio_use_native_aio = FALSE; - srv_n_file_io_threads = 4; - } else { - /* On NT and Win 2000 always use aio */ - os_aio_use_native_aio = TRUE; - } -#endif - os_aio_use_native_aio = FALSE; - - if (!os_aio_use_native_aio) { os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD * srv_n_file_io_threads, srv_n_file_io_threads, @@ -1047,15 +1147,6 @@ innobase_start_or_create_for_mysql(void) lock_sys_create(srv_lock_table_size); -#ifdef POSIX_ASYNC_IO - if (os_aio_use_native_aio) { - /* There is only one thread per async io array: - one for ibuf i/o, one for log i/o, one for ordinary reads, - one for ordinary writes; we need only 4 i/o threads */ - - srv_n_file_io_threads = 4; - } -#endif /* Create i/o-handler threads: */ for (i = 0; i < srv_n_file_io_threads; i++) { @@ -1107,7 +1198,14 @@ innobase_start_or_create_for_mysql(void) &max_flushed_lsn, &max_arch_log_no, &sum_of_new_sizes); if (err != DB_SUCCESS) { - fprintf(stderr, "InnoDB: Could not open data files\n"); + 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); } @@ -1118,7 +1216,10 @@ innobase_start_or_create_for_mysql(void) and restore them from the doublewrite buffer if possible */ - trx_sys_doublewrite_restore_corrupt_pages(); + if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { + + trx_sys_doublewrite_restore_corrupt_pages(); + } } srv_normalize_path_for_win(srv_arch_dir); @@ -1129,7 +1230,8 @@ innobase_start_or_create_for_mysql(void) for (i = 0; i < srv_n_log_files; i++) { err = open_or_create_log_file(create_new_db, - &log_file_created, k, i); + &log_file_created, + log_opened, k, i); if (err != DB_SUCCESS) { return((int) err); @@ -1365,7 +1467,7 @@ innobase_start_or_create_for_mysql(void) 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"); +"InnoDB: success! Cannot continue.\n"); exit(1); } @@ -1375,8 +1477,45 @@ innobase_start_or_create_for_mysql(void) os_fast_mutex_unlock(&srv_os_test_mutex); - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Started\n"); + 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); } @@ -1389,6 +1528,8 @@ 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); @@ -1401,8 +1542,10 @@ innobase_shutdown_for_mysql(void) return(DB_SUCCESS); } - /* Flush buffer pool to disk, write the current lsn to - the tablespace header(s), and copy all log data to archive */ + /* 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(); @@ -1413,14 +1556,88 @@ innobase_shutdown_for_mysql(void) srv_conc_n_threads); } - /* - TODO: We should exit the i/o-handler and other utility threads - before freeing all memory. Now this can potentially cause a seg - fault! - */ -#ifdef NOT_WORKING_YET + /* 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(); -#endif + + 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); } |