~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/trx/trx0i_s.cc

Merged vcol stuff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 2007, 2010, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
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.
12
 
 
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
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file trx/trx0i_s.c
21
 
INFORMATION SCHEMA innodb_trx, innodb_locks and
22
 
innodb_lock_waits tables fetch code.
23
 
 
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.
27
 
 
28
 
Created July 17, 2007 Vasil Dimov
29
 
*******************************************************/
30
 
 
31
 
#include "config.h"
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.
37
 
*/
38
 
#include "univ.i"
39
 
 
40
 
#if !defined(BUILD_DRIZZLE)
41
 
# include <mysql/plugin.h>
42
 
#endif
43
 
 
44
 
#include "buf0buf.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"
51
 
#include "mem0mem.h"
52
 
#include "page0page.h"
53
 
#include "rem0rec.h"
54
 
#include "row0row.h"
55
 
#include "srv0srv.h"
56
 
#include "sync0rw.h"
57
 
#include "sync0sync.h"
58
 
#include "sync0types.h"
59
 
#include "trx0i_s.h"
60
 
#include "trx0sys.h"
61
 
#include "trx0trx.h"
62
 
#include "ut0mem.h"
63
 
#include "ut0ut.h"
64
 
 
65
 
#include <drizzled/session.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
 
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
142
 
                                of rows */
143
 
        void*   base;           /*!< start of the chunk */
144
 
} i_s_mem_chunk_t;
145
 
 
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
153
 
                                        rows */
154
 
} i_s_table_cache_t;
155
 
 
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
162
 
                                        epoch */
163
 
        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 can possibly not be
181
 
                                        available later, when we release
182
 
                                        the kernel 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
 
UNIV_INTERN trx_i_s_cache_t*    trx_i_s_cache = &trx_i_s_cache_static;
198
 
 
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 */
203
 
 
204
 
#ifdef UNIV_PFS_MUTEX
205
 
UNIV_INTERN mysql_pfs_key_t     cache_last_read_mutex_key;
206
 
#endif /* UNIV_PFS_MUTEX */
207
 
 
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 */
212
 
static
213
 
ulint
214
 
wait_lock_get_heap_no(
215
 
/*==================*/
216
 
        const lock_t*   lock)   /*!< in: lock */
217
 
{
218
 
        ulint   ret;
219
 
 
220
 
        switch (lock_get_type(lock)) {
221
 
        case LOCK_REC:
222
 
                ret = lock_rec_find_set_bit(lock);
223
 
                ut_a(ret != ULINT_UNDEFINED);
224
 
                break;
225
 
        case LOCK_TABLE:
226
 
                ret = ULINT_UNDEFINED;
227
 
                break;
228
 
        default:
229
 
                ut_error;
230
 
        }
231
 
 
232
 
        return(ret);
233
 
}
234
 
 
235
 
/*******************************************************************//**
236
 
Initializes the members of a table cache. */
237
 
static
238
 
void
239
 
table_cache_init(
240
 
/*=============*/
241
 
        i_s_table_cache_t*      table_cache,    /*!< out: table cache */
242
 
        size_t                  row_size)       /*!< in: the size of a
243
 
                                                row */
244
 
{
245
 
        ulint   i;
246
 
 
247
 
        table_cache->rows_used = 0;
248
 
        table_cache->rows_allocd = 0;
249
 
        table_cache->row_size = row_size;
250
 
 
251
 
        for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
252
 
 
253
 
                /* the memory is actually allocated in
254
 
                table_cache_create_empty_row() */
255
 
                table_cache->chunks[i].base = NULL;
256
 
        }
257
 
}
258
 
 
259
 
/*******************************************************************//**
260
 
Frees a table cache. */
261
 
static
262
 
void
263
 
table_cache_free(
264
 
/*=============*/
265
 
        i_s_table_cache_t*      table_cache)    /*!< in/out: table cache */
266
 
{
267
 
        ulint   i;
268
 
 
269
 
        for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
270
 
 
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;
276
 
                }
277
 
        }
278
 
}
279
 
 
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
284
 
allocated.
285
 
@return empty row, or NULL if out of memory */
286
 
static
287
 
void*
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
292
 
                                                how many bytes are
293
 
                                                allocated */
294
 
{
295
 
        ulint   i;
296
 
        void*   row;
297
 
 
298
 
        ut_a(table_cache->rows_used <= table_cache->rows_allocd);
299
 
 
300
 
        if (table_cache->rows_used == table_cache->rows_allocd) {
301
 
 
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); */
306
 
 
307
 
                i_s_mem_chunk_t*        chunk;
308
 
                ulint                   req_bytes;
309
 
                ulint                   got_bytes;
310
 
                ulint                   req_rows;
311
 
                ulint                   got_rows;
312
 
 
313
 
                /* find the first not allocated chunk */
314
 
                for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
315
 
 
316
 
                        if (table_cache->chunks[i].base == NULL) {
317
 
 
318
 
                                break;
319
 
                        }
320
 
                }
321
 
 
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);
325
 
 
326
 
                /* allocate the chunk we just found */
327
 
 
328
 
                if (i == 0) {
329
 
 
330
 
                        /* first chunk, nothing is allocated yet */
331
 
                        req_rows = TABLE_CACHE_INITIAL_ROWSNUM;
332
 
                } else {
333
 
 
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
343
 
                        memory. */
344
 
                        req_rows = table_cache->rows_allocd / 2;
345
 
                }
346
 
                req_bytes = req_rows * table_cache->row_size;
