Commit f0f9ab69 authored by unknown's avatar unknown

Mbug#677407 / MySQL Bug#48883: Stale data from INNODB_LOCKS table.

The logic for how to check when to update the table cache for
INNODB_LOCKS with real data was flawed. This could result in both
not updating the cache often enough (when the table is queried
repeatedly with less than 100 milliseconds in-between) resulting
in stale data; as well as updating too often (when multiple
queries against the table start at around the same time).

This caused occasional test failures in innodb_information_schema.

Fix by updating the "last updated" timestamp in the right place,
when the cache is updated, not when it is read.
parent 3fb8bc16
...@@ -157,10 +157,6 @@ struct trx_i_s_cache_struct { ...@@ -157,10 +157,6 @@ struct trx_i_s_cache_struct {
ullint last_read; /*!< last time the cache was read; ullint last_read; /*!< last time the cache was read;
measured in microseconds since measured in microseconds since
epoch */ epoch */
mutex_t last_read_mutex;/*!< mutex protecting the
last_read member - it is updated
inside a shared lock of the
rw_lock member */
i_s_table_cache_t innodb_trx; /*!< innodb_trx table */ i_s_table_cache_t innodb_trx; /*!< innodb_trx table */
i_s_table_cache_t innodb_locks; /*!< innodb_locks table */ i_s_table_cache_t innodb_locks; /*!< innodb_locks table */
i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */ i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */
...@@ -1101,13 +1097,6 @@ can_cache_be_updated( ...@@ -1101,13 +1097,6 @@ can_cache_be_updated(
{ {
ullint now; ullint now;
/* Here we read cache->last_read without acquiring its mutex
because last_read is only updated when a shared rw lock on the
whole cache is being held (see trx_i_s_cache_end_read()) and
we are currently holding an exclusive rw lock on the cache.
So it is not possible for last_read to be updated while we are
reading it. */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX)); ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
#endif #endif
...@@ -1205,6 +1194,12 @@ trx_i_s_possibly_fetch_data_into_cache( ...@@ -1205,6 +1194,12 @@ trx_i_s_possibly_fetch_data_into_cache(
/*===================================*/ /*===================================*/
trx_i_s_cache_t* cache) /*!< in/out: cache */ trx_i_s_cache_t* cache) /*!< in/out: cache */
{ {
ullint now;
#ifdef UNIV_SYNC_DEBUG
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
#endif
if (!can_cache_be_updated(cache)) { if (!can_cache_be_updated(cache)) {
return(1); return(1);
...@@ -1217,6 +1212,10 @@ trx_i_s_possibly_fetch_data_into_cache( ...@@ -1217,6 +1212,10 @@ trx_i_s_possibly_fetch_data_into_cache(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
/* update cache last read time */
now = ut_time_us(NULL);
cache->last_read = now;
return(0); return(0);
} }
...@@ -1247,16 +1246,12 @@ trx_i_s_cache_init( ...@@ -1247,16 +1246,12 @@ trx_i_s_cache_init(
release kernel_mutex release kernel_mutex
release trx_i_s_cache_t::rw_lock release trx_i_s_cache_t::rw_lock
acquire trx_i_s_cache_t::rw_lock, S acquire trx_i_s_cache_t::rw_lock, S
acquire trx_i_s_cache_t::last_read_mutex
release trx_i_s_cache_t::last_read_mutex
release trx_i_s_cache_t::rw_lock */ release trx_i_s_cache_t::rw_lock */
rw_lock_create(&cache->rw_lock, SYNC_TRX_I_S_RWLOCK); rw_lock_create(&cache->rw_lock, SYNC_TRX_I_S_RWLOCK);
cache->last_read = 0; cache->last_read = 0;
mutex_create(&cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ);
table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t)); 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_locks, sizeof(i_s_locks_row_t));
table_cache_init(&cache->innodb_lock_waits, table_cache_init(&cache->innodb_lock_waits,
...@@ -1307,18 +1302,10 @@ trx_i_s_cache_end_read( ...@@ -1307,18 +1302,10 @@ trx_i_s_cache_end_read(
/*===================*/ /*===================*/
trx_i_s_cache_t* cache) /*!< in: cache */ trx_i_s_cache_t* cache) /*!< in: cache */
{ {
ullint now;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED)); ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED));
#endif #endif
/* update cache last read time */
now = ut_time_us(NULL);
mutex_enter(&cache->last_read_mutex);
cache->last_read = now;
mutex_exit(&cache->last_read_mutex);
rw_lock_s_unlock(&cache->rw_lock); rw_lock_s_unlock(&cache->rw_lock);
} }
......
...@@ -157,10 +157,6 @@ struct trx_i_s_cache_struct { ...@@ -157,10 +157,6 @@ struct trx_i_s_cache_struct {
ullint last_read; /*!< last time the cache was read; ullint last_read; /*!< last time the cache was read;
measured in microseconds since measured in microseconds since
epoch */ epoch */
mutex_t last_read_mutex;/*!< mutex protecting the
last_read member - it is updated
inside a shared lock of the
rw_lock member */
i_s_table_cache_t innodb_trx; /*!< innodb_trx table */ i_s_table_cache_t innodb_trx; /*!< innodb_trx table */
i_s_table_cache_t innodb_locks; /*!< innodb_locks table */ i_s_table_cache_t innodb_locks; /*!< innodb_locks table */
i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */ i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */
...@@ -1101,13 +1097,6 @@ can_cache_be_updated( ...@@ -1101,13 +1097,6 @@ can_cache_be_updated(
{ {
ullint now; ullint now;
/* Here we read cache->last_read without acquiring its mutex
because last_read is only updated when a shared rw lock on the
whole cache is being held (see trx_i_s_cache_end_read()) and
we are currently holding an exclusive rw lock on the cache.
So it is not possible for last_read to be updated while we are
reading it. */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX)); ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
#endif #endif
...@@ -1205,6 +1194,12 @@ trx_i_s_possibly_fetch_data_into_cache( ...@@ -1205,6 +1194,12 @@ trx_i_s_possibly_fetch_data_into_cache(
/*===================================*/ /*===================================*/
trx_i_s_cache_t* cache) /*!< in/out: cache */ trx_i_s_cache_t* cache) /*!< in/out: cache */
{ {
ullint now;
#ifdef UNIV_SYNC_DEBUG
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
#endif
if (!can_cache_be_updated(cache)) { if (!can_cache_be_updated(cache)) {
return(1); return(1);
...@@ -1217,6 +1212,10 @@ trx_i_s_possibly_fetch_data_into_cache( ...@@ -1217,6 +1212,10 @@ trx_i_s_possibly_fetch_data_into_cache(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
/* update cache last read time */
now = ut_time_us(NULL);
cache->last_read = now;
return(0); return(0);
} }
...@@ -1247,16 +1246,12 @@ trx_i_s_cache_init( ...@@ -1247,16 +1246,12 @@ trx_i_s_cache_init(
release kernel_mutex release kernel_mutex
release trx_i_s_cache_t::rw_lock release trx_i_s_cache_t::rw_lock
acquire trx_i_s_cache_t::rw_lock, S acquire trx_i_s_cache_t::rw_lock, S
acquire trx_i_s_cache_t::last_read_mutex
release trx_i_s_cache_t::last_read_mutex
release trx_i_s_cache_t::rw_lock */ release trx_i_s_cache_t::rw_lock */
rw_lock_create(&cache->rw_lock, SYNC_TRX_I_S_RWLOCK); rw_lock_create(&cache->rw_lock, SYNC_TRX_I_S_RWLOCK);
cache->last_read = 0; cache->last_read = 0;
mutex_create(&cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ);
table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t)); 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_locks, sizeof(i_s_locks_row_t));
table_cache_init(&cache->innodb_lock_waits, table_cache_init(&cache->innodb_lock_waits,
...@@ -1307,18 +1302,10 @@ trx_i_s_cache_end_read( ...@@ -1307,18 +1302,10 @@ trx_i_s_cache_end_read(
/*===================*/ /*===================*/
trx_i_s_cache_t* cache) /*!< in: cache */ trx_i_s_cache_t* cache) /*!< in: cache */
{ {
ullint now;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED)); ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED));
#endif #endif
/* update cache last read time */
now = ut_time_us(NULL);
mutex_enter(&cache->last_read_mutex);
cache->last_read = now;
mutex_exit(&cache->last_read_mutex);
rw_lock_s_unlock(&cache->rw_lock); rw_lock_s_unlock(&cache->rw_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment