1 /*****************************************************************************
2 
3 Copyright (c) 2007, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 
25 *****************************************************************************/
26 
27 /** @file include/trx0i_s.h
28  INFORMATION SCHEMA innodb_trx, innodb_locks and
29  innodb_lock_waits tables cache structures and public
30  functions.
31 
32  Created July 17, 2007 Vasil Dimov
33  *******************************************************/
34 
35 #ifndef trx0i_s_h
36 #define trx0i_s_h
37 
38 #include "dict0types.h"
39 #include "trx0types.h"
40 #include "univ.i"
41 
42 class PSI_server_data_lock_container;
43 
44 /** The maximum amount of memory that can be consumed by innodb_trx,
45 innodb_locks and innodb_lock_waits information schema tables. */
46 #define TRX_I_S_MEM_LIMIT 16777216 /* 16 MiB */
47 
48 /** The maximum length of a string that can be stored in
49 i_s_locks_row_t::lock_data */
50 #define TRX_I_S_LOCK_DATA_MAX_LEN 8192
51 
52 /** The maximum length of a string that can be stored in
53 i_s_trx_row_t::trx_query */
54 #define TRX_I_S_TRX_QUERY_MAX_LEN 1024
55 
56 /** The maximum length of a string that can be stored in
57 i_s_trx_row_t::trx_operation_state */
58 #define TRX_I_S_TRX_OP_STATE_MAX_LEN 64
59 
60 /** The maximum length of a string that can be stored in
61 i_s_trx_row_t::trx_foreign_key_error */
62 #define TRX_I_S_TRX_FK_ERROR_MAX_LEN 256
63 
64 /** The maximum length of a string that can be stored in
65 i_s_trx_row_t::trx_isolation_level */
66 #define TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN 16
67 
68 /** Safely copy strings in to the INNODB_TRX table's
69 string based columns */
70 #define TRX_I_S_STRING_COPY(data, field, constraint, tcache)             \
71   do {                                                                   \
72     if (strlen(data) > constraint) {                                     \
73       char buff[constraint + 1];                                         \
74       strncpy(buff, data, constraint);                                   \
75       buff[constraint] = '\0';                                           \
76                                                                          \
77       field = static_cast<const char *>(                                 \
78           ha_storage_put_memlim((tcache)->storage, buff, constraint + 1, \
79                                 MAX_ALLOWED_FOR_STORAGE(tcache)));       \
80     } else {                                                             \
81       field = static_cast<const char *>(ha_storage_put_str_memlim(       \
82           (tcache)->storage, data, MAX_ALLOWED_FOR_STORAGE(tcache)));    \
83     }                                                                    \
84   } while (0)
85 
86 /** This structure represents INFORMATION_SCHEMA.innodb_locks row */
87 struct i_s_locks_row_t {
88   uint64_t lock_trx_immutable_id; /*!< transaction address as integer. We need
89                           an id which is unique and does not change over time.
90                           Unfortunately trx->id is initially equal to 0 for
91                           all trxs which still appear to be read only, and it
92                           changes to non-zero, once trx needs to perform write.
93                           For this reason trx->id is not good enough for our
94                           purpose. */
95   uint64_t lock_immutable_id; /*!< lock address as integer. We need to identify
96                       the lock in unique way. Specifying space, page and heap_no
97                       and trx is not enough, because there could be locks with
98                       different modes. Using mode as part of id is not good,
99                       because we sometimes change the mode of the lock (for
100                       example when granting the lock we drop LOCK_WAITING flag
101                       and in lock_trx_release_read_locks we add LOCK_REC_NOT_GAP
102                       flag). The only permanent thing is then the address.
103                       We use both lock_immutable_id and lock_trx_immutable_id
104                       even though lock_immutable_id is unique, because we need
105                       to be able to locate the row in PERFORMANCE_SCHEMA based
106                       on the id, and we need a way to verify that the
107                       lock_immutable_id is safe to dereference. Simplest way to
108                       do that is to check that trx still has the lock on its
109                       list of locks.     */
110 
111   /** Information for record locks.  All these are
112   ULINT_UNDEFINED for table locks. */
113   /* @{ */
114   space_id_t lock_space; /*!< tablespace identifier */
115   page_no_t lock_page;   /*!< page number within the_space */
116   ulint lock_rec;        /*!< heap number of the record
117                          on the page */
118   /* @} */
119 
120   /** The following are auxiliary and not included in the table */
121   /* @{ */
122   table_id_t lock_table_id;
123   /*!< table identifier from
124   lock_get_table_id */
125   /* @} */
126 };
127 
128 /** This structure represents INFORMATION_SCHEMA.innodb_trx row */
129 struct i_s_trx_row_t {
130   trx_id_t trx_id;       /*!< transaction identifier */
131   const char *trx_state; /*!< transaction state from
132                          trx_get_que_state_str() */
133   ib_time_t trx_started; /*!< trx_t::start_time */
134   const i_s_locks_row_t *requested_lock_row;
135   /*!< pointer to a row
136   in innodb_locks if trx
137   is waiting, or NULL */
138 
139   /** The value of trx->lock.wait_started */
140   ib_time_t trx_wait_started;
141   /** The value of TRX_WEIGHT(trx) */
142   uintmax_t trx_weight;
143   /** If `first` is `true` then `second` is the value of the
144   trx->lock.schedule_weight, otherwise the `second` should be ignored and
145   displayed as NULL to the end user.
146   (This could be std::optional once we move to C++17) */
147   std::pair<bool, trx_schedule_weight_t> trx_schedule_weight;
148   ulint trx_mysql_thread_id;        /*!< thd_get_thread_id() */
149   const char *trx_query;            /*!< MySQL statement being
150                                     executed in the transaction */
151   const CHARSET_INFO *trx_query_cs; /*!< the charset of trx_query */
152   const char *trx_operation_state;  /*!< trx_t::op_info */
153   ulint trx_tables_in_use;          /*!< n_mysql_tables_in_use in
154                                    trx_t */
155   ulint trx_tables_locked;
156   /*!< mysql_n_tables_locked in
157   trx_t */
158   ulint trx_lock_structs; /*!< list len of trx_locks in
159                          trx_t */
160   ulint trx_lock_memory_bytes;
161   /*!< mem_heap_get_size(
162   trx->lock_heap) */
163   ulint trx_rows_locked;       /*!< lock_number_of_rows_locked() */
164   uintmax_t trx_rows_modified; /*!< trx_t::undo_no */
165   ulint trx_concurrency_tickets;
166   /*!< n_tickets_to_enter_innodb in
167   trx_t */
168   const char *trx_isolation_level;
169   /*!< isolation_level in trx_t */
170   ibool trx_unique_checks;
171   /*!< check_unique_secondary in trx_t*/
172   ibool trx_foreign_key_checks;
173   /*!< check_foreigns in trx_t */
174   const char *trx_foreign_key_error;
175   /*!< detailed_error in trx_t */
176   ibool trx_has_search_latch;
177   /*!< has_search_latch in trx_t */
178   ulint trx_is_read_only;
179   /*!< trx_t::read_only */
180   ulint trx_is_autocommit_non_locking;
181   /*!< trx_is_autocommit_non_locking(trx)
182    */
183 };
184 
185 /** Cache of INFORMATION_SCHEMA table data */
186 struct trx_i_s_cache_t;
187 
188 /** Auxiliary enum used by functions that need to select one of the
189 INFORMATION_SCHEMA tables */
190 enum i_s_table {
191   I_S_INNODB_TRX, /*!< INFORMATION_SCHEMA.innodb_trx */
192 };
193 
194 /** This is the intermediate buffer where data needed to fill the
195 INFORMATION SCHEMA tables is fetched and later retrieved by the C++
196 code in handler/i_s.cc. */
197 extern trx_i_s_cache_t *trx_i_s_cache;
198 
199 /** Initialize INFORMATION SCHEMA trx related cache. */
200 void trx_i_s_cache_init(trx_i_s_cache_t *cache); /*!< out: cache to init */
201 /** Free the INFORMATION SCHEMA trx related cache. */
202 void trx_i_s_cache_free(trx_i_s_cache_t *cache); /*!< in/out: cache to free */
203 
204 /** Issue a shared/read lock on the tables cache. */
205 void trx_i_s_cache_start_read(trx_i_s_cache_t *cache); /*!< in: cache */
206 
207 /** Release a shared/read lock on the tables cache. */
208 void trx_i_s_cache_end_read(trx_i_s_cache_t *cache); /*!< in: cache */
209 
210 /** Issue an exclusive/write lock on the tables cache. */
211 void trx_i_s_cache_start_write(trx_i_s_cache_t *cache); /*!< in: cache */
212 
213 /** Release an exclusive/write lock on the tables cache. */
214 void trx_i_s_cache_end_write(trx_i_s_cache_t *cache); /*!< in: cache */
215 
216 /** Retrieves the number of used rows in the cache for a given
217  INFORMATION SCHEMA table.
218  @return number of rows */
219 ulint trx_i_s_cache_get_rows_used(trx_i_s_cache_t *cache, /*!< in: cache */
220                                   enum i_s_table table); /*!< in: which table */
221 
222 /** Retrieves the nth row in the cache for a given INFORMATION SCHEMA
223  table.
224  @return row */
225 void *trx_i_s_cache_get_nth_row(trx_i_s_cache_t *cache, /*!< in: cache */
226                                 enum i_s_table table,   /*!< in: which table */
227                                 ulint n);               /*!< in: row number */
228 
229 /** Update the transactions cache if it has not been read for some time.
230  @return 0 - fetched, 1 - not */
231 int trx_i_s_possibly_fetch_data_into_cache(
232     trx_i_s_cache_t *cache); /*!< in/out: cache */
233 
234 /** Returns TRUE if the data in the cache is truncated due to the memory
235  limit posed by TRX_I_S_MEM_LIMIT.
236  @param[in]   cache   The cache
237  @return true if truncated */
238 bool trx_i_s_cache_is_truncated(trx_i_s_cache_t *cache);
239 
240 /** The maximum length of a resulting lock_id_size in
241 trx_i_s_create_lock_id(), not including the terminating NUL.
242 "%lu:%lu:%lu:%lu:%lu" -> 20*5+4 chars */
243 #define TRX_I_S_LOCK_ID_MAX_LEN (20 * 5 + 4)
244 
245 /** Crafts a lock id string from a i_s_locks_row_t object. Returns its
246  second argument. This function aborts if there is not enough space in
247  lock_id. Be sure to provide at least TRX_I_S_LOCK_ID_MAX_LEN + 1 if you
248  want to be 100% sure that it will not abort.
249  @return resulting lock id */
250 char *trx_i_s_create_lock_id(
251     const i_s_locks_row_t *row, /*!< in: innodb_locks row */
252     char *lock_id,              /*!< out: resulting lock_id */
253     ulint lock_id_size);        /*!< in: size of the lock id
254                           buffer */
255 
256 /** Fill performance schema lock data.
257 Create a string that represents the LOCK_DATA
258 column, for a given lock record.
259 @param[out]	lock_data	Lock data string
260 @param[in]	lock		Lock to inspect
261 @param[in]	heap_no		Lock heap number
262 @param[in]	container	Data container to fill
263 */
264 void p_s_fill_lock_data(const char **lock_data, const lock_t *lock,
265                         ulint heap_no,
266                         PSI_server_data_lock_container *container);
267 
268 /** Fills i_s_locks_row_t object with data about the lock.
269 @param[out] row     Result object that's filled
270 @param[in]  lock    Lock to get data from
271 @param[in]  heap_no Lock's record number or ULINT_UNDEFINED if the lock is a
272                     table lock */
273 void fill_locks_row(i_s_locks_row_t *row, const lock_t *lock, ulint heap_no);
274 
275 /** Parses lock id into row
276 @param[in]      lock_id     Lock id generated with trx_i_s_create_lock_id
277 @param[out]     row         Row to be filled in with data
278 @return LOCK_REC, LOCK_TABLE or 0 if failed to parse */
279 int trx_i_s_parse_lock_id(const char *lock_id, i_s_locks_row_t *row);
280 #endif /* trx0i_s_h */
281