347
 
 
348
 
                if (req_bytes > MAX_ALLOWED_FOR_ALLOC(cache)) {
349
 
 
350
 
                        return(NULL);
351
 
                }
352
 
 
353
 
                chunk = &table_cache->chunks[i];
354
 
 
355
 
                chunk->base = mem_alloc2(req_bytes, &got_bytes);
356
 
 
357
 
                got_rows = got_bytes / table_cache->row_size;
358
 
 
359
 
                cache->mem_allocd += got_bytes;
360
 
 
361
 
#if 0
362
 
                printf("allocating chunk %d req bytes=%lu, got bytes=%lu, "
363
 
                       "row size=%lu, "
364
 
                       "req rows=%lu, got rows=%lu\n",
365
 
                       i, req_bytes, got_bytes,
366
 
                       table_cache->row_size,
367
 
                       req_rows, got_rows);
368
 
#endif
369
 
 
370
 
                chunk->rows_allocd = got_rows;
371
 
 
372
 
                table_cache->rows_allocd += got_rows;
373
 
 
374
 
                /* adjust the offset of the next chunk */
375
 
                if (i < MEM_CHUNKS_IN_TABLE_CACHE - 1) {
376
 
 
377
 
                        table_cache->chunks[i + 1].offset
378
 
                                = chunk->offset + chunk->rows_allocd;
379
 
                }
380
 
 
381
 
                /* return the first empty row in the newly allocated
382
 
                chunk */
383
 
                row = chunk->base;
384
 
        } else {
385
 
 
386
 
                char*   chunk_start;
387
 
                ulint   offset;
388
 
 
389
 
                /* there is an empty row, no need to allocate new
390
 
                chunks */
391
 
 
392
 
                /* find the first chunk that contains allocated but
393
 
                empty/unused rows */
394
 
                for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
395
 
 
396
 
                        if (table_cache->chunks[i].offset
397
 
                            + table_cache->chunks[i].rows_allocd
398
 
                            > table_cache->rows_used) {
399
 
 
400
 
                                break;
401
 
                        }
402
 
                }
403
 
 
404
 
                /* i == MEM_CHUNKS_IN_TABLE_CACHE means that all chunks
405
 
                are full, but
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);
410
 
 
411
 
                chunk_start = (char*) table_cache->chunks[i].base;
412
 
                offset = table_cache->rows_used
413
 
                        - table_cache->chunks[i].offset;
414
 
 
415
 
                row = chunk_start + offset * table_cache->row_size;
416
 
        }
417
 
 
418
 
        table_cache->rows_used++;
419
 
 
420
 
        return(row);
421
 
}
422
 
 
423
 
#ifdef UNIV_DEBUG
424
 
/*******************************************************************//**
425
 
Validates a row in the locks cache.
426
 
@return TRUE if valid */
427
 
static
428
 
ibool
429
 
i_s_locks_row_validate(
430
 
/*===================*/
431
 
        const i_s_locks_row_t*  row)    /*!< in: row to validate */
432
 
{
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);
438
 
 
439
 
        if (row->lock_space == ULINT_UNDEFINED) {
440
 
                /* table lock */
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);
446
 
        } else {
447
 
                /* record lock */
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);
453
 
        }
454
 
 
455
 
        return(TRUE);
456
 
}
457
 
#endif /* UNIV_DEBUG */
458
 
 
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 */
463
 
static
464
 
ibool
465
 
fill_trx_row(
466
 
/*=========*/
467
 
        i_s_trx_row_t*          row,            /*!< out: result object
468
 
                                                that's filled */
469
 
        const trx_t*            trx,            /*!< in: transaction to
470
 
                                                get data from */
471
 
        const i_s_locks_row_t*  requested_lock_row,/*!< in: pointer to the
472
 
                                                corresponding row in
473
 
                                                innodb_locks if trx is
474
 
                                                waiting or NULL if trx
475
 
                                                is not waiting */
476
 
        trx_i_s_cache_t*        cache)          /*!< in/out: cache into
477
 
                                                which to copy volatile
478
 
                                                strings */
479
 
{
480
 
        const char*     stmt;
481
 
        size_t          stmt_len;
482
 
        const char*     s;
483
 
 
484
 
        ut_ad(mutex_own(&kernel_mutex));
485
 
 
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));
492
 
 
493
 
        if (trx->wait_lock != NULL) {
494
 
                ut_a(requested_lock_row != NULL);
495
 
                row->trx_wait_started = (ib_time_t) trx->wait_started;
496
 
        } else {
497
 
                ut_a(requested_lock_row == NULL);
498
 
                row->trx_wait_started = 0;
499
 
        }
500
 
 
501
 
        row->trx_weight = (ullint) TRX_WEIGHT(trx);
502
 
 
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;
509
 
                goto thd_done;
510
 
        }
511
 
 
512
 
        row->trx_mysql_thread_id = trx->session()->getSessionId();
513
 
        stmt= trx->mysql_thd->getQueryStringCopy(stmt_len);
514
 
 
515
 
        if (stmt != NULL) {
516
 
 
517
 
                char    query[TRX_I_S_TRX_QUERY_MAX_LEN + 1];
518
 
 
519
 
                if (stmt_len > TRX_I_S_TRX_QUERY_MAX_LEN) {
520
 
                        stmt_len = TRX_I_S_TRX_QUERY_MAX_LEN;
521
 
                }
522
 
 
523
 
                memcpy(query, stmt, stmt_len);
524
 
                query[stmt_len] = '\0';
525
 
 
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)));
529
 
 
530
 
                if (row->trx_query == NULL) {
531
 
 
532
 
                        return(FALSE);
533
 
                }
