1
/*****************************************************************************
3
Copyright (C) 2007, 2010, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
21
INFORMATION SCHEMA innodb_trx, innodb_locks and
22
innodb_lock_waits tables fetch code.
24
The code below fetches information needed to fill those
25
3 dynamic tables and uploads it into a "transactions
26
table cache" for later retrieval.
28
Created July 17, 2007 Vasil Dimov
29
*******************************************************/
32
/* Found during the build of 5.5.3 on Linux 2.4 and early 2.6 kernels:
33
The includes "univ.i" -> "my_global.h" cause a different path
34
to be taken further down with pthread functions and types,
35
so they must come first.
36
From the symptoms, this is related to bug#46587 in the MySQL bug DB.
40
#if !defined(BUILD_DRIZZLE)
41
# include <mysql/plugin.h>
45
#include "dict0dict.h"
46
#include "ha0storage.h"
47
#include "ha_prototypes.h"
48
#include "hash0hash.h"
49
#include "lock0iter.h"
50
#include "lock0lock.h"
52
#include "page0page.h"
57
#include "sync0sync.h"
58
#include "sync0types.h"
65
#include <drizzled/session.h>
67
/** Initial number of rows in the table cache */
68
#define TABLE_CACHE_INITIAL_ROWSNUM 1024
70
/** @brief The maximum number of chunks to allocate for a table cache.
72
The rows of a table cache are stored in a set of chunks. When a new
73
row is added a new chunk is allocated if necessary. Assuming that the
74
first one is 1024 rows (TABLE_CACHE_INITIAL_ROWSNUM) and each
75
subsequent is N/2 where N is the number of rows we have allocated till
76
now, then 39th chunk would accommodate 1677416425 rows and all chunks
77
would accommodate 3354832851 rows. */
78
#define MEM_CHUNKS_IN_TABLE_CACHE 39
80
/** The following are some testing auxiliary macros. Do not enable them
81
in a production environment. */
85
/** If this is enabled then lock folds will always be different
86
resulting in equal rows being put in a different cells of the hash
87
table. Checking for duplicates will be flawed because different
88
fold will be calculated when a row is searched in the hash table. */
89
#define TEST_LOCK_FOLD_ALWAYS_DIFFERENT
93
/** This effectively kills the search-for-duplicate-before-adding-a-row
94
function, but searching in the hash is still performed. It will always
95
be assumed that lock is not present and insertion will be performed in
97
#define TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T
101
/** This aggressively repeats adding each row many times. Depending on
102
the above settings this may be noop or may result in lots of rows being
104
#define TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
108
/** Very similar to TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T but hash
109
table search is not performed at all. */
110
#define TEST_DO_NOT_CHECK_FOR_DUPLICATE_ROWS
114
/** Do not insert each row into the hash table, duplicates may appear
115
if this is enabled, also if this is enabled searching into the hash is
116
noop because it will be empty. */
117
#define TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE
121
/** Memory limit passed to ha_storage_put_memlim().
122
@param cache hash storage
123
@return maximum allowed allocation size */
124
#define MAX_ALLOWED_FOR_STORAGE(cache) \
126
- (cache)->mem_allocd)
128
/** Memory limit in table_cache_create_empty_row().
129
@param cache hash storage
130
@return maximum allowed allocation size */
131
#define MAX_ALLOWED_FOR_ALLOC(cache) \
133
- (cache)->mem_allocd \
134
- ha_storage_get_size((cache)->storage))
136
/** Memory for each table in the intermediate buffer is allocated in
137
separate chunks. These chunks are considered to be concatenated to
138
represent one flat array of rows. */
139
typedef struct i_s_mem_chunk_struct {
140
ulint offset; /*!< offset, in number of rows */
141
ulint rows_allocd; /*!< the size of this chunk, in number
143
void* base; /*!< start of the chunk */
146
/** This represents one table's cache. */
147
typedef struct i_s_table_cache_struct {
148
ulint rows_used; /*!< number of used rows */
149
ulint rows_allocd; /*!< number of allocated rows */
150
ulint row_size; /*!< size of a single row */
151
i_s_mem_chunk_t chunks[MEM_CHUNKS_IN_TABLE_CACHE]; /*!< array of
152
memory chunks that stores the
156
/** This structure describes the intermediate buffer */
157
struct trx_i_s_cache_struct {
158
rw_lock_t rw_lock; /*!< read-write lock protecting
159
the rest of this structure */
160
ullint last_read; /*!< last time the cache was read;
161
measured in microseconds since
163
mutex_t last_read_mutex;/*!< mutex protecting the
164
last_read member - it is updated
165
inside a shared lock of the
167
i_s_table_cache_t innodb_trx; /*!< innodb_trx table */
168
i_s_table_cache_t innodb_locks; /*!< innodb_locks table */
169
i_s_table_cache_t innodb_lock_waits;/*!< innodb_lock_waits table */
170
/** the hash table size is LOCKS_HASH_CELLS_NUM * sizeof(void*) bytes */
171
#define LOCKS_HASH_CELLS_NUM 10000
172
hash_table_t* locks_hash; /*!< hash table used to eliminate
173
duplicate entries in the
174
innodb_locks table */
175
/** Initial size of the cache storage */
176
#define CACHE_STORAGE_INITIAL_SIZE 1024
177
/** Number of hash cells in the cache storage */
178
#define CACHE_STORAGE_HASH_CELLS 2048
179
ha_storage_t* storage; /*!< storage for external volatile
180
data that can possibly not be
181
available later, when we release
183
ulint mem_allocd; /*!< the amount of memory
184
allocated with mem_alloc*() */
185
ibool is_truncated; /*!< this is TRUE if the memory
186
limit was hit and thus the data
187
in the cache is truncated */
190
/** This is the intermediate buffer where data needed to fill the
191
INFORMATION SCHEMA tables is fetched and later retrieved by the C++
192
code in handler/i_s.cc. */
193
static trx_i_s_cache_t trx_i_s_cache_static;
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
UNIV_INTERN trx_i_s_cache_t* trx_i_s_cache = &trx_i_s_cache_static;
199
/* Key to register the lock/mutex with performance schema */
200
#ifdef UNIV_PFS_RWLOCK
201
UNIV_INTERN mysql_pfs_key_t trx_i_s_cache_lock_key;
202
#endif /* UNIV_PFS_RWLOCK */
204
#ifdef UNIV_PFS_MUTEX
205
UNIV_INTERN mysql_pfs_key_t cache_last_read_mutex_key;
206
#endif /* UNIV_PFS_MUTEX */
208
/*******************************************************************//**
209
For a record lock that is in waiting state retrieves the only bit that
210
is set, for a table lock returns ULINT_UNDEFINED.
211
@return record number within the heap */
214
wait_lock_get_heap_no(
215
/*==================*/
216
const lock_t* lock) /*!< in: lock */
220
switch (lock_get_type(lock)) {
222
ret = lock_rec_find_set_bit(lock);
223
ut_a(ret != ULINT_UNDEFINED);
226
ret = ULINT_UNDEFINED;
235
/*******************************************************************//**
236
Initializes the members of a table cache. */
241
i_s_table_cache_t* table_cache, /*!< out: table cache */
242
size_t row_size) /*!< in: the size of a
247
table_cache->rows_used = 0;
248
table_cache->rows_allocd = 0;
249
table_cache->row_size = row_size;
251
for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
253
/* the memory is actually allocated in
254
table_cache_create_empty_row() */
255
table_cache->chunks[i].base = NULL;
259
/*******************************************************************//**
260
Frees a table cache. */
265
i_s_table_cache_t* table_cache) /*!< in/out: table cache */
269
for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
271
/* the memory is actually allocated in
272
table_cache_create_empty_row() */
273
if (table_cache->chunks[i].base) {
274
mem_free(table_cache->chunks[i].base);
275
table_cache->chunks[i].base = NULL;
280
/*******************************************************************//**
281
Returns an empty row from a table cache. The row is allocated if no more
282
empty rows are available. The number of used rows is incremented.
283
If the memory limit is hit then NULL is returned and nothing is
285
@return empty row, or NULL if out of memory */
288
table_cache_create_empty_row(
289
/*=========================*/
290
i_s_table_cache_t* table_cache, /*!< in/out: table cache */
291
trx_i_s_cache_t* cache) /*!< in/out: cache to record
298
ut_a(table_cache->rows_used <= table_cache->rows_allocd);
300
if (table_cache->rows_used == table_cache->rows_allocd) {
302
/* rows_used == rows_allocd means that new chunk needs
303
to be allocated: either no more empty rows in the
304
last allocated chunk or nothing has been allocated yet
305
(rows_num == rows_allocd == 0); */
307
i_s_mem_chunk_t* chunk;
313
/* find the first not allocated chunk */
314
for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
316
if (table_cache->chunks[i].base == NULL) {
322
/* i == MEM_CHUNKS_IN_TABLE_CACHE means that all chunks
323
have been allocated :-X */
324
ut_a(i < MEM_CHUNKS_IN_TABLE_CACHE);
326
/* allocate the chunk we just found */
330
/* first chunk, nothing is allocated yet */
331
req_rows = TABLE_CACHE_INITIAL_ROWSNUM;
334
/* Memory is increased by the formula
335
new = old + old / 2; We are trying not to be
336
aggressive here (= using the common new = old * 2)
337
because the allocated memory will not be freed
338
until InnoDB exit (it is reused). So it is better
339
to once allocate the memory in more steps, but
340
have less unused/wasted memory than to use less
341
steps in allocation (which is done once in a
342
lifetime) but end up with lots of unused/wasted
344
req_rows = table_cache->rows_allocd / 2;
346
req_bytes = req_rows * table_cache->row_size;
348
if (req_bytes > MAX_ALLOWED_FOR_ALLOC(cache)) {
353
chunk = &table_cache->chunks[i];
355
chunk->base = mem_alloc2(req_bytes, &got_bytes);
357
got_rows = got_bytes / table_cache->row_size;
359
cache->mem_allocd += got_bytes;
362
printf("allocating chunk %d req bytes=%lu, got bytes=%lu, "
364
"req rows=%lu, got rows=%lu\n",
365
i, req_bytes, got_bytes,
366
table_cache->row_size,
370
chunk->rows_allocd = got_rows;
372
table_cache->rows_allocd += got_rows;
374
/* adjust the offset of the next chunk */
375
if (i < MEM_CHUNKS_IN_TABLE_CACHE - 1) {
377
table_cache->chunks[i + 1].offset
378
= chunk->offset + chunk->rows_allocd;
381
/* return the first empty row in the newly allocated
389
/* there is an empty row, no need to allocate new
392
/* find the first chunk that contains allocated but
394
for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
396
if (table_cache->chunks[i].offset
397
+ table_cache->chunks[i].rows_allocd
398
> table_cache->rows_used) {
404
/* i == MEM_CHUNKS_IN_TABLE_CACHE means that all chunks
406
table_cache->rows_used != table_cache->rows_allocd means
407
exactly the opposite - there are allocated but
408
empty/unused rows :-X */
409
ut_a(i < MEM_CHUNKS_IN_TABLE_CACHE);
411
chunk_start = (char*) table_cache->chunks[i].base;
412
offset = table_cache->rows_used
413
- table_cache->chunks[i].offset;
415
row = chunk_start + offset * table_cache->row_size;
418
table_cache->rows_used++;
424
/*******************************************************************//**
425
Validates a row in the locks cache.
426
@return TRUE if valid */
429
i_s_locks_row_validate(
430
/*===================*/
431
const i_s_locks_row_t* row) /*!< in: row to validate */
433
ut_ad(row->lock_trx_id != 0);
434
ut_ad(row->lock_mode != NULL);
435
ut_ad(row->lock_type != NULL);
436
ut_ad(row->lock_table != NULL);
437
ut_ad(row->lock_table_id != 0);
439
if (row->lock_space == ULINT_UNDEFINED) {
441
ut_ad(!strcmp("TABLE", row->lock_type));
442
ut_ad(row->lock_index == NULL);
443
ut_ad(row->lock_data == NULL);
444
ut_ad(row->lock_page == ULINT_UNDEFINED);
445
ut_ad(row->lock_rec == ULINT_UNDEFINED);
448
ut_ad(!strcmp("RECORD", row->lock_type));
449
ut_ad(row->lock_index != NULL);
450
ut_ad(row->lock_data != NULL);
451
ut_ad(row->lock_page != ULINT_UNDEFINED);
452
ut_ad(row->lock_rec != ULINT_UNDEFINED);
457
#endif /* UNIV_DEBUG */
459
/*******************************************************************//**
460
Fills i_s_trx_row_t object.
461
If memory can not be allocated then FALSE is returned.
462
@return FALSE if allocation fails */
467
i_s_trx_row_t* row, /*!< out: result object
469
const trx_t* trx, /*!< in: transaction to
471
const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the
473
innodb_locks if trx is
474
waiting or NULL if trx
476
trx_i_s_cache_t* cache) /*!< in/out: cache into
477
which to copy volatile
484
ut_ad(mutex_own(&kernel_mutex));
486
row->trx_id = trx->id;
487
row->trx_started = (ib_time_t) trx->start_time;
488
row->trx_state = trx_get_que_state_str(trx);
489
row->requested_lock_row = requested_lock_row;
490
ut_ad(requested_lock_row == NULL
491
|| i_s_locks_row_validate(requested_lock_row));
493
if (trx->wait_lock != NULL) {
494
ut_a(requested_lock_row != NULL);
495
row->trx_wait_started = (ib_time_t) trx->wait_started;
497
ut_a(requested_lock_row == NULL);
498
row->trx_wait_started = 0;
501
row->trx_weight = (ullint) TRX_WEIGHT(trx);
503
if (trx->mysql_thd == NULL) {
504
/* For internal transactions e.g., purge and transactions
505
being recovered at startup there is no associated MySQL
506
thread data structure. */
507
row->trx_mysql_thread_id = 0;
508
row->trx_query = NULL;
512
row->trx_mysql_thread_id = trx->session()->getSessionId();
513
stmt= trx->mysql_thd->getQueryStringCopy(stmt_len);
517
char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1];
519
if (stmt_len > TRX_I_S_TRX_QUERY_MAX_LEN) {
520
stmt_len = TRX_I_S_TRX_QUERY_MAX_LEN;
523
memcpy(query, stmt, stmt_len);
524
query[stmt_len] = '\0';
526
row->trx_query = static_cast<const char *>(ha_storage_put_memlim(
527
cache->storage, stmt, stmt_len + 1,
528
MAX_ALLOWED_FOR_STORAGE(cache)));
530
if (row->trx_query == NULL) {
536
row->trx_query = NULL;
542
if (s != NULL && s[0] != '\0') {
544
TRX_I_S_STRING_COPY(s, row->trx_operation_state,
545
TRX_I_S_TRX_OP_STATE_MAX_LEN, cache);
547
if (row->trx_operation_state == NULL) {
553
row->trx_operation_state = NULL;
556
// row->trx_tables_in_use = trx->n_mysql_tables_in_use;
558
row->trx_tables_locked = trx->mysql_n_tables_locked;
560
row->trx_lock_structs = UT_LIST_GET_LEN(trx->trx_locks);
562
row->trx_lock_memory_bytes = mem_heap_get_size(trx->lock_heap);
564
row->trx_rows_locked = lock_number_of_rows_locked(trx);
566
row->trx_rows_modified = trx->undo_no;
568
row->trx_concurrency_tickets = trx->n_tickets_to_enter_innodb;
570
switch (trx->isolation_level) {
571
case TRX_ISO_READ_UNCOMMITTED:
572
row->trx_isolation_level = "READ UNCOMMITTED";
574
case TRX_ISO_READ_COMMITTED:
575
row->trx_isolation_level = "READ COMMITTED";
577
case TRX_ISO_REPEATABLE_READ:
578
row->trx_isolation_level = "REPEATABLE READ";
580
case TRX_ISO_SERIALIZABLE:
581
row->trx_isolation_level = "SERIALIZABLE";
583
/* Should not happen as TRX_ISO_READ_COMMITTED is default */
585
row->trx_isolation_level = "UNKNOWN";
588
row->trx_unique_checks = (ibool) trx->check_unique_secondary;
590
row->trx_foreign_key_checks = (ibool) trx->check_foreigns;
592
s = trx->detailed_error;
594
if (s != NULL && s[0] != '\0') {
596
TRX_I_S_STRING_COPY(s,
597
row->trx_foreign_key_error,
598
TRX_I_S_TRX_FK_ERROR_MAX_LEN, cache);
600
if (row->trx_foreign_key_error == NULL) {
605
row->trx_foreign_key_error = NULL;
608
row->trx_has_search_latch = (ibool) trx->has_search_latch;
610
row->trx_search_latch_timeout = trx->search_latch_timeout;
615
/*******************************************************************//**
616
Format the nth field of "rec" and put it in "buf". The result is always
617
NUL-terminated. Returns the number of bytes that were written to "buf"
618
(including the terminating NUL).
619
@return end of the result */
624
char* buf, /*!< out: buffer */
625
ulint buf_size,/*!< in: buffer size in bytes */
626
ulint n, /*!< in: number of field */
627
const dict_index_t* index, /*!< in: index */
628
const rec_t* rec, /*!< in: record */
629
const ulint* offsets)/*!< in: record offsets, returned
630
by rec_get_offsets() */
634
dict_field_t* dict_field;
637
ut_ad(rec_offs_validate(rec, NULL, offsets));
647
/* we must append ", " before the actual data */
655
memcpy(buf, ", ", 3);
662
/* now buf_size >= 1 */
664
data = rec_get_nth_field(rec, offsets, n, &data_len);
666
dict_field = dict_index_get_nth_field(index, n);
668
ret += row_raw_format((const char*) data, data_len,
669
dict_field, buf, buf_size);
674
/*******************************************************************//**
675
Fills the "lock_data" member of i_s_locks_row_t object.
676
If memory can not be allocated then FALSE is returned.
677
@return FALSE if allocation fails */
682
const char** lock_data,/*!< out: "lock_data" to fill */
683
const lock_t* lock, /*!< in: lock used to find the data */
684
ulint heap_no,/*!< in: rec num used to find the data */
685
trx_i_s_cache_t* cache) /*!< in/out: cache where to store
690
const buf_block_t* block;
694
ut_a(lock_get_type(lock) == LOCK_REC);
698
block = buf_page_try_get(lock_rec_get_space_id(lock),
699
lock_rec_get_page_no(lock),
711
page = (const page_t*) buf_block_get_frame(block);
713
rec = page_find_rec_with_heap_no(page, heap_no);
715
if (page_rec_is_infimum(rec)) {
717
*lock_data = ha_storage_put_str_memlim(
718
cache->storage, "infimum pseudo-record",
719
MAX_ALLOWED_FOR_STORAGE(cache));
720
} else if (page_rec_is_supremum(rec)) {
722
*lock_data = ha_storage_put_str_memlim(
723
cache->storage, "supremum pseudo-record",
724
MAX_ALLOWED_FOR_STORAGE(cache));
727
const dict_index_t* index;
730
ulint offsets_onstack[REC_OFFS_NORMAL_SIZE];
732
char buf[TRX_I_S_LOCK_DATA_MAX_LEN];
736
rec_offs_init(offsets_onstack);
737
offsets = offsets_onstack;
739
index = lock_rec_get_index(lock);
741
n_fields = dict_index_get_n_unique(index);
746
offsets = rec_get_offsets(rec, index, offsets, n_fields,
749
/* format and store the data */
752
for (i = 0; i < n_fields; i++) {
754
buf_used += put_nth_field(
755
buf + buf_used, sizeof(buf) - buf_used,
756
i, index, rec, offsets) - 1;
759
*lock_data = (const char*) ha_storage_put_memlim(
760
cache->storage, buf, buf_used + 1,
761
MAX_ALLOWED_FOR_STORAGE(cache));
763
if (UNIV_UNLIKELY(heap != NULL)) {
765
/* this means that rec_get_offsets() has created a new
766
heap and has stored offsets in it; check that this is
767
really the case and free the heap */
768
ut_a(offsets != offsets_onstack);
775
if (*lock_data == NULL) {
783
/*******************************************************************//**
784
Fills i_s_locks_row_t object. Returns its first argument.
785
If memory can not be allocated then FALSE is returned.
786
@return FALSE if allocation fails */
791
i_s_locks_row_t* row, /*!< out: result object that's filled */
792
const lock_t* lock, /*!< in: lock to get data from */
793
ulint heap_no,/*!< in: lock's record number
794
or ULINT_UNDEFINED if the lock
796
trx_i_s_cache_t* cache) /*!< in/out: cache into which to copy
799
row->lock_trx_id = lock_get_trx_id(lock);
800
row->lock_mode = lock_get_mode_str(lock);
801
row->lock_type = lock_get_type_str(lock);
803
row->lock_table = ha_storage_put_str_memlim(
804
cache->storage, lock_get_table_name(lock),
805
MAX_ALLOWED_FOR_STORAGE(cache));
807
/* memory could not be allocated */
808
if (row->lock_table == NULL) {
813
switch (lock_get_type(lock)) {
815
row->lock_index = ha_storage_put_str_memlim(
816
cache->storage, lock_rec_get_index_name(lock),
817
MAX_ALLOWED_FOR_STORAGE(cache));
819
/* memory could not be allocated */
820
if (row->lock_index == NULL) {
825
row->lock_space = lock_rec_get_space_id(lock);
826
row->lock_page = lock_rec_get_page_no(lock);
827
row->lock_rec = heap_no;
829
if (!fill_lock_data(&row->lock_data, lock, heap_no, cache)) {
831
/* memory could not be allocated */
837
row->lock_index = NULL;
839
row->lock_space = ULINT_UNDEFINED;
840
row->lock_page = ULINT_UNDEFINED;
841
row->lock_rec = ULINT_UNDEFINED;
843
row->lock_data = NULL;
850
row->lock_table_id = lock_get_table_id(lock);
852
row->hash_chain.value = row;
853
ut_ad(i_s_locks_row_validate(row));
858
/*******************************************************************//**
859
Fills i_s_lock_waits_row_t object. Returns its first argument.
860
@return result object that's filled */
862
i_s_lock_waits_row_t*
865
i_s_lock_waits_row_t* row, /*!< out: result object
867
const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the
868
relevant requested lock
869
row in innodb_locks */
870
const i_s_locks_row_t* blocking_lock_row)/*!< in: pointer to the
871
relevant blocking lock
872
row in innodb_locks */
874
ut_ad(i_s_locks_row_validate(requested_lock_row));
875
ut_ad(i_s_locks_row_validate(blocking_lock_row));
877
row->requested_lock_row = requested_lock_row;
878
row->blocking_lock_row = blocking_lock_row;
883
/*******************************************************************//**
884
Calculates a hash fold for a lock. For a record lock the fold is
885
calculated from 4 elements, which uniquely identify a lock at a given
886
point in time: transaction id, space id, page number, record number.
887
For a table lock the fold is table's id.
893
const lock_t* lock, /*!< in: lock object to fold */
894
ulint heap_no)/*!< in: lock's record number
895
or ULINT_UNDEFINED if the lock
898
#ifdef TEST_LOCK_FOLD_ALWAYS_DIFFERENT
899
static ulint fold = 0;
905
switch (lock_get_type(lock)) {
907
ut_a(heap_no != ULINT_UNDEFINED);
909
ret = ut_fold_ulint_pair((ulint) lock_get_trx_id(lock),
910
lock_rec_get_space_id(lock));
912
ret = ut_fold_ulint_pair(ret,
913
lock_rec_get_page_no(lock));
915
ret = ut_fold_ulint_pair(ret, heap_no);
919
/* this check is actually not necessary for continuing
920
correct operation, but something must have gone wrong if
922
ut_a(heap_no == ULINT_UNDEFINED);
924
ret = (ulint) lock_get_table_id(lock);
935
/*******************************************************************//**
936
Checks whether i_s_locks_row_t object represents a lock_t object.
937
@return TRUE if they match */
942
const i_s_locks_row_t* row, /*!< in: innodb_locks row */
943
const lock_t* lock, /*!< in: lock object */
944
ulint heap_no)/*!< in: lock's record number
945
or ULINT_UNDEFINED if the lock
948
ut_ad(i_s_locks_row_validate(row));
949
#ifdef TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T
952
switch (lock_get_type(lock)) {
954
ut_a(heap_no != ULINT_UNDEFINED);
956
return(row->lock_trx_id == lock_get_trx_id(lock)
957
&& row->lock_space == lock_rec_get_space_id(lock)
958
&& row->lock_page == lock_rec_get_page_no(lock)
959
&& row->lock_rec == heap_no);
962
/* this check is actually not necessary for continuing
963
correct operation, but something must have gone wrong if
965
ut_a(heap_no == ULINT_UNDEFINED);
967
return(row->lock_trx_id == lock_get_trx_id(lock)
968
&& row->lock_table_id == lock_get_table_id(lock));
977
/*******************************************************************//**
978
Searches for a row in the innodb_locks cache that has a specified id.
979
This happens in O(1) time since a hash table is used. Returns pointer to
980
the row or NULL if none is found.
981
@return row or NULL */
986
trx_i_s_cache_t* cache, /*!< in: cache */
987
const lock_t* lock, /*!< in: lock to search for */
988
ulint heap_no)/*!< in: lock's record number
989
or ULINT_UNDEFINED if the lock
992
i_s_hash_chain_t* hash_chain;
995
/* hash_chain->"next" */
1000
fold_lock(lock, heap_no),
1001
/* the type of the next variable */
1003
/* auxiliary variable */
1005
/* assertion on every traversed item */
1006
ut_ad(i_s_locks_row_validate(hash_chain->value)),
1007
/* this determines if we have found the lock */
1008
locks_row_eq_lock(hash_chain->value, lock, heap_no));
1010
if (hash_chain == NULL) {
1016
return(hash_chain->value);
1019
/*******************************************************************//**
1020
Adds new element to the locks cache, enlarging it if necessary.
1021
Returns a pointer to the added row. If the row is already present then
1022
no row is added and a pointer to the existing row is returned.
1023
If row can not be allocated then NULL is returned.
1029
trx_i_s_cache_t* cache, /*!< in/out: cache */
1030
const lock_t* lock, /*!< in: the element to add */
1031
ulint heap_no)/*!< in: lock's record number
1032
or ULINT_UNDEFINED if the lock
1035
i_s_locks_row_t* dst_row;
1037
#ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
1039
for (i = 0; i < 10000; i++) {
1041
#ifndef TEST_DO_NOT_CHECK_FOR_DUPLICATE_ROWS
1042
/* quit if this lock is already present */
1043
dst_row = search_innodb_locks(cache, lock, heap_no);
1044
if (dst_row != NULL) {
1046
ut_ad(i_s_locks_row_validate(dst_row));
1051
dst_row = (i_s_locks_row_t*)
1052
table_cache_create_empty_row(&cache->innodb_locks, cache);
1054
/* memory could not be allocated */
1055
if (dst_row == NULL) {
1060
if (!fill_locks_row(dst_row, lock, heap_no, cache)) {
1062
/* memory could not be allocated */
1063
cache->innodb_locks.rows_used--;
1067
#ifndef TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE
1069
/* the type used in the hash chain */
1071
/* hash_chain->"next" */
1073
/* the hash table */
1076
fold_lock(lock, heap_no),
1077
/* add this data to the hash */
1078
&dst_row->hash_chain);
1080
#ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
1084
ut_ad(i_s_locks_row_validate(dst_row));
1088
/*******************************************************************//**
1089
Adds new pair of locks to the lock waits cache.
1090
If memory can not be allocated then FALSE is returned.
1091
@return FALSE if allocation fails */
1094
add_lock_wait_to_cache(
1095
/*===================*/
1096
trx_i_s_cache_t* cache, /*!< in/out: cache */
1097
const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the
1098
relevant requested lock
1099
row in innodb_locks */
1100
const i_s_locks_row_t* blocking_lock_row)/*!< in: pointer to the
1101
relevant blocking lock
1102
row in innodb_locks */
1104
i_s_lock_waits_row_t* dst_row;
1106
dst_row = (i_s_lock_waits_row_t*)
1107
table_cache_create_empty_row(&cache->innodb_lock_waits,
1110
/* memory could not be allocated */
1111
if (dst_row == NULL) {
1116
fill_lock_waits_row(dst_row, requested_lock_row, blocking_lock_row);
1121
/*******************************************************************//**
1122
Adds transaction's relevant (important) locks to cache.
1123
If the transaction is waiting, then the wait lock is added to
1124
innodb_locks and a pointer to the added row is returned in
1125
requested_lock_row, otherwise requested_lock_row is set to NULL.
1126
If rows can not be allocated then FALSE is returned and the value of
1127
requested_lock_row is undefined.
1128
@return FALSE if allocation fails */
1131
add_trx_relevant_locks_to_cache(
1132
/*============================*/
1133
trx_i_s_cache_t* cache, /*!< in/out: cache */
1134
const trx_t* trx, /*!< in: transaction */
1135
i_s_locks_row_t** requested_lock_row)/*!< out: pointer to the
1136
requested lock row, or NULL or
1139
ut_ad(mutex_own(&kernel_mutex));
1141
/* If transaction is waiting we add the wait lock and all locks
1142
from another transactions that are blocking the wait lock. */
1143
if (trx->que_state == TRX_QUE_LOCK_WAIT) {
1145
const lock_t* curr_lock;
1146
ulint wait_lock_heap_no;
1147
i_s_locks_row_t* blocking_lock_row;
1148
lock_queue_iterator_t iter;
1150
ut_a(trx->wait_lock != NULL);
1153
= wait_lock_get_heap_no(trx->wait_lock);
1155
/* add the requested lock */
1157
= add_lock_to_cache(cache, trx->wait_lock,
1160
/* memory could not be allocated */
1161
if (*requested_lock_row == NULL) {
1166
/* then iterate over the locks before the wait lock and
1167
add the ones that are blocking it */
1169
lock_queue_iterator_reset(&iter, trx->wait_lock,
1172
curr_lock = lock_queue_iterator_get_prev(&iter);
1173
while (curr_lock != NULL) {
1175
if (lock_has_to_wait(trx->wait_lock,
1178
/* add the lock that is
1179
blocking trx->wait_lock */
1181
= add_lock_to_cache(
1183
/* heap_no is the same
1184
for the wait and waited
1188
/* memory could not be allocated */
1189
if (blocking_lock_row == NULL) {
1194
/* add the relation between both locks
1195
to innodb_lock_waits */
1196
if (!add_lock_wait_to_cache(
1197
cache, *requested_lock_row,
1198
blocking_lock_row)) {
1200
/* memory could not be allocated */
1205
curr_lock = lock_queue_iterator_get_prev(&iter);
1209
*requested_lock_row = NULL;
1215
/** The minimum time that a cache must not be updated after it has been
1216
read for the last time; measured in microseconds. We use this technique
1217
to ensure that SELECTs which join several INFORMATION SCHEMA tables read
1218
the same version of the cache. */
1219
#define CACHE_MIN_IDLE_TIME_US 100000 /* 0.1 sec */
1221
/*******************************************************************//**
1222
Checks if the cache can safely be updated.
1223
@return TRUE if can be updated */
1226
can_cache_be_updated(
1227
/*=================*/
1228
trx_i_s_cache_t* cache) /*!< in: cache */
1232
/* Here we read cache->last_read without acquiring its mutex
1233
because last_read is only updated when a shared rw lock on the
1234
whole cache is being held (see trx_i_s_cache_end_read()) and
1235
we are currently holding an exclusive rw lock on the cache.
1236
So it is not possible for last_read to be updated while we are
1239
#ifdef UNIV_SYNC_DEBUG
1240
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1243
now = ut_time_us(NULL);
1244
if (now - cache->last_read > CACHE_MIN_IDLE_TIME_US) {
1252
/*******************************************************************//**
1253
Declare a cache empty, preparing it to be filled up. Not all resources
1254
are freed because they can be reused. */
1257
trx_i_s_cache_clear(
1258
/*================*/
1259
trx_i_s_cache_t* cache) /*!< out: cache to clear */
1261
cache->innodb_trx.rows_used = 0;
1262
cache->innodb_locks.rows_used = 0;
1263
cache->innodb_lock_waits.rows_used = 0;
1265
hash_table_clear(cache->locks_hash);
1267
ha_storage_empty(&cache->storage);
1270
/*******************************************************************//**
1271
Fetches the data needed to fill the 3 INFORMATION SCHEMA tables into the
1272
table cache buffer. Cache must be locked for write. */
1275
fetch_data_into_cache(
1276
/*==================*/
1277
trx_i_s_cache_t* cache) /*!< in/out: cache */
1280
i_s_trx_row_t* trx_row;
1281
i_s_locks_row_t* requested_lock_row;
1283
ut_ad(mutex_own(&kernel_mutex));
1285
trx_i_s_cache_clear(cache);
1287
/* We iterate over the list of all transactions and add each one
1288
to innodb_trx's cache. We also add all locks that are relevant
1289
to each transaction into innodb_locks' and innodb_lock_waits'
1292
for (trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
1294
trx = UT_LIST_GET_NEXT(trx_list, trx)) {
1296
if (!add_trx_relevant_locks_to_cache(cache, trx,
1297
&requested_lock_row)) {
1299
cache->is_truncated = TRUE;
1303
trx_row = (i_s_trx_row_t*)
1304
table_cache_create_empty_row(&cache->innodb_trx,
1307
/* memory could not be allocated */
1308
if (trx_row == NULL) {
1310
cache->is_truncated = TRUE;
1314
if (!fill_trx_row(trx_row, trx, requested_lock_row, cache)) {
1316
/* memory could not be allocated */
1317
cache->innodb_trx.rows_used--;
1318
cache->is_truncated = TRUE;
1323
cache->is_truncated = FALSE;
1326
/*******************************************************************//**
1327
Update the transactions cache if it has not been read for some time.
1328
Called from handler/i_s.cc.
1329
@return 0 - fetched, 1 - not */
1332
trx_i_s_possibly_fetch_data_into_cache(
1333
/*===================================*/
1334
trx_i_s_cache_t* cache) /*!< in/out: cache */
1336
if (!can_cache_be_updated(cache)) {
1341
/* We need to read trx_sys and record/table lock queues */
1342
mutex_enter(&kernel_mutex);
1344
fetch_data_into_cache(cache);
1346
mutex_exit(&kernel_mutex);
1351
/*******************************************************************//**
1352
Returns TRUE if the data in the cache is truncated due to the memory
1353
limit posed by TRX_I_S_MEM_LIMIT.
1354
@return TRUE if truncated */
1357
trx_i_s_cache_is_truncated(
1358
/*=======================*/
1359
trx_i_s_cache_t* cache) /*!< in: cache */
1361
return(cache->is_truncated);
1364
/*******************************************************************//**
1365
Initialize INFORMATION SCHEMA trx related cache. */
1370
trx_i_s_cache_t* cache) /*!< out: cache to init */
1372
/* The latching is done in the following order:
1373
acquire trx_i_s_cache_t::rw_lock, X
1374
acquire kernel_mutex
1375
release kernel_mutex
1376
release trx_i_s_cache_t::rw_lock
1377
acquire trx_i_s_cache_t::rw_lock, S
1378
acquire trx_i_s_cache_t::last_read_mutex
1379
release trx_i_s_cache_t::last_read_mutex
1380
release trx_i_s_cache_t::rw_lock */
1382
rw_lock_create(trx_i_s_cache_lock_key, &cache->rw_lock,
1383
SYNC_TRX_I_S_RWLOCK);
1385
cache->last_read = 0;
1387
mutex_create(cache_last_read_mutex_key,
1388
&cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ);
1390
table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t));
1391
table_cache_init(&cache->innodb_locks, sizeof(i_s_locks_row_t));
1392
table_cache_init(&cache->innodb_lock_waits,
1393
sizeof(i_s_lock_waits_row_t));
1395
cache->locks_hash = hash_create(LOCKS_HASH_CELLS_NUM);
1397
cache->storage = ha_storage_create(CACHE_STORAGE_INITIAL_SIZE,
1398
CACHE_STORAGE_HASH_CELLS);
1400
cache->mem_allocd = 0;
1402
cache->is_truncated = FALSE;
1405
/*******************************************************************//**
1406
Free the INFORMATION SCHEMA trx related cache. */
1411
trx_i_s_cache_t* cache) /*!< in, own: cache to free */
1413
hash_table_free(cache->locks_hash);
1414
ha_storage_free(cache->storage);
1415
table_cache_free(&cache->innodb_trx);
1416
table_cache_free(&cache->innodb_locks);
1417
table_cache_free(&cache->innodb_lock_waits);
1418
memset(cache, 0, sizeof *cache);
1421
/*******************************************************************//**
1422
Issue a shared/read lock on the tables cache. */
1425
trx_i_s_cache_start_read(
1426
/*=====================*/
1427
trx_i_s_cache_t* cache) /*!< in: cache */
1429
rw_lock_s_lock(&cache->rw_lock);
1432
/*******************************************************************//**
1433
Release a shared/read lock on the tables cache. */
1436
trx_i_s_cache_end_read(
1437
/*===================*/
1438
trx_i_s_cache_t* cache) /*!< in: cache */
1442
#ifdef UNIV_SYNC_DEBUG
1443
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED));
1446
/* update cache last read time */
1447
now = ut_time_us(NULL);
1448
mutex_enter(&cache->last_read_mutex);
1449
cache->last_read = now;
1450
mutex_exit(&cache->last_read_mutex);
1452
rw_lock_s_unlock(&cache->rw_lock);
1455
/*******************************************************************//**
1456
Issue an exclusive/write lock on the tables cache. */
1459
trx_i_s_cache_start_write(
1460
/*======================*/
1461
trx_i_s_cache_t* cache) /*!< in: cache */
1463
rw_lock_x_lock(&cache->rw_lock);
1466
/*******************************************************************//**
1467
Release an exclusive/write lock on the tables cache. */
1470
trx_i_s_cache_end_write(
1471
/*====================*/
1472
trx_i_s_cache_t* cache) /*!< in: cache */
1474
#ifdef UNIV_SYNC_DEBUG
1475
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1478
rw_lock_x_unlock(&cache->rw_lock);
1481
/*******************************************************************//**
1482
Selects a INFORMATION SCHEMA table cache from the whole cache.
1483
@return table cache */
1488
trx_i_s_cache_t* cache, /*!< in: whole cache */
1489
enum i_s_table table) /*!< in: which table */
1491
i_s_table_cache_t* table_cache;
1493
#ifdef UNIV_SYNC_DEBUG
1494
ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED)
1495
|| rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1499
case I_S_INNODB_TRX:
1500
table_cache = &cache->innodb_trx;
1502
case I_S_INNODB_LOCKS:
1503
table_cache = &cache->innodb_locks;
1505
case I_S_INNODB_LOCK_WAITS:
1506
table_cache = &cache->innodb_lock_waits;
1512
return(table_cache);
1515
/*******************************************************************//**
1516
Retrieves the number of used rows in the cache for a given
1517
INFORMATION SCHEMA table.
1518
@return number of rows */
1521
trx_i_s_cache_get_rows_used(
1522
/*========================*/
1523
trx_i_s_cache_t* cache, /*!< in: cache */
1524
enum i_s_table table) /*!< in: which table */
1526
i_s_table_cache_t* table_cache;
1528
table_cache = cache_select_table(cache, table);
1530
return(table_cache->rows_used);
1533
/*******************************************************************//**
1534
Retrieves the nth row (zero-based) in the cache for a given
1535
INFORMATION SCHEMA table.
1539
trx_i_s_cache_get_nth_row(
1540
/*======================*/
1541
trx_i_s_cache_t* cache, /*!< in: cache */
1542
enum i_s_table table, /*!< in: which table */
1543
ulint n) /*!< in: row number */
1545
i_s_table_cache_t* table_cache;
1549
table_cache = cache_select_table(cache, table);
1551
ut_a(n < table_cache->rows_used);
1555
for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
1557
if (table_cache->chunks[i].offset
1558
+ table_cache->chunks[i].rows_allocd > n) {
1560
row = (char*) table_cache->chunks[i].base
1561
+ (n - table_cache->chunks[i].offset)
1562
* table_cache->row_size;
1572
/*******************************************************************//**
1573
Crafts a lock id string from a i_s_locks_row_t object. Returns its
1574
second argument. This function aborts if there is not enough space in
1575
lock_id. Be sure to provide at least TRX_I_S_LOCK_ID_MAX_LEN + 1 if you
1576
want to be 100% sure that it will not abort.
1577
@return resulting lock id */
1580
trx_i_s_create_lock_id(
1581
/*===================*/
1582
const i_s_locks_row_t* row, /*!< in: innodb_locks row */
1583
char* lock_id,/*!< out: resulting lock_id */
1584
ulint lock_id_size)/*!< in: size of the lock id
1589
/* please adjust TRX_I_S_LOCK_ID_MAX_LEN if you change this */
1591
if (row->lock_space != ULINT_UNDEFINED) {
1593
res_len = ut_snprintf(lock_id, lock_id_size,
1594
TRX_ID_FMT ":%lu:%lu:%lu",
1595
row->lock_trx_id, row->lock_space,
1596
row->lock_page, row->lock_rec);
1599
res_len = ut_snprintf(lock_id, lock_id_size,
1600
TRX_ID_FMT ":" TRX_ID_FMT,
1602
row->lock_table_id);
1605
/* the typecast is safe because snprintf(3) never returns
1608
ut_a((ulint) res_len < lock_id_size);