diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d1bcde83b8077..02649112b8cd2 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2953,7 +2953,7 @@ static int innobase_close_connection(handlerton *, THD *thd) noexcept case TRX_STATE_PREPARED: if (trx->has_logged_persistent()) { - trx_disconnect_prepared(trx); + trx->disconnect_prepared(); return 0; } /* fall through */ diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 36105ad1c2b5a..2882bbee008e3 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -187,11 +187,7 @@ static bool trx_i_s_common_fill_table(THD *thd, TABLE_LIST *tables) RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); /* update the cache */ - trx_i_s_cache_start_write(trx_i_s_cache); - trx_i_s_possibly_fetch_data_into_cache(trx_i_s_cache); - trx_i_s_cache_end_write(trx_i_s_cache); - - if (trx_i_s_cache_is_truncated(trx_i_s_cache)) + if (trx_i_s_possibly_fetch_data_into_cache()) sql_print_warning("InnoDB: Data in %.*s truncated due to memory limit" " of %u bytes", int(tables->schema_table_name.length), @@ -380,22 +376,20 @@ static int fill_innodb_trx_from_cache(THD *thd, TABLE_LIST *tables, Item*) struct cache { - cache() { trx_i_s_cache_start_read(trx_i_s_cache); } - ~cache() { trx_i_s_cache_end_read(trx_i_s_cache); } + cache() { trx_i_s_cache_start_read(); } + ~cache() { trx_i_s_cache_end_read(); } } c; Field** fields = tables->table->field; - rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache, - I_S_INNODB_TRX); + rows_num = trx_i_s_cache_get_rows_used(I_S_INNODB_TRX); for (i = 0; i < rows_num; i++) { i_s_trx_row_t* row; row = (i_s_trx_row_t*) - trx_i_s_cache_get_nth_row( - trx_i_s_cache, I_S_INNODB_TRX, i); + trx_i_s_cache_get_nth_row(I_S_INNODB_TRX, i); /* trx_id */ OK(fields[IDX_TRX_ID]->store(row->trx_id, true)); @@ -669,14 +663,13 @@ fill_innodb_locks_from_cache( struct cache { - cache() { trx_i_s_cache_start_read(trx_i_s_cache); } - ~cache() { trx_i_s_cache_end_read(trx_i_s_cache); } + cache() { trx_i_s_cache_start_read(); } + ~cache() { trx_i_s_cache_end_read(); } } c; Field** fields = tables->table->field; - rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache, - I_S_INNODB_LOCKS); + rows_num = trx_i_s_cache_get_rows_used(I_S_INNODB_LOCKS); for (i = 0; i < rows_num; i++) { @@ -685,8 +678,7 @@ fill_innodb_locks_from_cache( const char* bufend; row = (i_s_locks_row_t*) - trx_i_s_cache_get_nth_row( - trx_i_s_cache, I_S_INNODB_LOCKS, i); + trx_i_s_cache_get_nth_row(I_S_INNODB_LOCKS, i); /* lock_id */ trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id)); @@ -855,22 +847,20 @@ fill_innodb_lock_waits_from_cache( struct cache { - cache() { trx_i_s_cache_start_read(trx_i_s_cache); } - ~cache() { trx_i_s_cache_end_read(trx_i_s_cache); } + cache() { trx_i_s_cache_start_read(); } + ~cache() { trx_i_s_cache_end_read(); } } c; Field** fields = tables->table->field; - rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache, - I_S_INNODB_LOCK_WAITS); + rows_num = trx_i_s_cache_get_rows_used(I_S_INNODB_LOCK_WAITS); for (i = 0; i < rows_num; i++) { i_s_lock_waits_row_t* row; row = (i_s_lock_waits_row_t*) - trx_i_s_cache_get_nth_row( - trx_i_s_cache, I_S_INNODB_LOCK_WAITS, i); + trx_i_s_cache_get_nth_row(I_S_INNODB_LOCK_WAITS, i); /* requesting_trx_id */ OK(fields[IDX_REQUESTING_TRX_ID]->store( diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h index f549745baa276..7fc37ec40bda7 100644 --- a/storage/innobase/include/trx0i_s.h +++ b/storage/innobase/include/trx0i_s.h @@ -146,9 +146,6 @@ struct i_s_lock_waits_row_t { const i_s_locks_row_t* blocking_lock_row; /*!< blocking lock */ }; -/** Cache of INFORMATION_SCHEMA table data */ -struct trx_i_s_cache_t; - /** Auxiliary enum used by functions that need to select one of the INFORMATION_SCHEMA tables */ enum i_s_table { @@ -157,90 +154,42 @@ enum i_s_table { I_S_INNODB_LOCK_WAITS /*!< INFORMATION_SCHEMA.innodb_lock_waits */ }; -/** This is the intermediate buffer where data needed to fill the -INFORMATION SCHEMA tables is fetched and later retrieved by the C++ -code in handler/i_s.cc. */ -extern trx_i_s_cache_t* trx_i_s_cache; - /*******************************************************************//** Initialize INFORMATION SCHEMA trx related cache. */ -void -trx_i_s_cache_init( -/*===============*/ - trx_i_s_cache_t* cache); /*!< out: cache to init */ +void trx_i_s_cache_init(); /*******************************************************************//** Free the INFORMATION SCHEMA trx related cache. */ -void -trx_i_s_cache_free( -/*===============*/ - trx_i_s_cache_t* cache); /*!< in/out: cache to free */ +void trx_i_s_cache_free(); /*******************************************************************//** Issue a shared/read lock on the tables cache. */ -void -trx_i_s_cache_start_read( -/*=====================*/ - trx_i_s_cache_t* cache); /*!< in: cache */ +void trx_i_s_cache_start_read() noexcept; /*******************************************************************//** Release a shared/read lock on the tables cache. */ -void -trx_i_s_cache_end_read( -/*===================*/ - trx_i_s_cache_t* cache); /*!< in: cache */ - -/*******************************************************************//** -Issue an exclusive/write lock on the tables cache. */ -void -trx_i_s_cache_start_write( -/*======================*/ - trx_i_s_cache_t* cache); /*!< in: cache */ - -/*******************************************************************//** -Release an exclusive/write lock on the tables cache. */ -void -trx_i_s_cache_end_write( -/*====================*/ - trx_i_s_cache_t* cache); /*!< in: cache */ - +void trx_i_s_cache_end_read() noexcept; /*******************************************************************//** Retrieves the number of used rows in the cache for a given INFORMATION SCHEMA table. +@param table table to be read @return number of rows */ -ulint -trx_i_s_cache_get_rows_used( -/*========================*/ - trx_i_s_cache_t* cache, /*!< in: cache */ - enum i_s_table table); /*!< in: which table */ +ulint trx_i_s_cache_get_rows_used(i_s_table table); /*******************************************************************//** Retrieves the nth row in the cache for a given INFORMATION SCHEMA table. +@param table table to read +@param n row number @return row */ -void* -trx_i_s_cache_get_nth_row( -/*======================*/ - trx_i_s_cache_t* cache, /*!< in: cache */ - enum i_s_table table, /*!< in: which table */ - ulint n); /*!< in: row number */ +void *trx_i_s_cache_get_nth_row(i_s_table table, ulint n); /*******************************************************************//** Update the transactions cache if it has not been read for some time. -@return 0 - fetched, 1 - not */ -int -trx_i_s_possibly_fetch_data_into_cache( -/*===================================*/ - trx_i_s_cache_t* cache); /*!< in/out: cache */ +@retval false when fetched or cached +@retval true if fetched but the cache was truncated */ +bool trx_i_s_possibly_fetch_data_into_cache(); -/*******************************************************************//** -Returns true, if the data in the cache is truncated due to the memory -limit posed by TRX_I_S_MEM_LIMIT. -@return TRUE if truncated */ -bool -trx_i_s_cache_is_truncated( -/*=======================*/ - trx_i_s_cache_t* cache); /*!< in: cache */ /** The maximum length of a resulting lock_id_size in trx_i_s_create_lock_id(), not including the terminating NUL. ":%lu:%lu:%lu" -> 63 chars */ diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index c2dbcc604d1dc..6e514331d7b58 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -825,9 +825,6 @@ class thread_safe_trx_ilist_t mysql_mutex_unlock(&mutex); } - void freeze() const { mysql_mutex_lock(&mutex); } - void unfreeze() const { mysql_mutex_unlock(&mutex); } - private: alignas(CPU_LEVEL1_DCACHE_LINESIZE) mutable mysql_mutex_t mutex; alignas(CPU_LEVEL1_DCACHE_LINESIZE) ilist trx_list; diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 61ecae6efc8f4..784ae19274746 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -73,10 +73,6 @@ trx_t *trx_create(); /** At shutdown, frees a transaction object. */ void trx_free_at_shutdown(trx_t *trx); -/** Disconnect a prepared transaction from MySQL. -@param[in,out] trx transaction */ -void trx_disconnect_prepared(trx_t *trx); - /** Initialize (resurrect) transactions at startup. */ dberr_t trx_lists_init_at_db_start(); @@ -730,7 +726,7 @@ struct trx_t : ilist_node<> This field is accessed by the thread that owns the transaction, without holding any mutex. There is only one foreign-thread access in trx_print_low() - and a possible race condition with trx_disconnect_prepared(). */ + and a possible race condition with disconnect_prepared(). */ bool is_recovered; const char* op_info; /*!< English text describing the current operation, or an empty @@ -968,6 +964,8 @@ struct trx_t : ilist_node<> public: /** Commit the transaction. */ void commit() noexcept; + /** Disconnect a prepared transaction */ + void disconnect_prepared() noexcept; /** Try to drop a persistent table. @param table persistent table diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index def31335d3468..a674af4f2c943 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -621,7 +621,7 @@ static void srv_init() &page_zip_stat_per_index_mutex, nullptr); /* Initialize some INFORMATION SCHEMA internal structures */ - trx_i_s_cache_init(trx_i_s_cache); + trx_i_s_cache_init(); } /*********************************************************************//** @@ -638,7 +638,7 @@ srv_free(void) mysql_mutex_destroy(&page_zip_stat_per_index_mutex); mysql_mutex_destroy(&srv_sys.tasks_mutex); - trx_i_s_cache_free(trx_i_s_cache); + trx_i_s_cache_free(); srv_thread_pool_end(); } diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index c1784b94bb172..70f97faafca74 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -133,11 +133,7 @@ struct trx_i_s_cache_t { /** This is the intermediate buffer where data needed to fill the INFORMATION SCHEMA tables is fetched and later retrieved by the C++ code in handler/i_s.cc. */ -static trx_i_s_cache_t trx_i_s_cache_static; -/** This is the intermediate buffer where data needed to fill the -INFORMATION SCHEMA tables is fetched and later retrieved by the C++ -code in handler/i_s.cc. */ -trx_i_s_cache_t* trx_i_s_cache = &trx_i_s_cache_static; +static trx_i_s_cache_t cache; /** @return the heap number of a record lock @retval 0xFFFF for table locks */ @@ -1045,8 +1041,11 @@ static void fetch_data_into_cache_low(trx_i_s_cache_t *cache, const trx_t *trx) static void fetch_data_into_cache(trx_i_s_cache_t *cache) { - LockMutexGuard g{SRW_LOCK_CALL}; + /* these are protected by cache->rw_lock.wr_lock() */ trx_i_s_cache_clear(cache); + /* this flag may be set by fetch_data_into_cache_low() below */ + cache->is_truncated= false; + LockMutexGuard g{SRW_LOCK_CALL}; /* Capture the state of transactions */ trx_sys.trx_list.for_each([cache](trx_t &trx) { @@ -1059,51 +1058,30 @@ static void fetch_data_into_cache(trx_i_s_cache_t *cache) trx.mutex_unlock(); } }); - cache->is_truncated= false; } /*******************************************************************//** Update the transactions cache if it has not been read for some time. -Called from handler/i_s.cc. -@return 0 - fetched, 1 - not */ -int -trx_i_s_possibly_fetch_data_into_cache( -/*===================================*/ - trx_i_s_cache_t* cache) /*!< in/out: cache */ +@retval false when fetched or cached +@retval true if fetched but the cache was truncated */ +bool trx_i_s_possibly_fetch_data_into_cache() { - if (!can_cache_be_updated(cache)) { - - return(1); - } - - /* We need to read trx_sys and record/table lock queues */ - fetch_data_into_cache(cache); - - /* update cache last read time */ - cache->last_read = my_interval_timer(); - - return(0); -} - -/*******************************************************************//** -Returns TRUE if the data in the cache is truncated due to the memory -limit posed by TRX_I_S_MEM_LIMIT. -@return TRUE if truncated */ -bool -trx_i_s_cache_is_truncated( -/*=======================*/ - trx_i_s_cache_t* cache) /*!< in: cache */ -{ - return(cache->is_truncated); + bool is_truncated= false; + cache.rw_lock.wr_lock(SRW_LOCK_CALL); + if (can_cache_be_updated(&cache)) + { + /* We need to read trx_sys and record/table lock queues */ + fetch_data_into_cache(&cache); + /* update cache last read time */ + cache.last_read= my_interval_timer(); + is_truncated= cache.is_truncated; + } + cache.rw_lock.wr_unlock(); + return is_truncated; } -/*******************************************************************//** -Initialize INFORMATION SCHEMA trx related cache. */ -void -trx_i_s_cache_init( -/*===============*/ - trx_i_s_cache_t* cache) /*!< out: cache to init */ +void trx_i_s_cache_init() { /* The latching is done in the following order: acquire trx_i_s_cache_t::rw_lock, rwlock @@ -1113,80 +1091,44 @@ trx_i_s_cache_init( acquire trx_i_s_cache_t::rw_lock, rdlock release trx_i_s_cache_t::rw_lock */ - cache->rw_lock.SRW_LOCK_INIT(trx_i_s_cache_lock_key); + cache.rw_lock.SRW_LOCK_INIT(trx_i_s_cache_lock_key); - cache->last_read = 0; + cache.last_read = 0; - table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t)); - table_cache_init(&cache->innodb_locks, sizeof(i_s_locks_row_t)); - table_cache_init(&cache->innodb_lock_waits, + table_cache_init(&cache.innodb_trx, sizeof(i_s_trx_row_t)); + table_cache_init(&cache.innodb_locks, sizeof(i_s_locks_row_t)); + table_cache_init(&cache.innodb_lock_waits, sizeof(i_s_lock_waits_row_t)); - cache->locks_hash.create(LOCKS_HASH_CELLS_NUM); + cache.locks_hash.create(LOCKS_HASH_CELLS_NUM); - cache->storage = ha_storage_create(CACHE_STORAGE_INITIAL_SIZE, + cache.storage = ha_storage_create(CACHE_STORAGE_INITIAL_SIZE, CACHE_STORAGE_HASH_CELLS); - cache->mem_allocd = 0; + cache.mem_allocd = 0; - cache->is_truncated = false; + cache.is_truncated = false; } -/*******************************************************************//** -Free the INFORMATION SCHEMA trx related cache. */ -void -trx_i_s_cache_free( -/*===============*/ - trx_i_s_cache_t* cache) /*!< in, own: cache to free */ +void trx_i_s_cache_free() { - cache->rw_lock.destroy(); - - cache->locks_hash.free(); - ha_storage_free(cache->storage); - table_cache_free(&cache->innodb_trx); - table_cache_free(&cache->innodb_locks); - table_cache_free(&cache->innodb_lock_waits); + cache.rw_lock.destroy(); + cache.locks_hash.free(); + ha_storage_free(cache.storage); + table_cache_free(&cache.innodb_trx); + table_cache_free(&cache.innodb_locks); + table_cache_free(&cache.innodb_lock_waits); } -/*******************************************************************//** -Issue a shared/read lock on the tables cache. */ -void -trx_i_s_cache_start_read( -/*=====================*/ - trx_i_s_cache_t* cache) /*!< in: cache */ -{ - cache->rw_lock.rd_lock(SRW_LOCK_CALL); -} - -/*******************************************************************//** -Release a shared/read lock on the tables cache. */ -void -trx_i_s_cache_end_read( -/*===================*/ - trx_i_s_cache_t* cache) /*!< in: cache */ -{ - cache->last_read = my_interval_timer(); - cache->rw_lock.rd_unlock(); -} - -/*******************************************************************//** -Issue an exclusive/write lock on the tables cache. */ -void -trx_i_s_cache_start_write( -/*======================*/ - trx_i_s_cache_t* cache) /*!< in: cache */ +void trx_i_s_cache_start_read() noexcept { - cache->rw_lock.wr_lock(SRW_LOCK_CALL); + cache.rw_lock.rd_lock(SRW_LOCK_CALL); } -/*******************************************************************//** -Release an exclusive/write lock on the tables cache. */ -void -trx_i_s_cache_end_write( -/*====================*/ - trx_i_s_cache_t* cache) /*!< in: cache */ +void trx_i_s_cache_end_read() noexcept { - cache->rw_lock.wr_unlock(); + cache.last_read= my_interval_timer(); + cache.rw_lock.rd_unlock(); } /*******************************************************************//** @@ -1196,55 +1138,33 @@ static i_s_table_cache_t* cache_select_table( /*===============*/ - trx_i_s_cache_t* cache, /*!< in: whole cache */ enum i_s_table table) /*!< in: which table */ { switch (table) { case I_S_INNODB_TRX: - return &cache->innodb_trx; + return &cache.innodb_trx; case I_S_INNODB_LOCKS: - return &cache->innodb_locks; + return &cache.innodb_locks; case I_S_INNODB_LOCK_WAITS: - return &cache->innodb_lock_waits; + return &cache.innodb_lock_waits; } ut_error; return NULL; } -/*******************************************************************//** -Retrieves the number of used rows in the cache for a given -INFORMATION SCHEMA table. -@return number of rows */ -ulint -trx_i_s_cache_get_rows_used( -/*========================*/ - trx_i_s_cache_t* cache, /*!< in: cache */ - enum i_s_table table) /*!< in: which table */ +ulint trx_i_s_cache_get_rows_used(i_s_table table) { - i_s_table_cache_t* table_cache; - - table_cache = cache_select_table(cache, table); - - return(table_cache->rows_used); + return cache_select_table(table)->rows_used; } -/*******************************************************************//** -Retrieves the nth row (zero-based) in the cache for a given -INFORMATION SCHEMA table. -@return row */ -void* -trx_i_s_cache_get_nth_row( -/*======================*/ - trx_i_s_cache_t* cache, /*!< in: cache */ - enum i_s_table table, /*!< in: which table */ - ulint n) /*!< in: row number */ +void *trx_i_s_cache_get_nth_row(i_s_table table, ulint n) { i_s_table_cache_t* table_cache; ulint i; void* row; - table_cache = cache_select_table(cache, table); + table_cache = cache_select_table(table); ut_a(n < table_cache->rows_used); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 2d2492600b5f9..abfa22810ed01 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -532,23 +532,19 @@ TRANSACTIONAL_TARGET void trx_free_at_shutdown(trx_t *trx) } -/** - Disconnect a prepared transaction from MySQL - @param[in,out] trx transaction -*/ -void trx_disconnect_prepared(trx_t *trx) +void trx_t::disconnect_prepared() noexcept { - ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED)); - ut_ad(trx->mysql_thd); - ut_ad(!trx->mysql_log_file_name); - trx->read_view.close(); - trx_sys.trx_list.freeze(); - trx->is_recovered= true; - trx->mysql_thd= NULL; - trx_sys.trx_list.unfreeze(); + ut_ad(trx_state_eq(this, TRX_STATE_PREPARED)); + ut_ad(mysql_thd); + ut_ad(!mysql_log_file_name); + read_view.close(); + mutex_lock(); + is_recovered= true; + mysql_thd= nullptr; + mutex_unlock(); /* todo/fixme: suggest to do it at innodb prepare */ - trx->will_lock= false; - trx_sys.rw_trx_hash.put_pins(trx); + will_lock= false; + trx_sys.rw_trx_hash.put_pins(this); } MY_ATTRIBUTE((nonnull, warn_unused_result))