534
 
        } else {
535
 
 
536
 
                row->trx_query = NULL;
537
 
        }
538
 
 
539
 
thd_done:
540
 
        s = trx->op_info;
541
 
 
542
 
        if (s != NULL && s[0] != '\0') {
543
 
 
544
 
                TRX_I_S_STRING_COPY(s, row->trx_operation_state,
545
 
                                    TRX_I_S_TRX_OP_STATE_MAX_LEN, cache);
546
 
 
547
 
                if (row->trx_operation_state == NULL) {
548
 
 
549
 
                        return(FALSE);
550
 
                }
551
 
        } else {
552
 
 
553
 
                row->trx_operation_state = NULL;
554
 
        }
555
 
 
556
 
//      row->trx_tables_in_use = trx->n_mysql_tables_in_use;
557
 
 
558
 
        row->trx_tables_locked = trx->mysql_n_tables_locked;
559
 
 
560
 
        row->trx_lock_structs = UT_LIST_GET_LEN(trx->trx_locks);
561
 
 
562
 
        row->trx_lock_memory_bytes = mem_heap_get_size(trx->lock_heap);
563
 
 
564
 
        row->trx_rows_locked = lock_number_of_rows_locked(trx);
565
 
 
566
 
        row->trx_rows_modified = trx->undo_no;
567
 
 
568
 
        row->trx_concurrency_tickets = trx->n_tickets_to_enter_innodb;
569
 
 
570
 
        switch (trx->isolation_level) {
571
 
        case TRX_ISO_READ_UNCOMMITTED:
572
 
                row->trx_isolation_level = "READ UNCOMMITTED";
573
 
                break;
574
 
        case TRX_ISO_READ_COMMITTED:
575
 
                row->trx_isolation_level = "READ COMMITTED";
576
 
                break;
577
 
        case TRX_ISO_REPEATABLE_READ:
578
 
                row->trx_isolation_level = "REPEATABLE READ";
579
 
                break;
580
 
        case TRX_ISO_SERIALIZABLE:
581
 
                row->trx_isolation_level = "SERIALIZABLE";
582
 
                break;
583
 
        /* Should not happen as TRX_ISO_READ_COMMITTED is default */
584
 
        default:
585
 
                row->trx_isolation_level = "UNKNOWN";
586
 
        }
587
 
 
588
 
        row->trx_unique_checks = (ibool) trx->check_unique_secondary;
589
 
 
590
 
        row->trx_foreign_key_checks = (ibool) trx->check_foreigns;
591
 
 
592
 
        s = trx->detailed_error;
593
 
 
594
 
        if (s != NULL && s[0] != '\0') {
595
 
 
596
 
                TRX_I_S_STRING_COPY(s,
597
 
                                    row->trx_foreign_key_error,
598
 
                                    TRX_I_S_TRX_FK_ERROR_MAX_LEN, cache);
599
 
 
600
 
                if (row->trx_foreign_key_error == NULL) {
601
 
 
602
 
                        return(FALSE);
603
 
                }
604
 
        } else {
605
 
                row->trx_foreign_key_error = NULL;
606
 
        }
607
 
 
608
 
        row->trx_has_search_latch = (ibool) trx->has_search_latch;
609
 
 
610
 
        row->trx_search_latch_timeout = trx->search_latch_timeout;
611
 
 
612
 
        return(TRUE);
613
 
}
614
 
 
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 */
620
 
static
621
 
ulint
622
 
