1 /*****************************************************************************
2
3 Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, 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 Street, Suite 500, Boston, MA 02110-1335 USA
24
25 *****************************************************************************/
26
27 /**************************************************//**
28 @file trx/trx0i_s.cc
29 INFORMATION SCHEMA innodb_trx, innodb_locks and
30 innodb_lock_waits tables fetch code.
31
32 The code below fetches information needed to fill those
33 3 dynamic tables and uploads it into a "transactions
34 table cache" for later retrieval.
35
36 Created July 17, 2007 Vasil Dimov
37 *******************************************************/
38
39 /* Found during the build of 5.5.3 on Linux 2.4 and early 2.6 kernels:
40 The includes "univ.i" -> "my_global.h" cause a different path
41 to be taken further down with pthread functions and types,
42 so they must come first.
43 From the symptoms, this is related to bug#46587 in the MySQL bug DB.
44 */
45 #include "univ.i"
46
47 #include <mysql/plugin.h>
48
49 #include "buf0buf.h"
50 #include "dict0dict.h"
51 #include "ha0storage.h"
52 #include "ha_prototypes.h"
53 #include "hash0hash.h"
54 #include "lock0iter.h"
55 #include "lock0lock.h"
56 #include "mem0mem.h"
57 #include "page0page.h"
58 #include "rem0rec.h"
59 #include "row0row.h"
60 #include "srv0srv.h"
61 #include "sync0rw.h"
62 #include "sync0sync.h"
63 #include "sync0types.h"
64 #include "trx0i_s.h"
65 #include "trx0sys.h"
66 #include "trx0trx.h"
67 #include "ut0mem.h"
68 #include "ut0ut.h"
69
70 /** Initial number of rows in the table cache */
71 #define TABLE_CACHE_INITIAL_ROWSNUM 1024
72
73 /** @brief The maximum number of chunks to allocate for a table cache.
74
75 The rows of a table cache are stored in a set of chunks. When a new
76 row is added a new chunk is allocated if necessary. Assuming that the
77 first one is 1024 rows (TABLE_CACHE_INITIAL_ROWSNUM) and each
78 subsequent is N/2 where N is the number of rows we have allocated till
79 now, then 39th chunk would accommodate 1677416425 rows and all chunks
80 would accommodate 3354832851 rows. */
81 #define MEM_CHUNKS_IN_TABLE_CACHE 39
82
83 /** The following are some testing auxiliary macros. Do not enable them
84 in a production environment. */
85 /* @{ */
86
87 #if 0
88 /** If this is enabled then lock folds will always be different
89 resulting in equal rows being put in a different cells of the hash
90 table. Checking for duplicates will be flawed because different
91 fold will be calculated when a row is searched in the hash table. */
92 #define TEST_LOCK_FOLD_ALWAYS_DIFFERENT
93 #endif
94
95 #if 0
96 /** This effectively kills the search-for-duplicate-before-adding-a-row
97 function, but searching in the hash is still performed. It will always
98 be assumed that lock is not present and insertion will be performed in
99 the hash table. */
100 #define TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T
101 #endif
102
103 #if 0
104 /** This aggressively repeats adding each row many times. Depending on
105 the above settings this may be noop or may result in lots of rows being
106 added. */
107 #define TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
108 #endif
109
110 #if 0
111 /** Very similar to TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T but hash
112 table search is not performed at all. */
113 #define TEST_DO_NOT_CHECK_FOR_DUPLICATE_ROWS
114 #endif
115
116 #if 0
117 /** Do not insert each row into the hash table, duplicates may appear
118 if this is enabled, also if this is enabled searching into the hash is
119 noop because it will be empty. */
120 #define TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE
121 #endif
122 /* @} */
123
124 /** Memory limit passed to ha_storage_put_memlim().
125 @param cache hash storage
126 @return maximum allowed allocation size */
127 #define MAX_ALLOWED_FOR_STORAGE(cache) \
128 (TRX_I_S_MEM_LIMIT \
129 - (cache)->mem_allocd)
130
131 /** Memory limit in table_cache_create_empty_row().
132 @param cache hash storage
133 @return maximum allowed allocation size */
134 #define MAX_ALLOWED_FOR_ALLOC(cache) \
135 (TRX_I_S_MEM_LIMIT \
136 - (cache)->mem_allocd \
137 - ha_storage_get_size((cache)->storage))
138
139 /** Memory for each table in the intermediate buffer is allocated in
140 separate chunks. These chunks are considered to be concatenated to
141 represent one flat array of rows. */
142 struct i_s_mem_chunk_t {
143 ulint offset; /*!< offset, in number of rows */
144 ulint rows_allocd; /*!< the size of this chunk, in number
145 of rows */
146 void* base; /*!< start of the chunk */
147 };
148
149 /** This represents one table's cache. */
150 struct i_s_table_cache_t {
151 ulint rows_used; /*!< number of used rows */
152 ulint rows_allocd; /*!< number of allocated rows */
153 ulint row_size; /*!< size of a single row */
154 i_s_mem_chunk_t chunks[MEM_CHUNKS_IN_TABLE_CACHE]; /*!< array of
155 memory chunks that stores the
156 rows */
157 };
158
159 /** This structure describes the intermediate buffer */
160 struct trx_i_s_cache_t {
161 rw_lock_t rw_lock; /*!< read-write lock protecting
162 the rest of this structure */
163 ullint last_read; /*!< last time the cache was read;
164 measured in microseconds since
165 epoch */
166 ib_mutex_t last_read_mutex;/*!< mutex protecting the
167 last_read member - it is updated
168 inside a shared lock of the
169 rw_lock member */
170 i_s_table_cache_t innodb_trx; /*!< innodb_trx table */
171 i_s_table_cache_t innodb_locks; /*!< innodb_locks table */
172 i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */
173 /** the hash table size is LOCKS_HASH_CELLS_NUM * sizeof(void*) bytes */
174 #define LOCKS_HASH_CELLS_NUM 10000
175 hash_table_t* locks_hash; /*!< hash table used to eliminate
176 duplicate entries in the
177 innodb_locks table */
178 /** Initial size of the cache storage */
179 #define CACHE_STORAGE_INITIAL_SIZE 1024
180 /** Number of hash cells in the cache storage */
181 #define CACHE_STORAGE_HASH_CELLS 2048
182 ha_storage_t* storage; /*!< storage for external volatile
183 data that may become unavailable
184 when we release
185 lock_sys->mutex or trx_sys->mutex */
186 ulint mem_allocd; /*!< the amount of memory
187 allocated with mem_alloc*() */
188 ibool is_truncated; /*!< this is TRUE if the memory
189 limit was hit and thus the data
190 in the cache is truncated */
191 };
192
193 /** This is the intermediate buffer where data needed to fill the
194 INFORMATION SCHEMA tables is fetched and later retrieved by the C++
195 code in handler/i_s.cc. */
196 static trx_i_s_cache_t trx_i_s_cache_static;
197 /** This is the intermediate buffer where data needed to fill the
198 INFORMATION SCHEMA tables is fetched and later retrieved by the C++
199 code in handler/i_s.cc. */
200 UNIV_INTERN trx_i_s_cache_t* trx_i_s_cache = &trx_i_s_cache_static;
201
202 /* Key to register the lock/mutex with performance schema */
203 #ifdef UNIV_PFS_RWLOCK
204 UNIV_INTERN mysql_pfs_key_t trx_i_s_cache_lock_key;
205 #endif /* UNIV_PFS_RWLOCK */
206
207 #ifdef UNIV_PFS_MUTEX
208 UNIV_INTERN mysql_pfs_key_t cache_last_read_mutex_key;
209 #endif /* UNIV_PFS_MUTEX */
210
211 /*******************************************************************//**
212 For a record lock that is in waiting state retrieves the only bit that
213 is set, for a table lock returns ULINT_UNDEFINED.
214 @return record number within the heap */
215 static
216 ulint
wait_lock_get_heap_no(const lock_t * lock)217 wait_lock_get_heap_no(
218 /*==================*/
219 const lock_t* lock) /*!< in: lock */
220 {
221 ulint ret;
222
223 switch (lock_get_type(lock)) {
224 case LOCK_REC:
225 ret = lock_rec_find_set_bit(lock);
226 ut_a(ret != ULINT_UNDEFINED);
227 break;
228 case LOCK_TABLE:
229 ret = ULINT_UNDEFINED;
230 break;
231 default:
232 ut_error;
233 }
234
235 return(ret);
236 }
237
238 /*******************************************************************//**
239 Initializes the members of a table cache. */
240 static
241 void
table_cache_init(i_s_table_cache_t * table_cache,size_t row_size)242 table_cache_init(
243 /*=============*/
244 i_s_table_cache_t* table_cache, /*!< out: table cache */
245 size_t row_size) /*!< in: the size of a
246 row */
247 {
248 ulint i;
249
250 table_cache->rows_used = 0;
251 table_cache->rows_allocd = 0;
252 table_cache->row_size = row_size;
253
254 for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
255
256 /* the memory is actually allocated in
257 table_cache_create_empty_row() */
258 table_cache->chunks[i].base = NULL;
259 }
260 }
261
262 /*******************************************************************//**
263 Frees a table cache. */
264 static
265 void
table_cache_free(i_s_table_cache_t * table_cache)266 table_cache_free(
267 /*=============*/
268 i_s_table_cache_t* table_cache) /*!< in/out: table cache */
269 {
270 ulint i;
271
272 for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
273
274 /* the memory is actually allocated in
275 table_cache_create_empty_row() */
276 if (table_cache->chunks[i].base) {
277 mem_free(table_cache->chunks[i].base);
278 table_cache->chunks[i].base = NULL;
279 }
280 }
281 }
282
283 /*******************************************************************//**
284 Returns an empty row from a table cache. The row is allocated if no more
285 empty rows are available. The number of used rows is incremented.
286 If the memory limit is hit then NULL is returned and nothing is
287 allocated.
288 @return empty row, or NULL if out of memory */
289 static
290 void*
table_cache_create_empty_row(i_s_table_cache_t * table_cache,trx_i_s_cache_t * cache)291 table_cache_create_empty_row(
292 /*=========================*/
293 i_s_table_cache_t* table_cache, /*!< in/out: table cache */
294 trx_i_s_cache_t* cache) /*!< in/out: cache to record
295 how many bytes are
296 allocated */
297 {
298 ulint i;
299 void* row;
300
301 ut_a(table_cache->rows_used <= table_cache->rows_allocd);
302
303 if (table_cache->rows_used == table_cache->rows_allocd) {
304
305 /* rows_used == rows_allocd means that new chunk needs
306 to be allocated: either no more empty rows in the
307 last allocated chunk or nothing has been allocated yet
308 (rows_num == rows_allocd == 0); */
309
310 i_s_mem_chunk_t* chunk;
311 ulint req_bytes;
312 ulint got_bytes;
313 ulint req_rows;
314 ulint got_rows;
315
316 /* find the first not allocated chunk */
317 for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
318
319 if (table_cache->chunks[i].base == NULL) {
320
321 break;
322 }
323 }
324
325 /* i == MEM_CHUNKS_IN_TABLE_CACHE means that all chunks
326 have been allocated :-X */
327 ut_a(i < MEM_CHUNKS_IN_TABLE_CACHE);
328
329 /* allocate the chunk we just found */
330
331 if (i == 0) {
332
333 /* first chunk, nothing is allocated yet */
334 req_rows = TABLE_CACHE_INITIAL_ROWSNUM;
335 } else {
336
337 /* Memory is increased by the formula
338 new = old + old / 2; We are trying not to be
339 aggressive here (= using the common new = old * 2)
340 because the allocated memory will not be freed
341 until InnoDB exit (it is reused). So it is better
342 to once allocate the memory in more steps, but
343 have less unused/wasted memory than to use less
344 steps in allocation (which is done once in a
345 lifetime) but end up with lots of unused/wasted
346 memory. */
347 req_rows = table_cache->rows_allocd / 2;
348 }
349 req_bytes = req_rows * table_cache->row_size;
350
351 if (req_bytes > MAX_ALLOWED_FOR_ALLOC(cache)) {
352
353 return(NULL);
354 }
355
356 chunk = &table_cache->chunks[i];
357
358 chunk->base = mem_alloc2(req_bytes, &got_bytes);
359
360 got_rows = got_bytes / table_cache->row_size;
361
362 cache->mem_allocd += got_bytes;
363
364 #if 0
365 printf("allocating chunk %d req bytes=%lu, got bytes=%lu, "
366 "row size=%lu, "
367 "req rows=%lu, got rows=%lu\n",
368 i, req_bytes, got_bytes,
369 table_cache->row_size,
370 req_rows, got_rows);
371 #endif
372
373 chunk->rows_allocd = got_rows;
374
375 table_cache->rows_allocd += got_rows;
376
377 /* adjust the offset of the next chunk */
378 if (i < MEM_CHUNKS_IN_TABLE_CACHE - 1) {
379
380 table_cache->chunks[i + 1].offset
381 = chunk->offset + chunk->rows_allocd;
382 }
383
384 /* return the first empty row in the newly allocated
385 chunk */
386 row = chunk->base;
387 } else {
388
389 char* chunk_start;
390 ulint offset;
391
392 /* there is an empty row, no need to allocate new
393 chunks */
394
395 /* find the first chunk that contains allocated but
396 empty/unused rows */
397 for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
398
399 if (table_cache->chunks[i].offset
400 + table_cache->chunks[i].rows_allocd
401 > table_cache->rows_used) {
402
403 break;
404 }
405 }
406
407 /* i == MEM_CHUNKS_IN_TABLE_CACHE means that all chunks
408 are full, but
409 table_cache->rows_used != table_cache->rows_allocd means
410 exactly the opposite - there are allocated but
411 empty/unused rows :-X */
412 ut_a(i < MEM_CHUNKS_IN_TABLE_CACHE);
413
414 chunk_start = (char*) table_cache->chunks[i].base;
415 offset = table_cache->rows_used
416 - table_cache->chunks[i].offset;
417
418 row = chunk_start + offset * table_cache->row_size;
419 }
420
421 table_cache->rows_used++;
422
423 return(row);
424 }
425
426 #ifdef UNIV_DEBUG
427 /*******************************************************************//**
428 Validates a row in the locks cache.
429 @return TRUE if valid */
430 static
431 ibool
i_s_locks_row_validate(const i_s_locks_row_t * row)432 i_s_locks_row_validate(
433 /*===================*/
434 const i_s_locks_row_t* row) /*!< in: row to validate */
435 {
436 ut_ad(row->lock_trx_id != 0);
437 ut_ad(row->lock_mode != NULL);
438 ut_ad(row->lock_type != NULL);
439 ut_ad(row->lock_table != NULL);
440 ut_ad(row->lock_table_id != 0);
441
442 if (row->lock_space == ULINT_UNDEFINED) {
443 /* table lock */
444 ut_ad(!strcmp("TABLE", row->lock_type));
445 ut_ad(row->lock_index == NULL);
446 ut_ad(row->lock_data == NULL);
447 ut_ad(row->lock_page == ULINT_UNDEFINED);
448 ut_ad(row->lock_rec == ULINT_UNDEFINED);
449 } else {
450 /* record lock */
451 ut_ad(!strcmp("RECORD", row->lock_type));
452 ut_ad(row->lock_index != NULL);
453 /* row->lock_data == NULL if buf_page_try_get() == NULL */
454 ut_ad(row->lock_page != ULINT_UNDEFINED);
455 ut_ad(row->lock_rec != ULINT_UNDEFINED);
456 }
457
458 return(TRUE);
459 }
460 #endif /* UNIV_DEBUG */
461
462 /*******************************************************************//**
463 Fills i_s_trx_row_t object.
464 If memory can not be allocated then FALSE is returned.
465 @return FALSE if allocation fails */
466 static
467 ibool
fill_trx_row(i_s_trx_row_t * row,const trx_t * trx,const i_s_locks_row_t * requested_lock_row,trx_i_s_cache_t * cache)468 fill_trx_row(
469 /*=========*/
470 i_s_trx_row_t* row, /*!< out: result object
471 that's filled */
472 const trx_t* trx, /*!< in: transaction to
473 get data from */
474 const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the
475 corresponding row in
476 innodb_locks if trx is
477 waiting or NULL if trx
478 is not waiting */
479 trx_i_s_cache_t* cache) /*!< in/out: cache into
480 which to copy volatile
481 strings */
482 {
483 const char* stmt;
484 size_t stmt_len;
485 const char* s;
486
487 ut_ad(lock_mutex_own());
488
489 row->trx_id = trx->id;
490 row->trx_started = (ib_time_t) trx->start_time;
491 row->trx_state = trx_get_que_state_str(trx);
492 row->requested_lock_row = requested_lock_row;
493 ut_ad(requested_lock_row == NULL
494 || i_s_locks_row_validate(requested_lock_row));
495
496 if (trx->lock.wait_lock != NULL) {
497
498 ut_a(requested_lock_row != NULL);
499 row->trx_wait_started = (ib_time_t) trx->lock.wait_started;
500 } else {
501 ut_a(requested_lock_row == NULL);
502 row->trx_wait_started = 0;
503 }
504
505 row->trx_weight = (ullint) TRX_WEIGHT(trx);
506
507 if (trx->mysql_thd == NULL) {
508 /* For internal transactions e.g., purge and transactions
509 being recovered at startup there is no associated MySQL
510 thread data structure. */
511 row->trx_mysql_thread_id = 0;
512 row->trx_query = NULL;
513 goto thd_done;
514 }
515
516 row->trx_mysql_thread_id = thd_get_thread_id(trx->mysql_thd);
517
518 stmt = innobase_get_stmt(trx->mysql_thd, &stmt_len);
519
520 if (stmt != NULL) {
521 char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1];
522
523 if (stmt_len > TRX_I_S_TRX_QUERY_MAX_LEN) {
524 stmt_len = TRX_I_S_TRX_QUERY_MAX_LEN;
525 }
526
527 memcpy(query, stmt, stmt_len);
528 query[stmt_len] = '\0';
529
530 row->trx_query = static_cast<const char*>(
531 ha_storage_put_memlim(
532 cache->storage, query, stmt_len + 1,
533 MAX_ALLOWED_FOR_STORAGE(cache)));
534
535 row->trx_query_cs = innobase_get_charset(trx->mysql_thd);
536
537 if (row->trx_query == NULL) {
538
539 return(FALSE);
540 }
541 } else {
542
543 row->trx_query = NULL;
544 }
545
546 thd_done:
547 s = trx->op_info;
548
549 if (s != NULL && s[0] != '\0') {
550
551 TRX_I_S_STRING_COPY(s, row->trx_operation_state,
552 TRX_I_S_TRX_OP_STATE_MAX_LEN, cache);
553
554 if (row->trx_operation_state == NULL) {
555
556 return(FALSE);
557 }
558 } else {
559
560 row->trx_operation_state = NULL;
561 }
562
563 row->trx_tables_in_use = trx->n_mysql_tables_in_use;
564
565 row->trx_tables_locked = trx->mysql_n_tables_locked;
566
567 /* These are protected by both trx->mutex or lock_sys->mutex,
568 or just lock_sys->mutex. For reading, it suffices to hold
569 lock_sys->mutex. */
570
571 row->trx_lock_structs = UT_LIST_GET_LEN(trx->lock.trx_locks);
572
573 row->trx_lock_memory_bytes = mem_heap_get_size(trx->lock.lock_heap);
574
575 row->trx_rows_locked = lock_number_of_rows_locked(&trx->lock);
576
577 row->trx_rows_modified = trx->undo_no;
578
579 row->trx_concurrency_tickets = trx->n_tickets_to_enter_innodb;
580
581 switch (trx->isolation_level) {
582 case TRX_ISO_READ_UNCOMMITTED:
583 row->trx_isolation_level = "READ UNCOMMITTED";
584 break;
585 case TRX_ISO_READ_COMMITTED:
586 row->trx_isolation_level = "READ COMMITTED";
587 break;
588 case TRX_ISO_REPEATABLE_READ:
589 row->trx_isolation_level = "REPEATABLE READ";
590 break;
591 case TRX_ISO_SERIALIZABLE:
592 row->trx_isolation_level = "SERIALIZABLE";
593 break;
594 /* Should not happen as TRX_ISO_READ_COMMITTED is default */
595 default:
596 row->trx_isolation_level = "UNKNOWN";
597 }
598
599 row->trx_unique_checks = (ibool) trx->check_unique_secondary;
600
601 row->trx_foreign_key_checks = (ibool) trx->check_foreigns;
602
603 s = trx->detailed_error;
604
605 if (s != NULL && s[0] != '\0') {
606
607 TRX_I_S_STRING_COPY(s,
608 row->trx_foreign_key_error,
609 TRX_I_S_TRX_FK_ERROR_MAX_LEN, cache);
610
611 if (row->trx_foreign_key_error == NULL) {
612
613 return(FALSE);
614 }
615 } else {
616 row->trx_foreign_key_error = NULL;
617 }
618
619 row->trx_has_search_latch = (ibool) trx->has_search_latch;
620
621 row->trx_search_latch_timeout = trx->search_latch_timeout;
622
623 row->trx_is_read_only = trx->read_only;
624
625 row->trx_is_autocommit_non_locking = trx_is_autocommit_non_locking(trx);
626
627 return(TRUE);
628 }
629
630 /*******************************************************************//**
631 Format the nth field of "rec" and put it in "buf". The result is always
632 NUL-terminated. Returns the number of bytes that were written to "buf"
633 (including the terminating NUL).
634 @return end of the result */
635 static
636 ulint
put_nth_field(char * buf,ulint buf_size,ulint n,const dict_index_t * index,const rec_t * rec,const ulint * offsets)637 put_nth_field(
638 /*==========*/
639 char* buf, /*!< out: buffer */
640 ulint buf_size,/*!< in: buffer size in bytes */
641 ulint n, /*!< in: number of field */
642 const dict_index_t* index, /*!< in: index */
643 const rec_t* rec, /*!< in: record */
644 const ulint* offsets)/*!< in: record offsets, returned
645 by rec_get_offsets() */
646 {
647 const byte* data;
648 ulint data_len;
649 dict_field_t* dict_field;
650 ulint ret;
651
652 ut_ad(rec_offs_validate(rec, NULL, offsets));
653
654 if (buf_size == 0) {
655
656 return(0);
657 }
658
659 ret = 0;
660
661 if (n > 0) {
662 /* we must append ", " before the actual data */
663
664 if (buf_size < 3) {
665
666 buf[0] = '\0';
667 return(1);
668 }
669
670 memcpy(buf, ", ", 3);
671
672 buf += 2;
673 buf_size -= 2;
674 ret += 2;
675 }
676
677 /* now buf_size >= 1 */
678
679 data = rec_get_nth_field(rec, offsets, n, &data_len);
680
681 dict_field = dict_index_get_nth_field(index, n);
682
683 ret += row_raw_format((const char*) data, data_len,
684 dict_field, buf, buf_size);
685
686 return(ret);
687 }
688
689 /*******************************************************************//**
690 Fills the "lock_data" member of i_s_locks_row_t object.
691 If memory can not be allocated then FALSE is returned.
692 @return FALSE if allocation fails */
693 static
694 ibool
fill_lock_data(const char ** lock_data,const lock_t * lock,ulint heap_no,trx_i_s_cache_t * cache)695 fill_lock_data(
696 /*===========*/
697 const char** lock_data,/*!< out: "lock_data" to fill */
698 const lock_t* lock, /*!< in: lock used to find the data */
699 ulint heap_no,/*!< in: rec num used to find the data */
700 trx_i_s_cache_t* cache) /*!< in/out: cache where to store
701 volatile data */
702 {
703 mtr_t mtr;
704
705 const buf_block_t* block;
706 const page_t* page;
707 const rec_t* rec;
708
709 ut_a(lock_get_type(lock) == LOCK_REC);
710
711 mtr_start(&mtr);
712
713 block = buf_page_try_get(lock_rec_get_space_id(lock),
714 lock_rec_get_page_no(lock),
715 &mtr);
716
717 if (block == NULL) {
718
719 *lock_data = NULL;
720
721 mtr_commit(&mtr);
722
723 return(TRUE);
724 }
725
726 page = (const page_t*) buf_block_get_frame(block);
727
728 rec = page_find_rec_with_heap_no(page, heap_no);
729
730 if (page_rec_is_infimum(rec)) {
731
732 *lock_data = ha_storage_put_str_memlim(
733 cache->storage, "infimum pseudo-record",
734 MAX_ALLOWED_FOR_STORAGE(cache));
735 } else if (page_rec_is_supremum(rec)) {
736
737 *lock_data = ha_storage_put_str_memlim(
738 cache->storage, "supremum pseudo-record",
739 MAX_ALLOWED_FOR_STORAGE(cache));
740 } else {
741
742 const dict_index_t* index;
743 ulint n_fields;
744 mem_heap_t* heap;
745 ulint offsets_onstack[REC_OFFS_NORMAL_SIZE];
746 ulint* offsets;
747 char buf[TRX_I_S_LOCK_DATA_MAX_LEN];
748 ulint buf_used;
749 ulint i;
750
751 rec_offs_init(offsets_onstack);
752 offsets = offsets_onstack;
753
754 index = lock_rec_get_index(lock);
755
756 n_fields = dict_index_get_n_unique(index);
757
758 ut_a(n_fields > 0);
759
760 heap = NULL;
761 offsets = rec_get_offsets(rec, index, offsets, n_fields,
762 &heap);
763
764 /* format and store the data */
765
766 buf_used = 0;
767 for (i = 0; i < n_fields; i++) {
768
769 buf_used += put_nth_field(
770 buf + buf_used, sizeof(buf) - buf_used,
771 i, index, rec, offsets) - 1;
772 }
773
774 *lock_data = (const char*) ha_storage_put_memlim(
775 cache->storage, buf, buf_used + 1,
776 MAX_ALLOWED_FOR_STORAGE(cache));
777
778 if (UNIV_UNLIKELY(heap != NULL)) {
779
780 /* this means that rec_get_offsets() has created a new
781 heap and has stored offsets in it; check that this is
782 really the case and free the heap */
783 ut_a(offsets != offsets_onstack);
784 mem_heap_free(heap);
785 }
786 }
787
788 mtr_commit(&mtr);
789
790 if (*lock_data == NULL) {
791
792 return(FALSE);
793 }
794
795 return(TRUE);
796 }
797
798 /*******************************************************************//**
799 Fills i_s_locks_row_t object. Returns its first argument.
800 If memory can not be allocated then FALSE is returned.
801 @return FALSE if allocation fails */
802 static
803 ibool
fill_locks_row(i_s_locks_row_t * row,const lock_t * lock,ulint heap_no,trx_i_s_cache_t * cache)804 fill_locks_row(
805 /*===========*/
806 i_s_locks_row_t* row, /*!< out: result object that's filled */
807 const lock_t* lock, /*!< in: lock to get data from */
808 ulint heap_no,/*!< in: lock's record number
809 or ULINT_UNDEFINED if the lock
810 is a table lock */
811 trx_i_s_cache_t* cache) /*!< in/out: cache into which to copy
812 volatile strings */
813 {
814 row->lock_trx_id = lock_get_trx_id(lock);
815 row->lock_mode = lock_get_mode_str(lock);
816 row->lock_type = lock_get_type_str(lock);
817
818 row->lock_table = ha_storage_put_str_memlim(
819 cache->storage, lock_get_table_name(lock),
820 MAX_ALLOWED_FOR_STORAGE(cache));
821
822 /* memory could not be allocated */
823 if (row->lock_table == NULL) {
824
825 return(FALSE);
826 }
827
828 switch (lock_get_type(lock)) {
829 case LOCK_REC:
830 row->lock_index = ha_storage_put_str_memlim(
831 cache->storage, lock_rec_get_index_name(lock),
832 MAX_ALLOWED_FOR_STORAGE(cache));
833
834 /* memory could not be allocated */
835 if (row->lock_index == NULL) {
836
837 return(FALSE);
838 }
839
840 row->lock_space = lock_rec_get_space_id(lock);
841 row->lock_page = lock_rec_get_page_no(lock);
842 row->lock_rec = heap_no;
843
844 if (!fill_lock_data(&row->lock_data, lock, heap_no, cache)) {
845
846 /* memory could not be allocated */
847 return(FALSE);
848 }
849
850 break;
851 case LOCK_TABLE:
852 row->lock_index = NULL;
853
854 row->lock_space = ULINT_UNDEFINED;
855 row->lock_page = ULINT_UNDEFINED;
856 row->lock_rec = ULINT_UNDEFINED;
857
858 row->lock_data = NULL;
859
860 break;
861 default:
862 ut_error;
863 }
864
865 row->lock_table_id = lock_get_table_id(lock);
866
867 row->hash_chain.value = row;
868 ut_ad(i_s_locks_row_validate(row));
869
870 return(TRUE);
871 }
872
873 /*******************************************************************//**
874 Fills i_s_lock_waits_row_t object. Returns its first argument.
875 @return result object that's filled */
876 static
877 i_s_lock_waits_row_t*
fill_lock_waits_row(i_s_lock_waits_row_t * row,const i_s_locks_row_t * requested_lock_row,const i_s_locks_row_t * blocking_lock_row)878 fill_lock_waits_row(
879 /*================*/
880 i_s_lock_waits_row_t* row, /*!< out: result object
881 that's filled */
882 const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the
883 relevant requested lock
884 row in innodb_locks */
885 const i_s_locks_row_t* blocking_lock_row)/*!< in: pointer to the
886 relevant blocking lock
887 row in innodb_locks */
888 {
889 ut_ad(i_s_locks_row_validate(requested_lock_row));
890 ut_ad(i_s_locks_row_validate(blocking_lock_row));
891
892 row->requested_lock_row = requested_lock_row;
893 row->blocking_lock_row = blocking_lock_row;
894
895 return(row);
896 }
897
898 /*******************************************************************//**
899 Calculates a hash fold for a lock. For a record lock the fold is
900 calculated from 4 elements, which uniquely identify a lock at a given
901 point in time: transaction id, space id, page number, record number.
902 For a table lock the fold is table's id.
903 @return fold */
904 static
905 ulint
fold_lock(const lock_t * lock,ulint heap_no)906 fold_lock(
907 /*======*/
908 const lock_t* lock, /*!< in: lock object to fold */
909 ulint heap_no)/*!< in: lock's record number
910 or ULINT_UNDEFINED if the lock
911 is a table lock */
912 {
913 #ifdef TEST_LOCK_FOLD_ALWAYS_DIFFERENT
914 static ulint fold = 0;
915
916 return(fold++);
917 #else
918 ulint ret;
919
920 switch (lock_get_type(lock)) {
921 case LOCK_REC:
922 ut_a(heap_no != ULINT_UNDEFINED);
923
924 ret = ut_fold_ulint_pair((ulint) lock_get_trx_id(lock),
925 lock_rec_get_space_id(lock));
926
927 ret = ut_fold_ulint_pair(ret,
928 lock_rec_get_page_no(lock));
929
930 ret = ut_fold_ulint_pair(ret, heap_no);
931
932 break;
933 case LOCK_TABLE:
934 /* this check is actually not necessary for continuing
935 correct operation, but something must have gone wrong if
936 it fails. */
937 ut_a(heap_no == ULINT_UNDEFINED);
938
939 ret = (ulint) lock_get_table_id(lock);
940
941 break;
942 default:
943 ut_error;
944 }
945
946 return(ret);
947 #endif
948 }
949
950 /*******************************************************************//**
951 Checks whether i_s_locks_row_t object represents a lock_t object.
952 @return TRUE if they match */
953 static
954 ibool
locks_row_eq_lock(const i_s_locks_row_t * row,const lock_t * lock,ulint heap_no)955 locks_row_eq_lock(
956 /*==============*/
957 const i_s_locks_row_t* row, /*!< in: innodb_locks row */
958 const lock_t* lock, /*!< in: lock object */
959 ulint heap_no)/*!< in: lock's record number
960 or ULINT_UNDEFINED if the lock
961 is a table lock */
962 {
963 ut_ad(i_s_locks_row_validate(row));
964 #ifdef TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T
965 return(0);
966 #else
967 switch (lock_get_type(lock)) {
968 case LOCK_REC:
969 ut_a(heap_no != ULINT_UNDEFINED);
970
971 return(row->lock_trx_id == lock_get_trx_id(lock)
972 && row->lock_space == lock_rec_get_space_id(lock)
973 && row->lock_page == lock_rec_get_page_no(lock)
974 && row->lock_rec == heap_no);
975
976 case LOCK_TABLE:
977 /* this check is actually not necessary for continuing
978 correct operation, but something must have gone wrong if
979 it fails. */
980 ut_a(heap_no == ULINT_UNDEFINED);
981
982 return(row->lock_trx_id == lock_get_trx_id(lock)
983 && row->lock_table_id == lock_get_table_id(lock));
984
985 default:
986 ut_error;
987 return(FALSE);
988 }
989 #endif
990 }
991
992 /*******************************************************************//**
993 Searches for a row in the innodb_locks cache that has a specified id.
994 This happens in O(1) time since a hash table is used. Returns pointer to
995 the row or NULL if none is found.
996 @return row or NULL */
997 static
998 i_s_locks_row_t*
search_innodb_locks(trx_i_s_cache_t * cache,const lock_t * lock,ulint heap_no)999 search_innodb_locks(
1000 /*================*/
1001 trx_i_s_cache_t* cache, /*!< in: cache */
1002 const lock_t* lock, /*!< in: lock to search for */
1003 ulint heap_no)/*!< in: lock's record number
1004 or ULINT_UNDEFINED if the lock
1005 is a table lock */
1006 {
1007 i_s_hash_chain_t* hash_chain;
1008
1009 HASH_SEARCH(
1010 /* hash_chain->"next" */
1011 next,
1012 /* the hash table */
1013 cache->locks_hash,
1014 /* fold */
1015 fold_lock(lock, heap_no),
1016 /* the type of the next variable */
1017 i_s_hash_chain_t*,
1018 /* auxiliary variable */
1019 hash_chain,
1020 /* assertion on every traversed item */
1021 ut_ad(i_s_locks_row_validate(hash_chain->value)),
1022 /* this determines if we have found the lock */
1023 locks_row_eq_lock(hash_chain->value, lock, heap_no));
1024
1025 if (hash_chain == NULL) {
1026
1027 return(NULL);
1028 }
1029 /* else */
1030
1031 return(hash_chain->value);
1032 }
1033
1034 /*******************************************************************//**
1035 Adds new element to the locks cache, enlarging it if necessary.
1036 Returns a pointer to the added row. If the row is already present then
1037 no row is added and a pointer to the existing row is returned.
1038 If row can not be allocated then NULL is returned.
1039 @return row */
1040 static
1041 i_s_locks_row_t*
add_lock_to_cache(trx_i_s_cache_t * cache,const lock_t * lock,ulint heap_no)1042 add_lock_to_cache(
1043 /*==============*/
1044 trx_i_s_cache_t* cache, /*!< in/out: cache */
1045 const lock_t* lock, /*!< in: the element to add */
1046 ulint heap_no)/*!< in: lock's record number
1047 or ULINT_UNDEFINED if the lock
1048 is a table lock */
1049 {
1050 i_s_locks_row_t* dst_row;
1051
1052 #ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
1053 ulint i;
1054 for (i = 0; i < 10000; i++) {
1055 #endif
1056 #ifndef TEST_DO_NOT_CHECK_FOR_DUPLICATE_ROWS
1057 /* quit if this lock is already present */
1058 dst_row = search_innodb_locks(cache, lock, heap_no);
1059 if (dst_row != NULL) {
1060
1061 ut_ad(i_s_locks_row_validate(dst_row));
1062 return(dst_row);
1063 }
1064 #endif
1065
1066 dst_row = (i_s_locks_row_t*)
1067 table_cache_create_empty_row(&cache->innodb_locks, cache);
1068
1069 /* memory could not be allocated */
1070 if (dst_row == NULL) {
1071
1072 return(NULL);
1073 }
1074
1075 if (!fill_locks_row(dst_row, lock, heap_no, cache)) {
1076
1077 /* memory could not be allocated */
1078 cache->innodb_locks.rows_used--;
1079 return(NULL);
1080 }
1081
1082 #ifndef TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE
1083 HASH_INSERT(
1084 /* the type used in the hash chain */
1085 i_s_hash_chain_t,
1086 /* hash_chain->"next" */
1087 next,
1088 /* the hash table */
1089 cache->locks_hash,
1090 /* fold */
1091 fold_lock(lock, heap_no),
1092 /* add this data to the hash */
1093 &dst_row->hash_chain);
1094 #endif
1095 #ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
1096 } /* for()-loop */
1097 #endif
1098
1099 ut_ad(i_s_locks_row_validate(dst_row));
1100 return(dst_row);
1101 }
1102
1103 /*******************************************************************//**
1104 Adds new pair of locks to the lock waits cache.
1105 If memory can not be allocated then FALSE is returned.
1106 @return FALSE if allocation fails */
1107 static
1108 ibool
add_lock_wait_to_cache(trx_i_s_cache_t * cache,const i_s_locks_row_t * requested_lock_row,const i_s_locks_row_t * blocking_lock_row)1109 add_lock_wait_to_cache(
1110 /*===================*/
1111 trx_i_s_cache_t* cache, /*!< in/out: cache */
1112 const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the
1113 relevant requested lock
1114 row in innodb_locks */
1115 const i_s_locks_row_t* blocking_lock_row)/*!< in: pointer to the
1116 relevant blocking lock
1117 row in innodb_locks */
1118 {
1119 i_s_lock_waits_row_t* dst_row;
1120
1121 dst_row = (i_s_lock_waits_row_t*)
1122 table_cache_create_empty_row(&cache->innodb_lock_waits,
1123 cache);
1124
1125 /* memory could not be allocated */
1126 if (dst_row == NULL) {
1127
1128 return(FALSE);
1129 }
1130
1131 fill_lock_waits_row(dst_row, requested_lock_row, blocking_lock_row);
1132
1133 return(TRUE);
1134 }
1135
1136 /*******************************************************************//**
1137 Adds transaction's relevant (important) locks to cache.
1138 If the transaction is waiting, then the wait lock is added to
1139 innodb_locks and a pointer to the added row is returned in
1140 requested_lock_row, otherwise requested_lock_row is set to NULL.
1141 If rows can not be allocated then FALSE is returned and the value of
1142 requested_lock_row is undefined.
1143 @return FALSE if allocation fails */
1144 static
1145 ibool
add_trx_relevant_locks_to_cache(trx_i_s_cache_t * cache,const trx_t * trx,i_s_locks_row_t ** requested_lock_row)1146 add_trx_relevant_locks_to_cache(
1147 /*============================*/
1148 trx_i_s_cache_t* cache, /*!< in/out: cache */
1149 const trx_t* trx, /*!< in: transaction */
1150 i_s_locks_row_t** requested_lock_row)/*!< out: pointer to the
1151 requested lock row, or NULL or
1152 undefined */
1153 {
1154 ut_ad(lock_mutex_own());
1155
1156 /* If transaction is waiting we add the wait lock and all locks
1157 from another transactions that are blocking the wait lock. */
1158 if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
1159
1160 const lock_t* curr_lock;
1161 ulint wait_lock_heap_no;
1162 i_s_locks_row_t* blocking_lock_row;
1163 lock_queue_iterator_t iter;
1164
1165 ut_a(trx->lock.wait_lock != NULL);
1166
1167 wait_lock_heap_no
1168 = wait_lock_get_heap_no(trx->lock.wait_lock);
1169
1170 /* add the requested lock */
1171 *requested_lock_row
1172 = add_lock_to_cache(cache, trx->lock.wait_lock,
1173 wait_lock_heap_no);
1174
1175 /* memory could not be allocated */
1176 if (*requested_lock_row == NULL) {
1177
1178 return(FALSE);
1179 }
1180
1181 /* then iterate over the locks before the wait lock and
1182 add the ones that are blocking it */
1183
1184 lock_queue_iterator_reset(&iter, trx->lock.wait_lock,
1185 ULINT_UNDEFINED);
1186
1187 for (curr_lock = lock_queue_iterator_get_prev(&iter);
1188 curr_lock != NULL;
1189 curr_lock = lock_queue_iterator_get_prev(&iter)) {
1190
1191 if (lock_has_to_wait(trx->lock.wait_lock,
1192 curr_lock)) {
1193
1194 /* add the lock that is
1195 blocking trx->lock.wait_lock */
1196 blocking_lock_row
1197 = add_lock_to_cache(
1198 cache, curr_lock,
1199 /* heap_no is the same
1200 for the wait and waited
1201 locks */
1202 wait_lock_heap_no);
1203
1204 /* memory could not be allocated */
1205 if (blocking_lock_row == NULL) {
1206
1207 return(FALSE);
1208 }
1209
1210 /* add the relation between both locks
1211 to innodb_lock_waits */
1212 if (!add_lock_wait_to_cache(
1213 cache, *requested_lock_row,
1214 blocking_lock_row)) {
1215
1216 /* memory could not be allocated */
1217 return(FALSE);
1218 }
1219 }
1220 }
1221 } else {
1222
1223 *requested_lock_row = NULL;
1224 }
1225
1226 return(TRUE);
1227 }
1228
1229 /** The minimum time that a cache must not be updated after it has been
1230 read for the last time; measured in microseconds. We use this technique
1231 to ensure that SELECTs which join several INFORMATION SCHEMA tables read
1232 the same version of the cache. */
1233 #define CACHE_MIN_IDLE_TIME_US 100000 /* 0.1 sec */
1234
1235 /*******************************************************************//**
1236 Checks if the cache can safely be updated.
1237 @return TRUE if can be updated */
1238 static
1239 ibool
can_cache_be_updated(trx_i_s_cache_t * cache)1240 can_cache_be_updated(
1241 /*=================*/
1242 trx_i_s_cache_t* cache) /*!< in: cache */
1243 {
1244 ullint now;
1245
1246 /* Here we read cache->last_read without acquiring its mutex
1247 because last_read is only updated when a shared rw lock on the
1248 whole cache is being held (see trx_i_s_cache_end_read()) and
1249 we are currently holding an exclusive rw lock on the cache.
1250 So it is not possible for last_read to be updated while we are
1251 reading it. */
1252
1253 #ifdef UNIV_SYNC_DEBUG
1254 ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1255 #endif
1256
1257 now = ut_time_us(NULL);
1258 if (now - cache->last_read > CACHE_MIN_IDLE_TIME_US) {
1259
1260 return(TRUE);
1261 }
1262
1263 return(FALSE);
1264 }
1265
1266 /*******************************************************************//**
1267 Declare a cache empty, preparing it to be filled up. Not all resources
1268 are freed because they can be reused. */
1269 static
1270 void
trx_i_s_cache_clear(trx_i_s_cache_t * cache)1271 trx_i_s_cache_clear(
1272 /*================*/
1273 trx_i_s_cache_t* cache) /*!< out: cache to clear */
1274 {
1275 cache->innodb_trx.rows_used = 0;
1276 cache->innodb_locks.rows_used = 0;
1277 cache->innodb_lock_waits.rows_used = 0;
1278
1279 hash_table_clear(cache->locks_hash);
1280
1281 ha_storage_empty(&cache->storage);
1282 }
1283
1284 /*******************************************************************//**
1285 Fetches the data needed to fill the 3 INFORMATION SCHEMA tables into the
1286 table cache buffer. Cache must be locked for write. */
1287 static
1288 void
fetch_data_into_cache_low(trx_i_s_cache_t * cache,ibool only_ac_nl,trx_list_t * trx_list)1289 fetch_data_into_cache_low(
1290 /*======================*/
1291 trx_i_s_cache_t* cache, /*!< in/out: cache */
1292 ibool only_ac_nl, /*!< in: only select non-locking
1293 autocommit transactions */
1294 trx_list_t* trx_list) /*!< in: trx list */
1295 {
1296 const trx_t* trx;
1297
1298 ut_ad(trx_list == &trx_sys->rw_trx_list
1299 || trx_list == &trx_sys->ro_trx_list
1300 || trx_list == &trx_sys->mysql_trx_list);
1301
1302 ut_ad(only_ac_nl == (trx_list == &trx_sys->mysql_trx_list));
1303
1304 /* Iterate over the transaction list and add each one
1305 to innodb_trx's cache. We also add all locks that are relevant
1306 to each transaction into innodb_locks' and innodb_lock_waits'
1307 caches. */
1308
1309 for (trx = UT_LIST_GET_FIRST(*trx_list);
1310 trx != NULL;
1311 trx =
1312 (trx_list == &trx_sys->mysql_trx_list
1313 ? UT_LIST_GET_NEXT(mysql_trx_list, trx)
1314 : UT_LIST_GET_NEXT(trx_list, trx))) {
1315
1316 i_s_trx_row_t* trx_row;
1317 i_s_locks_row_t* requested_lock_row;
1318
1319 if (trx->state == TRX_STATE_NOT_STARTED
1320 || (only_ac_nl && !trx_is_autocommit_non_locking(trx))) {
1321
1322 continue;
1323 }
1324
1325 assert_trx_nonlocking_or_in_list(trx);
1326
1327 ut_ad(trx->in_ro_trx_list
1328 == (trx_list == &trx_sys->ro_trx_list));
1329
1330 ut_ad(trx->in_rw_trx_list
1331 == (trx_list == &trx_sys->rw_trx_list));
1332
1333 if (!add_trx_relevant_locks_to_cache(cache, trx,
1334 &requested_lock_row)) {
1335
1336 cache->is_truncated = TRUE;
1337 return;
1338 }
1339
1340 trx_row = (i_s_trx_row_t*)
1341 table_cache_create_empty_row(&cache->innodb_trx,
1342 cache);
1343
1344 /* memory could not be allocated */
1345 if (trx_row == NULL) {
1346
1347 cache->is_truncated = TRUE;
1348 return;
1349 }
1350
1351 if (!fill_trx_row(trx_row, trx, requested_lock_row, cache)) {
1352
1353 /* memory could not be allocated */
1354 cache->innodb_trx.rows_used--;
1355 cache->is_truncated = TRUE;
1356 return;
1357 }
1358 }
1359 }
1360
1361 /*******************************************************************//**
1362 Fetches the data needed to fill the 3 INFORMATION SCHEMA tables into the
1363 table cache buffer. Cache must be locked for write. */
1364 static
1365 void
fetch_data_into_cache(trx_i_s_cache_t * cache)1366 fetch_data_into_cache(
1367 /*==================*/
1368 trx_i_s_cache_t* cache) /*!< in/out: cache */
1369 {
1370 ut_ad(lock_mutex_own());
1371 ut_ad(mutex_own(&trx_sys->mutex));
1372
1373 trx_i_s_cache_clear(cache);
1374
1375 fetch_data_into_cache_low(cache, FALSE, &trx_sys->rw_trx_list);
1376 fetch_data_into_cache_low(cache, FALSE, &trx_sys->ro_trx_list);
1377
1378 /* Only select autocommit non-locking selects because they can
1379 only be on the MySQL transaction list (TRUE). */
1380 fetch_data_into_cache_low(cache, TRUE, &trx_sys->mysql_trx_list);
1381
1382 cache->is_truncated = FALSE;
1383 }
1384
1385 /*******************************************************************//**
1386 Update the transactions cache if it has not been read for some time.
1387 Called from handler/i_s.cc.
1388 @return 0 - fetched, 1 - not */
1389 UNIV_INTERN
1390 int
trx_i_s_possibly_fetch_data_into_cache(trx_i_s_cache_t * cache)1391 trx_i_s_possibly_fetch_data_into_cache(
1392 /*===================================*/
1393 trx_i_s_cache_t* cache) /*!< in/out: cache */
1394 {
1395 if (!can_cache_be_updated(cache)) {
1396
1397 return(1);
1398 }
1399
1400 /* We need to read trx_sys and record/table lock queues */
1401
1402 lock_mutex_enter();
1403
1404 mutex_enter(&trx_sys->mutex);
1405
1406 fetch_data_into_cache(cache);
1407
1408 mutex_exit(&trx_sys->mutex);
1409
1410 lock_mutex_exit();
1411
1412 return(0);
1413 }
1414
1415 /*******************************************************************//**
1416 Returns TRUE if the data in the cache is truncated due to the memory
1417 limit posed by TRX_I_S_MEM_LIMIT.
1418 @return TRUE if truncated */
1419 UNIV_INTERN
1420 ibool
trx_i_s_cache_is_truncated(trx_i_s_cache_t * cache)1421 trx_i_s_cache_is_truncated(
1422 /*=======================*/
1423 trx_i_s_cache_t* cache) /*!< in: cache */
1424 {
1425 return(cache->is_truncated);
1426 }
1427
1428 /*******************************************************************//**
1429 Initialize INFORMATION SCHEMA trx related cache. */
1430 UNIV_INTERN
1431 void
trx_i_s_cache_init(trx_i_s_cache_t * cache)1432 trx_i_s_cache_init(
1433 /*===============*/
1434 trx_i_s_cache_t* cache) /*!< out: cache to init */
1435 {
1436 /* The latching is done in the following order:
1437 acquire trx_i_s_cache_t::rw_lock, X
1438 acquire lock mutex
1439 release lock mutex
1440 release trx_i_s_cache_t::rw_lock
1441 acquire trx_i_s_cache_t::rw_lock, S
1442 acquire trx_i_s_cache_t::last_read_mutex
1443 release trx_i_s_cache_t::last_read_mutex
1444 release trx_i_s_cache_t::rw_lock */
1445
1446 rw_lock_create(trx_i_s_cache_lock_key, &cache->rw_lock,
1447 SYNC_TRX_I_S_RWLOCK);
1448
1449 cache->last_read = 0;
1450
1451 mutex_create(cache_last_read_mutex_key,
1452 &cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ);
1453
1454 table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t));
1455 table_cache_init(&cache->innodb_locks, sizeof(i_s_locks_row_t));
1456 table_cache_init(&cache->innodb_lock_waits,
1457 sizeof(i_s_lock_waits_row_t));
1458
1459 cache->locks_hash = hash_create(LOCKS_HASH_CELLS_NUM);
1460
1461 cache->storage = ha_storage_create(CACHE_STORAGE_INITIAL_SIZE,
1462 CACHE_STORAGE_HASH_CELLS);
1463
1464 cache->mem_allocd = 0;
1465
1466 cache->is_truncated = FALSE;
1467 }
1468
1469 /*******************************************************************//**
1470 Free the INFORMATION SCHEMA trx related cache. */
1471 UNIV_INTERN
1472 void
trx_i_s_cache_free(trx_i_s_cache_t * cache)1473 trx_i_s_cache_free(
1474 /*===============*/
1475 trx_i_s_cache_t* cache) /*!< in, own: cache to free */
1476 {
1477 hash_table_free(cache->locks_hash);
1478 ha_storage_free(cache->storage);
1479 table_cache_free(&cache->innodb_trx);
1480 table_cache_free(&cache->innodb_locks);
1481 table_cache_free(&cache->innodb_lock_waits);
1482 memset(cache, 0, sizeof *cache);
1483 }
1484
1485 /*******************************************************************//**
1486 Issue a shared/read lock on the tables cache. */
1487 UNIV_INTERN
1488 void
trx_i_s_cache_start_read(trx_i_s_cache_t * cache)1489 trx_i_s_cache_start_read(
1490 /*=====================*/
1491 trx_i_s_cache_t* cache) /*!< in: cache */
1492 {
1493 rw_lock_s_lock(&cache->rw_lock);
1494 }
1495
1496 /*******************************************************************//**
1497 Release a shared/read lock on the tables cache. */
1498 UNIV_INTERN
1499 void
trx_i_s_cache_end_read(trx_i_s_cache_t * cache)1500 trx_i_s_cache_end_read(
1501 /*===================*/
1502 trx_i_s_cache_t* cache) /*!< in: cache */
1503 {
1504 ullint now;
1505
1506 #ifdef UNIV_SYNC_DEBUG
1507 ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED));
1508 #endif
1509
1510 /* update cache last read time */
1511 now = ut_time_us(NULL);
1512 mutex_enter(&cache->last_read_mutex);
1513 cache->last_read = now;
1514 mutex_exit(&cache->last_read_mutex);
1515
1516 rw_lock_s_unlock(&cache->rw_lock);
1517 }
1518
1519 /*******************************************************************//**
1520 Issue an exclusive/write lock on the tables cache. */
1521 UNIV_INTERN
1522 void
trx_i_s_cache_start_write(trx_i_s_cache_t * cache)1523 trx_i_s_cache_start_write(
1524 /*======================*/
1525 trx_i_s_cache_t* cache) /*!< in: cache */
1526 {
1527 rw_lock_x_lock(&cache->rw_lock);
1528 }
1529
1530 /*******************************************************************//**
1531 Release an exclusive/write lock on the tables cache. */
1532 UNIV_INTERN
1533 void
trx_i_s_cache_end_write(trx_i_s_cache_t * cache)1534 trx_i_s_cache_end_write(
1535 /*====================*/
1536 trx_i_s_cache_t* cache) /*!< in: cache */
1537 {
1538 #ifdef UNIV_SYNC_DEBUG
1539 ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1540 #endif
1541
1542 rw_lock_x_unlock(&cache->rw_lock);
1543 }
1544
1545 /*******************************************************************//**
1546 Selects a INFORMATION SCHEMA table cache from the whole cache.
1547 @return table cache */
1548 static
1549 i_s_table_cache_t*
cache_select_table(trx_i_s_cache_t * cache,enum i_s_table table)1550 cache_select_table(
1551 /*===============*/
1552 trx_i_s_cache_t* cache, /*!< in: whole cache */
1553 enum i_s_table table) /*!< in: which table */
1554 {
1555 i_s_table_cache_t* table_cache;
1556
1557 #ifdef UNIV_SYNC_DEBUG
1558 ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED)
1559 || rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1560 #endif
1561
1562 switch (table) {
1563 case I_S_INNODB_TRX:
1564 table_cache = &cache->innodb_trx;
1565 break;
1566 case I_S_INNODB_LOCKS:
1567 table_cache = &cache->innodb_locks;
1568 break;
1569 case I_S_INNODB_LOCK_WAITS:
1570 table_cache = &cache->innodb_lock_waits;
1571 break;
1572 default:
1573 ut_error;
1574 }
1575
1576 return(table_cache);
1577 }
1578
1579 /*******************************************************************//**
1580 Retrieves the number of used rows in the cache for a given
1581 INFORMATION SCHEMA table.
1582 @return number of rows */
1583 UNIV_INTERN
1584 ulint
trx_i_s_cache_get_rows_used(trx_i_s_cache_t * cache,enum i_s_table table)1585 trx_i_s_cache_get_rows_used(
1586 /*========================*/
1587 trx_i_s_cache_t* cache, /*!< in: cache */
1588 enum i_s_table table) /*!< in: which table */
1589 {
1590 i_s_table_cache_t* table_cache;
1591
1592 table_cache = cache_select_table(cache, table);
1593
1594 return(table_cache->rows_used);
1595 }
1596
1597 /*******************************************************************//**
1598 Retrieves the nth row (zero-based) in the cache for a given
1599 INFORMATION SCHEMA table.
1600 @return row */
1601 UNIV_INTERN
1602 void*
trx_i_s_cache_get_nth_row(trx_i_s_cache_t * cache,enum i_s_table table,ulint n)1603 trx_i_s_cache_get_nth_row(
1604 /*======================*/
1605 trx_i_s_cache_t* cache, /*!< in: cache */
1606 enum i_s_table table, /*!< in: which table */
1607 ulint n) /*!< in: row number */
1608 {
1609 i_s_table_cache_t* table_cache;
1610 ulint i;
1611 void* row;
1612
1613 table_cache = cache_select_table(cache, table);
1614
1615 ut_a(n < table_cache->rows_used);
1616
1617 row = NULL;
1618
1619 for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
1620
1621 if (table_cache->chunks[i].offset
1622 + table_cache->chunks[i].rows_allocd > n) {
1623
1624 row = (char*) table_cache->chunks[i].base
1625 + (n - table_cache->chunks[i].offset)
1626 * table_cache->row_size;
1627 break;
1628 }
1629 }
1630
1631 ut_a(row != NULL);
1632
1633 return(row);
1634 }
1635
1636 /*******************************************************************//**
1637 Crafts a lock id string from a i_s_locks_row_t object. Returns its
1638 second argument. This function aborts if there is not enough space in
1639 lock_id. Be sure to provide at least TRX_I_S_LOCK_ID_MAX_LEN + 1 if you
1640 want to be 100% sure that it will not abort.
1641 @return resulting lock id */
1642 UNIV_INTERN
1643 char*
trx_i_s_create_lock_id(const i_s_locks_row_t * row,char * lock_id,ulint lock_id_size)1644 trx_i_s_create_lock_id(
1645 /*===================*/
1646 const i_s_locks_row_t* row, /*!< in: innodb_locks row */
1647 char* lock_id,/*!< out: resulting lock_id */
1648 ulint lock_id_size)/*!< in: size of the lock id
1649 buffer */
1650 {
1651 int res_len;
1652
1653 /* please adjust TRX_I_S_LOCK_ID_MAX_LEN if you change this */
1654
1655 if (row->lock_space != ULINT_UNDEFINED) {
1656 /* record lock */
1657 res_len = ut_snprintf(lock_id, lock_id_size,
1658 TRX_ID_FMT ":%lu:%lu:%lu",
1659 row->lock_trx_id, row->lock_space,
1660 row->lock_page, row->lock_rec);
1661 } else {
1662 /* table lock */
1663 res_len = ut_snprintf(lock_id, lock_id_size,
1664 TRX_ID_FMT":" UINT64PF,
1665 row->lock_trx_id,
1666 row->lock_table_id);
1667 }
1668
1669 /* the typecast is safe because snprintf(3) never returns
1670 negative result */
1671 ut_a(res_len >= 0);
1672 ut_a((ulint) res_len < lock_id_size);
1673
1674 return(lock_id);
1675 }
1676