5 LP bug#677407 / MySQL Bug#48883: Stale data from INNODB_LOCKS table.
7 The innodb.innodb_information_schema test could fail sporadically due to
8 the flawed logic in the INFORMATION_SCHEMA.INNODB_LOCKS caching
11 The logic for how to check when to update the table cache for
12 INNODB_LOCKS with real data was flawed. This could result in both not
13 updating the cache often enough (when the table is queried repeatedly
14 with less than 100 milliseconds in-between) resulting in stale data; as
15 well as updating too often (when multiple queries against the table
16 start at around the same time).
18 Fixed by updating the "last updated" timestamp in the right place, when
19 the cache is updated, not when it is read.
21 I hereby grant Percona the following BSD license to this patch for
22 inclusion in Percona Server:
24 Copyright (c) 2010, Kristian Nielsen All rights reserved.
26 Redistribution and use in source and binary forms, with or without
27 modification, are permitted provided that the following conditions are
30 * Redistributions of source code must retain the above copyright
31 notice, this list of conditions and the following disclaimer.
32 * Redistributions in binary form must reproduce the above copyright
33 notice, this list of conditions and the following disclaimer in
34 the documentation and/or other materials provided with the
36 * Neither the name of the author nor the names of its contributors
37 may be used to endorse or promote products derived from this
38 software without specific prior written permission.
40 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 --- a/storage/innodb_plugin/trx/trx0i_s.c
53 +++ b/storage/innodb_plugin/trx/trx0i_s.c
55 ullint last_read; /*!< last time the cache was read;
56 measured in microseconds since
58 - mutex_t last_read_mutex;/*!< mutex protecting the
59 - last_read member - it is updated
60 - inside a shared lock of the
62 i_s_table_cache_t innodb_trx; /*!< innodb_trx table */
63 i_s_table_cache_t innodb_locks; /*!< innodb_locks table */
64 i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */
65 @@ -1142,13 +1138,6 @@
69 - /* Here we read cache->last_read without acquiring its mutex
70 - because last_read is only updated when a shared rw lock on the
71 - whole cache is being held (see trx_i_s_cache_end_read()) and
72 - we are currently holding an exclusive rw lock on the cache.
73 - So it is not possible for last_read to be updated while we are
76 #ifdef UNIV_SYNC_DEBUG
77 ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
79 @@ -1246,6 +1235,12 @@
80 /*===================================*/
81 trx_i_s_cache_t* cache) /*!< in/out: cache */
85 +#ifdef UNIV_SYNC_DEBUG
86 + ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
89 if (!can_cache_be_updated(cache)) {
92 @@ -1258,6 +1253,10 @@
94 mutex_exit(&kernel_mutex);
96 + /* update cache last read time */
97 + now = ut_time_us(NULL);
98 + cache->last_read = now;
103 @@ -1288,16 +1287,12 @@
105 release trx_i_s_cache_t::rw_lock
106 acquire trx_i_s_cache_t::rw_lock, S
107 - acquire trx_i_s_cache_t::last_read_mutex
108 - release trx_i_s_cache_t::last_read_mutex
109 release trx_i_s_cache_t::rw_lock */
111 rw_lock_create(&cache->rw_lock, SYNC_TRX_I_S_RWLOCK);
113 cache->last_read = 0;
115 - mutex_create(&cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ);
117 table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t));
118 table_cache_init(&cache->innodb_locks, sizeof(i_s_locks_row_t));
119 table_cache_init(&cache->innodb_lock_waits,
120 @@ -1348,18 +1343,10 @@
121 /*===================*/
122 trx_i_s_cache_t* cache) /*!< in: cache */
126 #ifdef UNIV_SYNC_DEBUG
127 ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED));
130 - /* update cache last read time */
131 - now = ut_time_us(NULL);
132 - mutex_enter(&cache->last_read_mutex);
133 - cache->last_read = now;
134 - mutex_exit(&cache->last_read_mutex);
136 rw_lock_s_unlock(&cache->rw_lock);