put_nth_field(
623
 
/*==========*/
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() */
631
 
{
632
 
        const byte*     data;
633
 
        ulint           data_len;
634
 
        dict_field_t*   dict_field;
635
 
        ulint           ret;
636
 
 
637
 
        ut_ad(rec_offs_validate(rec, NULL, offsets));
638
 
 
639
 
        if (buf_size == 0) {
640
 
 
641
 
                return(0);
642
 
        }
643
 
 
644
 
        ret = 0;
645
 
 
646
 
        if (n > 0) {
647
 
                /* we must append ", " before the actual data */
648
 
 
649
 
                if (buf_size < 3) {
650
 
 
651
 
                        buf[0] = '\0';
652
 
                        return(1);
653
 
                }
654
 
 
655
 
                memcpy(buf, ", ", 3);
656
 
 
657
 
                buf += 2;
658
 
                buf_size -= 2;
659
 
                ret += 2;
660
 
        }
661
 
 
662
 
        /* now buf_size >= 1 */
663
 
 
664
 
        data = rec_get_nth_field(rec, offsets, n, &data_len);
665
 
 
666
 
        dict_field = dict_index_get_nth_field(index, n);
667
 
 
668
 
        ret += row_raw_format((const char*) data, data_len,
669
 
                              dict_field, buf, buf_size);
670
 
 
671
 
        return(ret);
672
 
}
673
 
 
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 */
678
 
static
679
 
ibool
680
 
fill_lock_data(
681
 
/*===========*/
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
686
 
                                        volatile data */
687
 
{
688
 
        mtr_t                   mtr;
689
 
 
690
 
        const buf_block_t*      block;
691
 
        const page_t*           page;
692
 
        const rec_t*            rec;
693
 
 
694
 
        ut_a(lock_get_type(lock) == LOCK_REC);
695
 
 
696
 
        mtr_start(&mtr);
697
 
 
698
 
        block = buf_page_try_get(lock_rec_get_space_id(lock),
699
 
                                 lock_rec_get_page_no(lock),
700
 
                                 &mtr);
701
 
 
702
 
        if (block == NULL) {
703
 
 
704
 
                *lock_data = NULL;
705
 
 
706
 
                mtr_commit(&mtr);
707
 
 
708
 
                return(TRUE);
709
 
        }
710
 
 
711
 
        page = (const page_t*) buf_block_get_frame(block);
712
 
 
713
 
        rec = page_find_rec_with_heap_no(page, heap_no);
714
 
 
715
 
        if (page_rec_is_infimum(rec)) {
716
 
 
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)) {
721
 
 
722
 
                *lock_data = ha_storage_put_str_memlim(
723
 
                        cache->storage, "supremum pseudo-record",
724
 
                        MAX_ALLOWED_FOR_STORAGE(cache));
725
 
        } else {
726
 
 
727
 
                const dict_index_t*     index;
728
 
                ulint                   n_fields;
729
 
                mem_heap_t*             heap;
730
 
                ulint                   offsets_onstack[REC_OFFS_NORMAL_SIZE];
731
 
                ulint*                  offsets;
732
 
                char                    buf[TRX_I_S_LOCK_DATA_MAX_LEN];
733
 
                ulint                   buf_used;
734
 
                ulint                   i;
735
 
 
736
 
                rec_offs_init(offsets_onstack);
737
 
                offsets = offsets_onstack;
738
 
 
739
 
                index = lock_rec_get_index(lock);
740
 
 
741
 
                n_fields = dict_index_get_n_unique(index);
742
 
 
743
 
                ut_a(n_fields > 0);
744
 
 
745
 
                heap = NULL;
746
 
                offsets = rec_get_offsets(rec, index, offsets, n_fields,
747
 
                                          &heap);
748
 
 
749
 
                /* format and store the data */
750
 
 
751
 
                buf_used = 0;
752
 
                for (i = 0; i < n_fields; i++) {
753
 
 
754
 
                        buf_used += put_nth_field(
755
 
                                buf + buf_used, sizeof(buf) - buf_used,
756
 
                                i, index, rec, offsets) - 1;
757
 
                }
758
 
 
759
 
                *lock_data = (const char*) ha_storage_put_memlim(
760
 
                        cache->storage, buf, buf_used + 1,
761
 
                        MAX_ALLOWED_FOR_STORAGE(cache));
762
 
 
763
 
                if (UNIV_UNLIKELY(heap != NULL)) {
764
 
 
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);
769
 
                        mem_heap_free(heap);
770
 
                }
771
 
        }
772
 
 
773
 
        mtr_commit(&mtr);
774
 
 
775
 
        if (*lock_data == NULL) {
776
 
 
777
 
                return(FALSE);
778
 
        }
779
 
 
780
 
        return(TRUE);
781
 
}
782
 
 
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 */
787
 
static
788
 
ibool
789
 
fill_locks_row(
790
 
/*===========*/
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
795
 
                                is a table lock */
796
 
        trx_i_s_cache_t* cache) /*!< in/out: cache into which to copy
797
 
                                volatile strings */
798
 
{
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);
802
 
 
803
 
        row->lock_table = ha_storage_put_str_memlim(
804
 
                cache->storage, lock_get_table_name(lock),
805
 
                MAX_ALLOWED_FOR_STORAGE(cache));
806
 
 
807
 
        /* memory could not be allocated */
808
 
        if (row->lock_table == NULL) {
809
 
 
810
 
                return(FALSE);
811
 
        }
812
 
 
813
 
        switch (lock_get_type(lock)) {
814
 
        case LOCK_REC:
815
 
                row->lock_index = ha_storage_put_str_memlim(
816
 
                        cache->storage, lock_rec_get_index_name(lock),
817
 
                        MAX_ALLOWED_FOR_STORAGE(cache));
818
 
 
819
 
                /* memory could not be allocated */
820
 
                if (row->lock_index == NULL) {
821
 
 
822
 
                        return(FALSE);
823
 
                }
824
 
 
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;
828
 
 
829
 
                if (!fill_lock_data(&row->lock_data, lock, heap_no, cache)) {
830
 
 
831
 
                        /* memory could not be allocated */
832
 
                        return(FALSE);
833
 
                }
834
 
 
835
 
                break;
836
 
        case LOCK_TABLE:
837
 
                row->lock_index = NULL;
838
 
 
839
 
                row->lock_space = ULINT_UNDEFINED;
840
 
                row->lock_page = ULINT_UNDEFINED;
841
 
                row->lock_rec = ULINT_UNDEFINED;
842
 
 
843
 
                row->lock_data = NULL;
844
 
 
845
 
                break;
846
 
        default:
847
 
                ut_error;
848
 
        }
849
 
 
850
 
        row->lock_table_id = lock_get_table_id(lock);
851
 
 
852
 
        row->hash_chain.value = row;
853
 
        ut_ad(i_s_locks_row_validate(row));
854
 
 
855
 
        return(TRUE);
856
 
}
857
 
 
858
 
/*******************************************************************//**
859
 
Fills i_s_lock_waits_row_t object. Returns its first argument.
860
 
@return result object that's filled */
861
 
static
862
 
i_s_lock_waits_row_t*
863
 
