diff options
Diffstat (limited to 'innobase/srv/srv0start.c')
-rw-r--r-- | innobase/srv/srv0start.c | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c new file mode 100644 index 00000000000..f627e5d6aa5 --- /dev/null +++ b/innobase/srv/srv0start.c @@ -0,0 +1,700 @@ +/************************************************************************ +Starts the Innobase 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 "com0com.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 measure_cont = FALSE; + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; + +#define SRV_MAX_N_IO_THREADS 1000 + +ulint n[SRV_MAX_N_IO_THREADS + 5]; +os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; + +#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD +#define SRV_MAX_N_PENDING_SYNC_IOS 100 + +#define SRV_MAX_N_OPEN_FILES 25 + +#define SRV_LOG_SPACE_FIRST_ID 1000000000 + +/************************************************************************ +I/o-handler thread function. */ +static +ulint +io_handler_thread( +/*==============*/ + void* arg) +{ + ulint segment; + ulint i; + + segment = *((ulint*)arg); + +/* printf("Io handler thread %lu starts\n", segment); */ + + for (i = 0;; i++) { + fil_aio_wait(segment); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + } + + return(0); +} + +/************************************************************************* +Creates or opens the log files. */ +static +ulint +open_or_create_log_file( +/*====================*/ + /* out: DB_SUCCESS or error code */ + ibool create_new_db, /* in: TRUE if we should create a + new database */ + ibool* log_file_created, /* out: TRUE if new log file + created */ + 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; + + 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, &ret); + + if (ret == FALSE) { + if (os_file_get_last_error() != OS_FILE_ALREADY_EXISTS) { + fprintf(stderr, + "Innobase: Error in creating or opening %s\n", name); + + return(DB_ERROR); + } + + files[i] = os_file_create( + name, OS_FILE_OPEN, OS_FILE_AIO, &ret); + if (!ret) { + fprintf(stderr, + "Innobase: Error in opening %s\n", name); + + return(DB_ERROR); + } + + ret = os_file_get_size(files[i], &size, &size_high); + ut_a(ret); + + if (size != UNIV_PAGE_SIZE * srv_log_file_size + || size_high != 0) { + fprintf(stderr, + "Innobase: Error: log file %s is of different size\n" + "Innobase: than specified in the .cnf file!\n", name); + + return(DB_ERROR); + } + } else { + *log_file_created = TRUE; + + fprintf(stderr, + "Innobase: Log file %s did not exist: new to be created\n", + name); + ret = os_file_set_size(name, files[i], + UNIV_PAGE_SIZE * srv_log_file_size, 0); + if (!ret) { + fprintf(stderr, + "Innobase: 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("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. */ +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; + char name[10000]; + + ut_a(srv_n_data_files < 1000); + + *sum_of_new_sizes = 0; + + *create_new_db = FALSE; + + for (i = 0; i < srv_n_data_files; 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, &ret); + if (ret == FALSE) { + if (os_file_get_last_error() != + OS_FILE_ALREADY_EXISTS) { + fprintf(stderr, + "Innobase: Error in creating or opening %s\n", + name); + + return(DB_ERROR); + } + + if (one_created) { + fprintf(stderr, + "Innobase: Error: data files can only be added at the end\n"); + fprintf(stderr, + "Innobase: 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, &ret); + + if (!ret) { + fprintf(stderr, + "Innobase: Error in opening %s\n", name); + + return(DB_ERROR); + } + + ret = os_file_get_size(files[i], &size, &size_high); + ut_a(ret); + + if (size != UNIV_PAGE_SIZE * srv_data_file_sizes[i] + || size_high != 0) { + fprintf(stderr, + "Innobase: Error: data file %s is of different size\n" + "Innobase: than specified in the .cnf file!\n", name); + + 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) { + fprintf(stderr, + "Innobase: Data file %s did not exist: new to be created\n", name); + } else { + fprintf(stderr, + "Innobase: The first specified data file %s did not exist:\n" + "Innobase: a new database to be created!\n", name); + *create_new_db = TRUE; + } + + printf("Innobase: Setting file %s size to %lu\n", + name, UNIV_PAGE_SIZE * srv_data_file_sizes[i]); + + ret = os_file_set_size(name, files[i], + UNIV_PAGE_SIZE * srv_data_file_sizes[i], 0); + + if (!ret) { + fprintf(stderr, + "Innobase: 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); +} + +/********************************************************************* +This thread is used to measure contention of latches. */ +static +ulint +test_measure_cont( +/*==============*/ + void* arg) +{ + ulint i, j; + ulint pcount, kcount, s_scount, s_xcount, s_mcount, lcount; + + UT_NOT_USED(arg); + + fprintf(stderr, "Starting contention measurement\n"); + + for (i = 0; i < 1000; i++) { + + pcount = 0; + kcount = 0; + s_scount = 0; + s_xcount = 0; + s_mcount = 0; + lcount = 0; + + for (j = 0; j < 100; j++) { + + if (srv_measure_by_spin) { + ut_delay(ut_rnd_interval(0, 20000)); + } else { + os_thread_sleep(20000); + } + + if (kernel_mutex.lock_word) { + kcount++; + } + + if (buf_pool->mutex.lock_word) { + pcount++; + } + + if (log_sys->mutex.lock_word) { + lcount++; + } + + if (btr_search_latch.reader_count) { + s_scount++; + } + + if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) { + s_xcount++; + } + + if (btr_search_latch.mutex.lock_word) { + s_mcount++; + } + } + + fprintf(stderr, + "Mutex res. l %lu, p %lu, k %lu s x %lu s s %lu s mut %lu of %lu\n", + lcount, pcount, kcount, s_xcount, s_scount, s_mcount, j); + + sync_print_wait_info(); + + fprintf(stderr, + "log i/o %lu n non sea %lu n succ %lu n h fail %lu\n", + log_sys->n_log_ios, btr_cur_n_non_sea, + btr_search_n_succ, btr_search_n_hash_fail); + } + + return(0); +} + +/******************************************************************** +Starts Innobase 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 */ +{ + ulint i; + ulint k; + ulint err; + 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; + mtr_t mtr; + + log_do_write = TRUE; +/* yydebug = TRUE; */ + + os_aio_use_native_aio = srv_use_native_aio; + + err = srv_boot(); + + if (err != DB_SUCCESS) { + + return((int) err); + } + +#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_ASYNC_IO + /* On NT always use aio */ + os_aio_use_native_aio = TRUE; +#endif + + if (!os_aio_use_native_aio) { + os_aio_init(4 * 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); + +#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++) { + n[i] = i; + + os_thread_create(io_handler_thread, n + i, thread_ids + i); + } + + 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) { + + return((int) err); + } + + for (k = 0; k < srv_n_log_groups; k++) { + + for (i = 0; i < srv_n_log_files; i++) { + + err = open_or_create_log_file(create_new_db, + &log_file_created, 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, + "Innobase: Error: all log files must be created at the same time.\n" + "Innobase: If you want bigger or smaller log files,\n" + "Innobase: shut down the database and make sure there\n" + "Innobase: were no errors in shutdown.\n" + "Innobase: Then delete the existing log files. Edit the .cnf file\n" + "Innobase: 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, + "Innobase: Cannot initialize created log files because\n" + "Innobase: data files were not in sync with each other\n" + "Innobase: 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, + "Innobase: Cannot initialize created log files because\n" + "Innobase: data files are corrupt, or new data files were\n" + "Innobase: created when the database was started previous\n" + "Innobase: time but the database was not shut down\n" + "Innobase: normally after that.\n"); + + return(DB_ERROR); + } + + mutex_enter(&(log_sys->mutex)); + + recv_reset_logs(ut_dulint_align_down(max_flushed_lsn, + OS_FILE_LOG_BLOCK_SIZE), + max_arch_log_no + 1, TRUE); + + mutex_exit(&(log_sys->mutex)); + } + + sess_sys_init_at_db_start(); + + if (create_new_db) { + mtr_start(&mtr); + + fsp_header_init(0, sum_of_new_sizes, &mtr); + + mtr_commit(&mtr); + + trx_sys_create(); + dict_create(); + + } else if (srv_archive_recovery) { + fprintf(stderr, + "Innobase: 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); + } + + trx_sys_init_at_db_start(); + dict_boot(); + + 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); + } + + trx_sys_init_at_db_start(); + dict_boot(); + + /* The following needs trx lists which are initialized in + trx_sys_init_at_db_start */ + + 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); + } + + 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); + } + + /* 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); + /* 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 */ + os_thread_create(&srv_lock_timeout_monitor_thread, NULL, + thread_ids + 2 + SRV_MAX_N_IO_THREADS); + fprintf(stderr, "Innobase: Started\n"); + + sync_order_checks_on = TRUE; + + /* buf_debug_prints = TRUE; */ + + return((int) DB_SUCCESS); +} + +/******************************************************************** +Shuts down the Innobase database. */ + +int +innobase_shutdown_for_mysql(void) +/*=============================*/ + /* out: DB_SUCCESS or error code */ +{ + /* Flush buffer pool to disk, write the current lsn to + the tablespace header(s), and copy all log data to archive */ + + logs_empty_and_mark_files_at_shutdown(); + + return((int) DB_SUCCESS); +} |