diff --git a/dict/dict0dict.c b/dict/dict0dict.c index a36da9e2d6e..8b0c7185df0 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -794,16 +794,20 @@ dict_init(void) } /************************************************************************** -Returns a table object. NOTE! This is a high-level function to be used -mainly from outside the 'dict' directory. Inside this directory -dict_table_get_low is usually the appropriate function. */ +Returns a table object and optionally increment its MySQL open handle count. +NOTE! This is a high-level function to be used mainly from outside the +'dict' directory. Inside this directory dict_table_get_low is usually the +appropriate function. */ dict_table_t* dict_table_get( /*===========*/ /* out: table, NULL if does not exist */ - const char* table_name) /* in: table name */ + const char* table_name, /* in: table name */ + ibool inc_mysql_count) + /* in: whether to increment the open + handle count on the table */ { dict_table_t* table; @@ -811,42 +815,17 @@ dict_table_get( table = dict_table_get_low(table_name); - mutex_exit(&(dict_sys->mutex)); - - if (table != NULL) { - if (!table->stat_initialized) { - dict_update_statistics(table); - } - } - - return(table); -} - -/************************************************************************** -Returns a table object and increments MySQL open handle count on the table. */ - -dict_table_t* -dict_table_get_and_increment_handle_count( -/*======================================*/ - /* out: table, NULL if - does not exist */ - const char* table_name) /* in: table name */ -{ - dict_table_t* table; - - mutex_enter(&(dict_sys->mutex)); - - table = dict_table_get_low(table_name); - - if (table != NULL) { - + if (inc_mysql_count && table) { table->n_mysql_handles_opened++; } mutex_exit(&(dict_sys->mutex)); if (table != NULL) { - if (!table->stat_initialized && !table->ibd_file_missing) { + if (!table->stat_initialized) { + /* If table->ibd_file_missing == TRUE, this will + print an error message and return without doing + anything. */ dict_update_statistics(table); } } diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index ab6f14977cb..ebbbb6fcde4 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -40,9 +40,6 @@ have disables the InnoDB inlining in this file. */ #include #include #include - -#define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1)) - #include "ha_innodb.h" pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */ @@ -1257,18 +1254,6 @@ trx_is_interrupted( return(trx && trx->mysql_thd && ((THD*) trx->mysql_thd)->killed); } -/************************************************************************** -Obtain a pointer to the MySQL THD object, as in current_thd(). This -definition must match the one in sql/ha_innodb.cc! */ -extern "C" -void* -innobase_current_thd(void) -/*======================*/ - /* out: MySQL THD object */ -{ - return(current_thd); -} - /********************************************************************* Call this when you have opened a new table handle in HANDLER, before you call index_read_idx() etc. Actually, we can let the cursor stay open even @@ -2328,7 +2313,7 @@ ha_innobase::open( /* Get pointer to a table object in InnoDB dictionary cache */ - ib_table = dict_table_get_and_increment_handle_count(norm_name); + ib_table = dict_table_get(norm_name, TRUE); if (NULL == ib_table) { ut_print_timestamp(stderr); @@ -2490,7 +2475,7 @@ get_field_offset( /****************************************************************** Checks if a field in a record is SQL NULL. Uses the record format information in table to track the null bit in record. */ -inline +static inline uint field_in_record_is_null( /*====================*/ @@ -4915,7 +4900,7 @@ ha_innobase::create( log_buffer_flush_to_disk(); - innobase_table = dict_table_get(norm_name); + innobase_table = dict_table_get(norm_name, FALSE); DBUG_ASSERT(innobase_table != 0); @@ -5526,16 +5511,10 @@ ha_innobase::info( prebuilt->trx->op_info = (char*) "returning various info to MySQL"; - if (ib_table->space != 0) { - my_snprintf(path, sizeof(path), "%s/%s%s", - mysql_data_home, ib_table->name, ".ibd"); - unpack_filename(path,path); - } else { - my_snprintf(path, sizeof(path), "%s/%s%s", + my_snprintf(path, sizeof(path), "%s/%s%s", mysql_data_home, ib_table->name, reg_ext); - unpack_filename(path,path); - } + unpack_filename(path,path); /* Note that we do not know the access time of the table, nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ @@ -7344,7 +7323,6 @@ innobase_get_at_most_n_mbchars( } } -extern "C" { /********************************************************************** This function returns true if @@ -7354,33 +7332,34 @@ is either REPLACE or LOAD DATA INFILE REPLACE. 2) SQL-query in the current thread is INSERT ON DUPLICATE KEY UPDATE. -NOTE that /mysql/innobase/row/row0ins.c must contain the +NOTE that storage/innobase/row/row0ins.c must contain the prototype for this function ! */ - +extern "C" ibool innobase_query_is_update(void) /*==========================*/ { - THD* thd; + THD* thd = current_thd; - thd = (THD *)innobase_current_thd(); + if (!thd) { + /* InnoDB's internal threads may run InnoDB stored procedures + that call this function. Then current_thd is not defined + (it is probably NULL). */ - if (thd->lex->sql_command == SQLCOM_REPLACE || - thd->lex->sql_command == SQLCOM_REPLACE_SELECT || - (thd->lex->sql_command == SQLCOM_LOAD && - thd->lex->duplicates == DUP_REPLACE)) { - - return(1); + return(FALSE); } - if (thd->lex->sql_command == SQLCOM_INSERT && - thd->lex->duplicates == DUP_UPDATE) { - - return(1); + switch (thd->lex->sql_command) { + case SQLCOM_REPLACE: + case SQLCOM_REPLACE_SELECT: + return(TRUE); + case SQLCOM_LOAD: + return(thd->lex->duplicates == DUP_REPLACE); + case SQLCOM_INSERT: + return(thd->lex->duplicates == DUP_UPDATE); + default: + return(FALSE); } - - return(0); -} } /*********************************************************************** diff --git a/include/btr0sea.h b/include/btr0sea.h index 343d90787f9..c534bce7711 100644 --- a/include/btr0sea.h +++ b/include/btr0sea.h @@ -183,7 +183,7 @@ struct btr_search_struct{ number of full fields */ ulint n_bytes; /* recommended prefix: number of bytes in an incomplete field; - cf. BTR_PAGE_MAX_REC_SIZE */ + see also BTR_PAGE_MAX_REC_SIZE */ ibool left_side; /* TRUE or FALSE, depending on whether the leftmost record of several records with the same prefix should be indexed in the diff --git a/include/data0type.ic b/include/data0type.ic index 6ef482ee7d7..e4401c30abe 100644 --- a/include/data0type.ic +++ b/include/data0type.ic @@ -65,8 +65,8 @@ dtype_get_mblen( innobase_get_cset_width(dtype_get_charset_coll(prtype), mbminlen, mbmaxlen); ut_ad(*mbminlen <= *mbmaxlen); - ut_ad(*mbminlen <= 2); /* cf. the bit-field in dtype_t */ - ut_ad(*mbmaxlen < 1 << 3); /* cf. the bit-field in dtype_t */ + ut_ad(*mbminlen <= 2); /* mbminlen in dtype_t is 0..3 */ + ut_ad(*mbmaxlen < 1 << 3); /* mbmaxlen in dtype_t is 0..7 */ #else /* !UNIV_HOTBACKUP */ ut_a(mtype <= DATA_BINARY); *mbminlen = *mbmaxlen = 1; diff --git a/include/dict0dict.h b/include/dict0dict.h index 5c5280a69bb..5deeb02132c 100644 --- a/include/dict0dict.h +++ b/include/dict0dict.h @@ -333,26 +333,20 @@ dict_foreign_parse_drop_constraints( const char*** constraints_to_drop); /* out: id's of the constraints to drop */ /************************************************************************** -Returns a table object. NOTE! This is a high-level function to be used -mainly from outside the 'dict' directory. Inside this directory -dict_table_get_low is usually the appropriate function. */ +Returns a table object and optionally increment its MySQL open handle count. +NOTE! This is a high-level function to be used mainly from outside the +'dict' directory. Inside this directory dict_table_get_low is usually the +appropriate function. */ dict_table_t* dict_table_get( /*===========*/ /* out: table, NULL if does not exist */ - const char* table_name); /* in: table name */ -/************************************************************************** -Returns a table object and increments MySQL open handle count on the table. -*/ - -dict_table_t* -dict_table_get_and_increment_handle_count( -/*======================================*/ - /* out: table, NULL if - does not exist */ - const char* table_name); /* in: table name */ + const char* table_name, /* in: table name */ + ibool inc_mysql_count); + /* in: whether to increment the open + handle count on the table */ /************************************************************************** Returns a table object based on table id. */ diff --git a/include/sync0sync.h b/include/sync0sync.h index b5841be3a8c..58df610a44d 100644 --- a/include/sync0sync.h +++ b/include/sync0sync.h @@ -516,12 +516,6 @@ to 20 microseconds. */ #define SYNC_SPIN_ROUNDS srv_n_spin_wait_rounds -#define SYNC_INFINITE_TIME ((ulint)(-1)) - -/* Means that a timeout elapsed when waiting */ - -#define SYNC_TIME_EXCEEDED (ulint)1 - /* The number of system calls made in this module. Intended for performance monitoring. */ diff --git a/include/univ.i b/include/univ.i index 3edd2cd7fae..9ebb0d59364 100644 --- a/include/univ.i +++ b/include/univ.i @@ -77,25 +77,37 @@ memory is read outside the allocated blocks. */ /* Make a non-inline debug version */ #if 0 -#define UNIV_DEBUG_VALGRIND -#define UNIV_DEBUG_PRINT -#define UNIV_BUF_DEBUG -#define UNIV_DEBUG -#define UNIV_DEBUG_FILE_ACCESSES -#define UNIV_LIST_DEBUG -#define UNIV_MEM_DEBUG -#define UNIV_IBUF_DEBUG -#define UNIV_SYNC_DEBUG -#define UNIV_SEARCH_DEBUG -#define UNIV_SYNC_PERF_STAT -#define UNIV_SEARCH_PERF_STAT -#define UNIV_SRV_PRINT_LATCH_WAITS -#define UNIV_BTR_PRINT +#define UNIV_DEBUG_VALGRIND /* Enable extra + Valgrind instrumentation */ +#define UNIV_DEBUG_PRINT /* Enable the compilation of + some debug print functions */ +#define UNIV_BUF_DEBUG /* Enable buffer pool + debugging without UNIV_DEBUG */ +#define UNIV_DEBUG /* Enable ut_ad() assertions */ +#define UNIV_DEBUG_FILE_ACCESSES /* Debug .ibd file access + (field file_page_was_freed + in buf_page_t) */ +#define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */ +#define UNIV_MEM_DEBUG /* detect memory leaks etc */ +#define UNIV_IBUF_DEBUG /* debug the insert buffer; +this limits the database to IBUF_COUNT_N_SPACES and IBUF_COUNT_N_PAGES, +and the insert buffer must be empty when the database is started */ +#define UNIV_SYNC_DEBUG /* debug mutex and latch +operations (very slow); also UNIV_DEBUG must be defined */ +#define UNIV_SEARCH_DEBUG /* debug B-tree comparisons */ +#define UNIV_SYNC_PERF_STAT /* operation counts for + rw-locks and mutexes */ +#define UNIV_SEARCH_PERF_STAT /* statistics for the + adaptive hash index */ +#define UNIV_SRV_PRINT_LATCH_WAITS /* enable diagnostic output + in sync0sync.c */ +#define UNIV_BTR_PRINT /* enable functions for + printing B-trees */ #define UNIV_ZIP_DEBUG #endif -#define UNIV_BTR_DEBUG -#define UNIV_LIGHT_MEM_DEBUG +#define UNIV_BTR_DEBUG /* check B-tree links */ +#define UNIV_LIGHT_MEM_DEBUG /* light memory debugging */ #ifdef HAVE_purify /* The following sets all new allocated memory to zero before use: diff --git a/include/ut0ut.h b/include/ut0ut.h index 3aa52a27f88..0e9423be86c 100644 --- a/include/ut0ut.h +++ b/include/ut0ut.h @@ -127,7 +127,8 @@ ulint ut_2_power_up( /*==========*/ /* out: first power of 2 which is >= n */ - ulint n); /* in: number != 0 */ + ulint n) /* in: number != 0 */ + __attribute__((const)); /**************************************************************** Sort function for ulint arrays. */ diff --git a/log/log0recv.c b/log/log0recv.c index 12ce59bb192..c5f87657fac 100644 --- a/log/log0recv.c +++ b/log/log0recv.c @@ -34,6 +34,7 @@ Created 9/20/1997 Heikki Tuuri #include "btr0cur.h" #include "dict0boot.h" #include "fil0fil.h" +#include "sync0sync.h" #ifdef UNIV_HOTBACKUP /* This is set to FALSE if the backup was originally taken with the @@ -191,6 +192,7 @@ recv_sys_empty_hash(void) recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 256); } +#ifndef UNIV_LOG_DEBUG /************************************************************ Frees the recovery system. */ static @@ -210,6 +212,7 @@ recv_sys_free(void) mutex_exit(&(recv_sys->mutex)); } +#endif /* UNIV_LOG_DEBUG */ /************************************************************ Truncates possible corrupted or extra records from a log group. */ @@ -2887,6 +2890,15 @@ recv_recovery_from_checkpoint_finish(void) #ifndef UNIV_LOG_DEBUG recv_sys_free(); #endif + +#ifdef UNIV_SYNC_DEBUG + /* Wait for a while so that created threads have time to suspend + themselves before we switch the latching order checks on */ + os_thread_sleep(1000000); + + /* Switch latching order checks on in sync0sync.c */ + sync_order_checks_on = TRUE; +#endif if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) { /* Rollback the uncommitted transactions which have no user session */ diff --git a/que/que0que.c b/que/que0que.c index b2663e30879..f5a63ae6ffa 100644 --- a/que/que0que.c +++ b/que/que0que.c @@ -335,6 +335,8 @@ que_fork_start_command( que_fork_t* fork) /* in: a query fork */ { que_thr_t* thr; + que_thr_t* suspended_thr = NULL; + que_thr_t* completed_thr = NULL; fork->state = QUE_FORK_ACTIVE; @@ -344,14 +346,18 @@ que_fork_start_command( but in a parallelized select, which necessarily is non-scrollable, there may be several to choose from */ - /*--------------------------------------------------------------- - First we try to find a query thread in the QUE_THR_COMMAND_WAIT state - */ + /* First we try to find a query thread in the QUE_THR_COMMAND_WAIT + state. Then we try to find a query thread in the QUE_THR_SUSPENDED + state, finally we try to find a query thread in the QUE_THR_COMPLETED + state */ thr = UT_LIST_GET_FIRST(fork->thrs); - while (thr != NULL) { - if (thr->state == QUE_THR_COMMAND_WAIT) { + /* We make a single pass over the thr list within which we note which + threads are ready to run. */ + while (thr) { + switch (thr->state) { + case QUE_THR_COMMAND_WAIT: /* We have to send the initial message to query thread to start it */ @@ -359,49 +365,44 @@ que_fork_start_command( que_thr_init_command(thr); return(thr); - } - ut_ad(thr->state != QUE_THR_LOCK_WAIT); - - thr = UT_LIST_GET_NEXT(thrs, thr); - } - - /*---------------------------------------------------------------- - Then we try to find a query thread in the QUE_THR_SUSPENDED state */ - - thr = UT_LIST_GET_FIRST(fork->thrs); - - while (thr != NULL) { - if (thr->state == QUE_THR_SUSPENDED) { + case QUE_THR_SUSPENDED: /* In this case the execution of the thread was suspended: no initial message is needed because execution can continue from where it was left */ + if (!suspended_thr) { + suspended_thr = thr; + } - que_thr_move_to_run_state(thr); + break; + + case QUE_THR_COMPLETED: + if (!completed_thr) { + completed_thr = thr; + } + + break; + + case QUE_THR_LOCK_WAIT: + ut_error; - return(thr); } thr = UT_LIST_GET_NEXT(thrs, thr); } - /*----------------------------------------------------------------- - Then we try to find a query thread in the QUE_THR_COMPLETED state */ + if (suspended_thr) { - thr = UT_LIST_GET_FIRST(fork->thrs); + thr = suspended_thr; + que_thr_move_to_run_state(thr); - while (thr != NULL) { - if (thr->state == QUE_THR_COMPLETED) { - que_thr_init_command(thr); + } else if (completed_thr) { - return(thr); - } - - thr = UT_LIST_GET_NEXT(thrs, thr); + thr = completed_thr; + que_thr_init_command(thr); } - /* Else we return NULL */ - return(NULL); + return(thr); } /************************************************************************** diff --git a/row/row0ins.c b/row/row0ins.c index 0192fcdff27..d3fae6cc52d 100644 --- a/row/row0ins.c +++ b/row/row0ins.c @@ -1535,7 +1535,8 @@ row_ins_check_foreign_constraints( if (foreign->foreign_index == index) { if (foreign->referenced_table == NULL) { - dict_table_get(foreign->referenced_table_name); + dict_table_get(foreign->referenced_table_name, + FALSE); } if (0 == trx->dict_operation_lock_mode) { diff --git a/row/row0sel.c b/row/row0sel.c index ae3ea234d88..107f835a51d 100644 --- a/row/row0sel.c +++ b/row/row0sel.c @@ -4506,7 +4506,7 @@ row_search_check_if_query_cache_permitted( dict_table_t* table; ibool ret = FALSE; - table = dict_table_get(norm_name); + table = dict_table_get(norm_name, FALSE); if (table == NULL) { diff --git a/row/row0upd.c b/row/row0upd.c index 92518565c69..8139ffa696e 100644 --- a/row/row0upd.c +++ b/row/row0upd.c @@ -203,7 +203,8 @@ row_upd_check_references_constraints( foreign->n_fields))) { if (foreign->foreign_table == NULL) { - dict_table_get(foreign->foreign_table_name); + dict_table_get(foreign->foreign_table_name, + FALSE); } if (foreign->foreign_table) { diff --git a/srv/srv0start.c b/srv/srv0start.c index 3091835b8cd..c99c28d0121 100644 --- a/srv/srv0start.c +++ b/srv/srv0start.c @@ -1558,17 +1558,6 @@ innobase_start_or_create_for_mysql(void) srv_was_started = TRUE; srv_is_being_started = FALSE; -#ifdef UNIV_SYNC_DEBUG - /* Wait a while so that the created threads have time to suspend - themselves before we switch sync debugging on; otherwise a thread may - execute mutex_enter() before the checks are on, and mutex_exit() after - the checks are on, which will cause an assertion failure in sync - debug. */ - - os_thread_sleep(3000000); - sync_order_checks_on = TRUE; -#endif - if (trx_doublewrite == NULL) { /* Create the doublewrite buffer to a new tablespace */ diff --git a/trx/trx0roll.c b/trx/trx0roll.c index e0dc95cac0d..4d82c22d70b 100644 --- a/trx/trx0roll.c +++ b/trx/trx0roll.c @@ -131,8 +131,26 @@ trx_rollback_for_mysql( trx->op_info = "rollback"; - err = trx_general_rollback_for_mysql(trx, FALSE, NULL); + /* If we are doing the XA recovery of prepared transactions, then + the transaction object does not have an InnoDB session object, and we + set a dummy session that we use for all MySQL transactions. */ + mutex_enter(&kernel_mutex); + + if (trx->sess == NULL) { + /* Open a dummy session */ + + if (!trx_dummy_sess) { + trx_dummy_sess = sess_open(); + } + + trx->sess = trx_dummy_sess; + } + + mutex_exit(&kernel_mutex); + + err = trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx->op_info = ""; return(err); diff --git a/trx/trx0trx.c b/trx/trx0trx.c index 8b8e7f6ba74..8270fc48794 100644 --- a/trx/trx0trx.c +++ b/trx/trx0trx.c @@ -1595,6 +1595,24 @@ trx_commit_for_mysql( trx->op_info = "committing"; + /* If we are doing the XA recovery of prepared transactions, then + the transaction object does not have an InnoDB session object, and we + set the dummy session that we use for all MySQL transactions. */ + + mutex_enter(&kernel_mutex); + + if (trx->sess == NULL) { + /* Open a dummy session */ + + if (!trx_dummy_sess) { + trx_dummy_sess = sess_open(); + } + + trx->sess = trx_dummy_sess; + } + + mutex_exit(&kernel_mutex); + trx_start_if_not_started(trx); mutex_enter(&kernel_mutex);