fill_lock_waits_row(
864
 
/*================*/
865
 
        i_s_lock_waits_row_t*   row,            /*!< out: result object
866
 
                                                that's filled */
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 */
873
 
{
874
 
        ut_ad(i_s_locks_row_validate(requested_lock_row));
875
 
        ut_ad(i_s_locks_row_validate(blocking_lock_row));
876
 
 
877
 
        row->requested_lock_row = requested_lock_row;
878
 
        row->blocking_lock_row = blocking_lock_row;
879
 
 
880
 
        return(row);
881
 
}
882
 
 
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.
888
 
@return fold */
889
 
static
890
 
ulint
891
 
fold_lock(
892
 
/*======*/
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
896
 
                                is a table lock */
897
 
{
898
 
#ifdef TEST_LOCK_FOLD_ALWAYS_DIFFERENT
899
 
        static ulint    fold = 0;
900
 
 
901
 
        return(fold++);
902
 
#else
903
 
        ulint   ret;
904
 
 
905
 
        switch (lock_get_type(lock)) {
906
 
        case LOCK_REC:
907
 
                ut_a(heap_no != ULINT_UNDEFINED);
908
 
 
909
 
                ret = ut_fold_ulint_pair((ulint) lock_get_trx_id(lock),
910
 
                                         lock_rec_get_space_id(lock));
911
 
 
912
 
                ret = ut_fold_ulint_pair(ret,
913
 
                                         lock_rec_get_page_no(lock));
914
 
 
915
 
                ret = ut_fold_ulint_pair(ret, heap_no);
916
 
 
917
 
                break;
918
 
        case LOCK_TABLE:
919
 
                /* this check is actually not necessary for continuing
920
 
                correct operation, but something must have gone wrong if
921
 
                it fails. */
922
 
                ut_a(heap_no == ULINT_UNDEFINED);
923
 
 
924
 
                ret = (ulint) lock_get_table_id(lock);
925
 
 
926
 
                break;
927
 
        default:
928
 
                ut_error;
929
 
        }
930
 
 
931
 
        return(ret);
932
 
#endif
933
 
}
934
 
 
935
 
/*******************************************************************//**
936
 
Checks whether i_s_locks_row_t object represents a lock_t object.
937
 
@return TRUE if they match */
938
 
static
939
 
ibool
940
 
locks_row_eq_lock(
941
 
/*==============*/
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
946
 
                                        is a table lock */
947
 
{
948
 
        ut_ad(i_s_locks_row_validate(row));
949
 
#ifdef TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T
950
 
        return(0);
951
 
#else
952
 
        switch (lock_get_type(lock)) {
953
 
        case LOCK_REC:
954
 
                ut_a(heap_no != ULINT_UNDEFINED);
955
 
 
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);
960
 
 
961
 
        case LOCK_TABLE:
962
 
                /* this check is actually not necessary for continuing
963
 
                correct operation, but something must have gone wrong if
964
 
                it fails. */
965
 
                ut_a(heap_no == ULINT_UNDEFINED);
966
 
 
967
 
                return(row->lock_trx_id == lock_get_trx_id(lock)
968
 
                       && row->lock_table_id == lock_get_table_id(lock));
969
 
 
970
 
        default:
971
 
                ut_error;
972
 
                return(FALSE);
973
 
        }
974
 
#endif
975
 
}
976
 
 
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 */
982
 
static
983
 
i_s_locks_row_t*
984
 
search_innodb_locks(
985
 
/*================*/
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
990
 
                                        is a table lock */
991
 
{
992
 
        i_s_hash_chain_t*       hash_chain;
993
 
 
994
 
        HASH_SEARCH(
995
 
                /* hash_chain->"next" */
996
 
                next,
997
 
                /* the hash table */
998
 
                cache->locks_hash,
999
 
                /* fold */
1000
 
                fold_lock(lock, heap_no),
1001
 
                /* the type of the next variable */
1002
 
                i_s_hash_chain_t*,
1003
 
                /* auxiliary variable */
1004
 
                hash_chain,
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));
1009
 
 
1010
 
        if (hash_chain == NULL) {
1011
 
 
1012
 
                return(NULL);
1013
 
        }
1014
 
        /* else */
1015
 
 
1016
 
        return(hash_chain->value);
1017
 
}
1018
 
 
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.
1024
 
@return row */
1025
 
static
1026
 
i_s_locks_row_t*
1027
 
add_lock_to_cache(
1028
 
/*==============*/
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
1033
 
                                        is a table lock */
1034
 
{
1035
 
        i_s_locks_row_t*        dst_row;
1036
 
 
1037
 
#ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
1038
 
        ulint   i;
1039
 
        for (i = 0; i < 10000; i++) {
1040
 
#endif
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) {
1045
 
 
1046
 
                ut_ad(i_s_locks_row_validate(dst_row));
1047
 
                return(dst_row);
1048
 
        }
1049
 
#endif
1050
 
 
1051
 
        dst_row = (i_s_locks_row_t*)
1052
 
                table_cache_create_empty_row(&cache->innodb_locks, cache);
1053
 
 
1054
 
        /* memory could not be allocated */
1055
 
        if (dst_row == NULL) {
1056
 
 
1057
 
                return(NULL);
1058
 
        }
1059
 
 
1060
 
        if (!fill_locks_row(dst_row, lock, heap_no, cache)) {
1061
 
 
1062
 
                /* memory could not be allocated */
1063
 
                cache->innodb_locks.rows_used--;
1064
 
                return(NULL);
1065
 
        }
1066
 
 
1067
 
#ifndef TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE
1068
 
        HASH_INSERT(
1069
 
                /* the type used in the hash chain */
1070
 
                i_s_hash_chain_t,
1071
 
                /* hash_chain->"next" */
1072
 
                next,
1073
 
                /* the hash table */
1074
 
                cache->locks_hash,
1075
 
                /* fold */
1076
 
                fold_lock(lock, heap_no),
1077
 
                /* add this data to the hash */
1078
 
                &dst_row->hash_chain);
1079
 
#endif
1080
 
#ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES
1081
 
        } /* for()-loop */
1082
 
#endif
1083
 
 
1084
 
        ut_ad(i_s_locks_row_validate(dst_row));
1085
 
        return(dst_row);
1086
 
}
1087
 
 
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 */
1092
 
static
1093
 
ibool
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 */
1103
 
{
1104
 
        i_s_lock_waits_row_t*   dst_row;
1105
 
 
1106
 
        dst_row = (i_s_lock_waits_row_t*)
1107
 
                table_cache_create_empty_row(&cache->innodb_lock_waits,
1108
 
                                             cache);
1109
 
 
1110
 
        /* memory could not be allocated */
1111
 
        if (dst_row == NULL) {
1112
 
 
1113
 
                return(FALSE);
1114
 
        }
1115
 
 
1116
 
        fill_lock_waits_row(dst_row, requested_lock_row, blocking_lock_row);
1117
 
 
1118
 
        return(TRUE);
1119
 
}
1120
 
 
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 */
1129
 
static
1130
 
ibool
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
1137
 
                                        undefined */
1138
 
{
1139
 
        ut_ad(mutex_own(&kernel_mutex));
1140
 
 
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) {
1144
 
 
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;
1149
 
 
1150
 
                ut_a(trx->wait_lock != NULL);
1151
 
 
1152
 
                wait_lock_heap_no
1153
 
                        = wait_lock_get_heap_no(trx->wait_lock);
1154
 
 
1155
 
                /* add the requested lock */
1156
 
                *requested_lock_row
1157
 
                        = add_lock_to_cache(cache, trx->wait_lock,
1158
 
                                            wait_lock_heap_no);
1159
 
 
1160
 
                /* memory could not be allocated */
1161
 
                if (*requested_lock_row == NULL) {
1162
 
 
1163
 
                        return(FALSE);
1164
 
                }
1165
 
 
1166
 
                /* then iterate over the locks before the wait lock and
1167
 
                add the ones that are blocking it */
1168
 
 
1169
 
                lock_queue_iterator_reset(&iter, trx->wait_lock,
1170
 
                                          ULINT_UNDEFINED);
1171
 
 
1172
 
                curr_lock = lock_queue_iterator_get_prev(&iter);
1173
 
                while (curr_lock != NULL) {
1174
 
 
1175
 
                        if (lock_has_to_wait(trx->wait_lock,
1176
 
                                             curr_lock)) {
1177
 
 
1178
 
                                /* add the lock that is
1179
 
                                blocking trx->wait_lock */
1180
 
                                blocking_lock_row
1181
 
                                        = add_lock_to_cache(
1182
 
                                                cache, curr_lock,
1183
 
                                                /* heap_no is the same
1184
 
                                                for the wait and waited
1185
 
                                                locks */
1186
 
                                                wait_lock_heap_no);
1187
 
 
1188
 
                                /* memory could not be allocated */
1189
 
                                if (blocking_lock_row == NULL) {
1190
 
 
1191
 
                                        return(FALSE);
1192
 
                                }
1193
 
 
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)) {
1199
 
 
1200
 
                                        /* memory could not be allocated */
1201
 
                                        return(FALSE);
1202
 
                                }
1203
 
                        }
1204
 
 
1205
 
                        curr_lock = lock_queue_iterator_get_prev(&iter);
1206
 
                }
1207
 
        } else {
1208
 
 
1209
 
                *requested_lock_row = NULL;
1210
 
        }
