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