1211
 
 
1212
 
        return(TRUE);
1213
 
}
1214
 
 
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 */
1220
 
 
1221
 
/*******************************************************************//**
1222
 
Checks if the cache can safely be updated.
1223
 
@return TRUE if can be updated */
1224
 
static
1225
 
ibool
1226
 
can_cache_be_updated(
1227
 
/*=================*/
1228
 
        trx_i_s_cache_t*        cache)  /*!< in: cache */
1229
 
{
1230
 
        ullint  now;
1231
 
 
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
1237
 
        reading it. */
1238
 
 
1239
 
#ifdef UNIV_SYNC_DEBUG
1240
 
        ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1241
 
#endif
1242
 
 
1243
 
        now = ut_time_us(NULL);
1244
 
        if (now - cache->last_read > CACHE_MIN_IDLE_TIME_US) {
1245
 
 
1246
 
                return(TRUE);
1247
 
        }
1248
 
 
1249
 
        return(FALSE);
1250
 
}
1251
 
 
1252
 
/*******************************************************************//**
1253
 
Declare a cache empty, preparing it to be filled up. Not all resources
1254
 
are freed because they can be reused. */
1255
 
static
1256
 
void
1257
 
trx_i_s_cache_clear(
1258
 
/*================*/
1259
 
        trx_i_s_cache_t*        cache)  /*!< out: cache to clear */
1260
 
{
1261
 
        cache->innodb_trx.rows_used = 0;
1262
 
        cache->innodb_locks.rows_used = 0;
1263
 
        cache->innodb_lock_waits.rows_used = 0;
1264
 
 
1265
 
        hash_table_clear(cache->locks_hash);
1266
 
 
1267
 
        ha_storage_empty(&cache->storage);
1268
 
}
1269
 
 
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. */
1273
 
static
1274
 
void
1275
 
fetch_data_into_cache(
1276
 
/*==================*/
1277
 
        trx_i_s_cache_t*        cache)  /*!< in/out: cache */
1278
 
{
1279
 
        trx_t*                  trx;
1280
 
        i_s_trx_row_t*          trx_row;
1281
 
        i_s_locks_row_t*        requested_lock_row;
1282
 
 
1283
 
        ut_ad(mutex_own(&kernel_mutex));
1284
 
 
1285
 
        trx_i_s_cache_clear(cache);
1286
 
 
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'
1290
 
        caches. */
1291
 
 
1292
 
        for (trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
1293
 
             trx != NULL;
1294
 
             trx = UT_LIST_GET_NEXT(trx_list, trx)) {
1295
 
 
1296
 
                if (!add_trx_relevant_locks_to_cache(cache, trx,
1297
 
                                                     &requested_lock_row)) {
1298
 
 
1299
 
                        cache->is_truncated = TRUE;
1300
 
                        return;
1301
 
                }
1302
 
 
1303
 
                trx_row = (i_s_trx_row_t*)
1304
 
                        table_cache_create_empty_row(&cache->innodb_trx,
1305
 
                                                     cache);
1306
 
 
1307
 
                /* memory could not be allocated */
1308
 
                if (trx_row == NULL) {
1309
 
 
1310
 
                        cache->is_truncated = TRUE;
1311
 
                        return;
1312
 
                }
1313
 
 
1314
 
                if (!fill_trx_row(trx_row, trx, requested_lock_row, cache)) {
1315
 
 
1316
 
                        /* memory could not be allocated */
1317
 
                        cache->innodb_trx.rows_used--;
1318
 
                        cache->is_truncated = TRUE;
1319
 
                        return;
1320
 
                }
1321
 
        }
1322
 
 
1323
 
        cache->is_truncated = FALSE;
1324
 
}
1325
 
 
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 */
1330
 
UNIV_INTERN
1331
 
int
1332
 
trx_i_s_possibly_fetch_data_into_cache(
1333
 
/*===================================*/
1334
 
        trx_i_s_cache_t*        cache)  /*!< in/out: cache */
1335
 
{
1336
 
        if (!can_cache_be_updated(cache)) {
1337
 
 
1338
 
                return(1);
1339
 
        }
1340
 
 
1341
 
        /* We need to read trx_sys and record/table lock queues */
1342
 
        mutex_enter(&kernel_mutex);
1343
 
 
1344
 
        fetch_data_into_cache(cache);
1345
 
 
1346
 
        mutex_exit(&kernel_mutex);
1347
 
 
1348
 
        return(0);
1349
 
}
1350
 
 
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 */
1355
 
UNIV_INTERN
1356
 
ibool
1357
 
trx_i_s_cache_is_truncated(
1358
 
/*=======================*/
1359
 
        trx_i_s_cache_t*        cache)  /*!< in: cache */
1360
 
{
1361
 
        return(cache->is_truncated);
1362
 
}
1363
 
 
1364
 
/*******************************************************************//**
1365
 
Initialize INFORMATION SCHEMA trx related cache. */
1366
 
UNIV_INTERN
1367
 
void
1368
 
trx_i_s_cache_init(
1369
 
/*===============*/
1370
 
        trx_i_s_cache_t*        cache)  /*!< out: cache to init */
1371
 
{
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 */
1381
 
 
1382
 
        rw_lock_create(trx_i_s_cache_lock_key, &cache->rw_lock,
1383
 
                       SYNC_TRX_I_S_RWLOCK);
1384
 
 
1385
 
        cache->last_read = 0;
1386
 
 
1387
 
        mutex_create(cache_last_read_mutex_key,
1388
 
                     &cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ);
1389
 
 
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));
1394
 
 
1395
 
        cache->locks_hash = hash_create(LOCKS_HASH_CELLS_NUM);
1396
 
 
1397
 
        cache->storage = ha_storage_create(CACHE_STORAGE_INITIAL_SIZE,
1398
 
                                           CACHE_STORAGE_HASH_CELLS);
1399
 
 
1400
 
        cache->mem_allocd = 0;
1401
 
 
1402
 
        cache->is_truncated = FALSE;
1403
 
}
1404
 
 
1405
 
/*******************************************************************//**
1406
 
Free the INFORMATION SCHEMA trx related cache. */
1407
 
UNIV_INTERN
1408
 
void
1409
 
trx_i_s_cache_free(
1410
 
/*===============*/
1411
 
        trx_i_s_cache_t*        cache)  /*!< in, own: cache to free */
1412
 
{
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);
1419
 
}
1420
 
 
1421
 
/*******************************************************************//**
1422
 
Issue a shared/read lock on the tables cache. */
1423
 
UNIV_INTERN
1424
 
void
1425
 
trx_i_s_cache_start_read(
1426
 
/*=====================*/
1427
 
        trx_i_s_cache_t*        cache)  /*!< in: cache */
1428
 
{
1429
 
        rw_lock_s_lock(&cache->rw_lock);
1430
 
}
1431
 
 
1432
 
/*******************************************************************//**
1433
 
Release a shared/read lock on the tables cache. */
1434
 
UNIV_INTERN
1435
 
void
1436
 
trx_i_s_cache_end_read(
1437
 
/*===================*/
1438
 
        trx_i_s_cache_t*        cache)  /*!< in: cache */
1439
 
{
1440
 
        ullint  now;
1441
 
 
1442
 
#ifdef UNIV_SYNC_DEBUG
1443
 
        ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_SHARED));
1444
 
#endif
1445
 
 
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);
1451
 
 
1452
 
        rw_lock_s_unlock(&cache->rw_lock);
1453
 
}
1454
 
 
1455
 
/*******************************************************************//**
1456
 
Issue an exclusive/write lock on the tables cache. */
1457
 
UNIV_INTERN
1458
 
void
1459
 
trx_i_s_cache_start_write(
1460
 
/*======================*/
1461
 
        trx_i_s_cache_t*        cache)  /*!< in: cache */
1462
 
{
1463
 
        rw_lock_x_lock(&cache->rw_lock);
1464
 
}
1465
 
 
1466
 
/*******************************************************************//**
1467
 
Release an exclusive/write lock on the tables cache. */
1468
 
UNIV_INTERN
1469
 
void
1470
 
trx_i_s_cache_end_write(
1471
 
/*====================*/
1472
 
        trx_i_s_cache_t*        cache)  /*!< in: cache */
1473
 
{
1474
 
#ifdef UNIV_SYNC_DEBUG
1475
 
        ut_a(rw_lock_own(&cache->rw_lock, RW_LOCK_EX));
1476
 
#endif
1477
 
 
1478
 
        rw_lock_x_unlock(&cache->rw_lock);
1479
 
}
1480
 
 
1481
 
/*******************************************************************//**
1482
 
Selects a INFORMATION SCHEMA table cache from the whole cache.
1483
 
@return table cache */
1484
 
static
1485
 
i_s_table_cache_t*
1486
 
cache_select_table(
1487
 
/*===============*/
1488
 
        trx_i_s_cache_t*        cache,  /*!< in: whole cache */
1489
 
        enum i_s_table          table)  /*!< in: which table */
1490
 
{
1491
 
        i_s_table_cache_t*      table_cache;
1492
 
 
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));
1496
 
#endif
1497
 
 
1498
 
        switch (table) {
1499
 
        case I_S_INNODB_TRX:
1500
 
                table_cache = &cache->innodb_trx;
1501
 
                break;
1502
 
        case I_S_INNODB_LOCKS:
1503
 
                table_cache = &cache->innodb_locks;
1504
 
                break;
1505
 
        case I_S_INNODB_LOCK_WAITS:
1506
 
                table_cache = &cache->innodb_lock_waits;
1507
 
                break;
1508
 
        default:
1509
 
                ut_error;
1510
 
        }
1511
 
 
1512
 
        return(table_cache);
1513
 
}
1514
 
 
1515
 
/*******************************************************************//**
1516
 
Retrieves the number of used rows in the cache for a given
1517
 
INFORMATION SCHEMA table.
1518
 
@return number of rows */
1519
 
UNIV_INTERN
1520
 
ulint
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 */
1525
 
{
1526
 
        i_s_table_cache_t*      table_cache;
1527
 
 
1528
 
        table_cache = cache_select_table(cache, table);
1529
 
 
1530
 
        return(table_cache->rows_used);
1531
 
}
1532
 
 
1533
 
/*******************************************************************//**
1534
 
Retrieves the nth row (zero-based) in the cache for a given
1535
 
INFORMATION SCHEMA table.
1536
 
@return row */
1537
 
UNIV_INTERN
1538
 
void*
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 */
1544
 
{
1545
 
        i_s_table_cache_t*      table_cache;
1546
 
        ulint                   i;
1547
 
        void*                   row;
1548
 
 
1549
 
        table_cache = cache_select_table(cache, table);
1550
 
 
1551
 
        ut_a(n < table_cache->rows_used);
1552
 
 
1553
 
        row = NULL;
1554
 
 
1555
 
        for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
1556
 
 
1557
 
                if (table_cache->chunks[i].offset
1558
 
                    + table_cache->chunks[i].rows_allocd > n) {
1559
 
 
1560
 
                        row = (char*) table_cache->chunks[i].base
1561
 
                                + (n - table_cache->chunks[i].offset)
1562
 
                                * table_cache->row_size;
1563
 
                        break;
1564
 
                }
1565
 
        }
1566
 
 
1567
 
        ut_a(row != NULL);
1568
 
 
1569
 
        return(row);
1570
 
}
1571
 
 
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 */
1578
 
UNIV_INTERN
1579
 
char*
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
1585
 
                                        buffer */
1586
 
{
1587
 
        int     res_len;
1588
 
 
1589
 
        /* please adjust TRX_I_S_LOCK_ID_MAX_LEN if you change this */
1590
 
 
1591
 
        if (row->lock_space != ULINT_UNDEFINED) {
1592
 
                /* record lock */
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);
1597
 
        } else {
1598
 
                /* table lock */
1599
 
                res_len = ut_snprintf(lock_id, lock_id_size,
1600
 
                                      TRX_ID_FMT ":" TRX_ID_FMT,
1601
 
                                      row->lock_trx_id,
1602
 
                                      row->lock_table_id);
1603
 
        }
1604
 
 
1605
 
        /* the typecast is safe because snprintf(3) never returns
1606
 
        negative result */
1607
 
        ut_a(res_len >= 0);
1608
 
        ut_a((ulint) res_len < lock_id_size);
1609
 
 
1610
 
        return(lock_id);
1611
 
}