~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/trx/trx0sys.c

  • Committer: Brian Aker
  • Date: 2009-05-21 19:15:01 UTC
  • mfrom: (991.1.12 for-brian)
  • Revision ID: brian@gaz-20090521191501-u5qe56byfubioj1r
Merge Stewart

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1996, 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/trx0sys.c
21
 
Transaction system
22
 
 
23
 
Created 3/26/1996 Heikki Tuuri
24
 
*******************************************************/
25
 
 
26
 
#include "trx0sys.h"
27
 
 
28
 
#ifdef UNIV_NONINL
29
 
#include "trx0sys.ic"
30
 
#endif
31
 
 
32
 
#ifndef UNIV_HOTBACKUP
33
 
#include "fsp0fsp.h"
34
 
#include "mtr0log.h"
35
 
#include "mtr0log.h"
36
 
#include "trx0trx.h"
37
 
#include "trx0rseg.h"
38
 
#include "trx0undo.h"
39
 
#include "srv0srv.h"
40
 
#include "trx0purge.h"
41
 
#include "log0log.h"
42
 
#include "log0recv.h"
43
 
#include "os0file.h"
44
 
#include "read0read.h"
45
 
 
46
 
/** The file format tag structure with id and name. */
47
 
struct file_format_struct {
48
 
        ulint           id;             /*!< id of the file format */
49
 
        const char*     name;           /*!< text representation of the
50
 
                                        file format */
51
 
        mutex_t         mutex;          /*!< covers changes to the above
52
 
                                        fields */
53
 
};
54
 
 
55
 
/** The file format tag */
56
 
typedef struct file_format_struct       file_format_t;
57
 
 
58
 
/** The transaction system */
59
 
UNIV_INTERN trx_sys_t*          trx_sys         = NULL;
60
 
/** The doublewrite buffer */
61
 
UNIV_INTERN trx_doublewrite_t*  trx_doublewrite = NULL;
62
 
 
63
 
/** The following is set to TRUE when we are upgrading from pre-4.1
64
 
format data files to the multiple tablespaces format data files */
65
 
UNIV_INTERN ibool       trx_doublewrite_must_reset_space_ids    = FALSE;
66
 
/** Set to TRUE when the doublewrite buffer is being created */
67
 
UNIV_INTERN ibool       trx_doublewrite_buf_is_being_created = FALSE;
68
 
 
69
 
/** The following is TRUE when we are using the database in the
70
 
post-4.1 format, i.e., we have successfully upgraded, or have created
71
 
a new database installation */
72
 
UNIV_INTERN ibool       trx_sys_multiple_tablespace_format      = FALSE;
73
 
 
74
 
/** In a MySQL replication slave, in crash recovery we store the master log
75
 
file name and position here. */
76
 
/* @{ */
77
 
/** Master binlog file name */
78
 
UNIV_INTERN char        trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
79
 
/** Master binlog file position.  We have successfully got the updates
80
 
up to this position.  -1 means that no crash recovery was needed, or
81
 
there was no master log position info inside InnoDB.*/
82
 
UNIV_INTERN ib_int64_t  trx_sys_mysql_master_log_pos    = -1;
83
 
/* @} */
84
 
 
85
 
/** If this MySQL server uses binary logging, after InnoDB has been inited
86
 
and if it has done a crash recovery, we store the binlog file name and position
87
 
here. */
88
 
/* @{ */
89
 
/** Binlog file name */
90
 
UNIV_INTERN char        trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
91
 
/** Binlog file position, or -1 if unknown */
92
 
UNIV_INTERN ib_int64_t  trx_sys_mysql_bin_log_pos       = -1;
93
 
/* @} */
94
 
#endif /* !UNIV_HOTBACKUP */
95
 
 
96
 
/** List of animal names representing file format. */
97
 
static const char*      file_format_name_map[] = {
98
 
        "Antelope",
99
 
        "Barracuda",
100
 
        "Cheetah",
101
 
        "Dragon",
102
 
        "Elk",
103
 
        "Fox",
104
 
        "Gazelle",
105
 
        "Hornet",
106
 
        "Impala",
107
 
        "Jaguar",
108
 
        "Kangaroo",
109
 
        "Leopard",
110
 
        "Moose",
111
 
        "Nautilus",
112
 
        "Ocelot",
113
 
        "Porpoise",
114
 
        "Quail",
115
 
        "Rabbit",
116
 
        "Shark",
117
 
        "Tiger",
118
 
        "Urchin",
119
 
        "Viper",
120
 
        "Whale",
121
 
        "Xenops",
122
 
        "Yak",
123
 
        "Zebra"
124
 
};
125
 
 
126
 
/** The number of elements in the file format name array. */
127
 
static const ulint      FILE_FORMAT_NAME_N
128
 
        = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
129
 
 
130
 
#ifdef UNIV_PFS_MUTEX
131
 
/* Key to register the mutex with performance schema */
132
 
UNIV_INTERN mysql_pfs_key_t     trx_doublewrite_mutex_key;
133
 
UNIV_INTERN mysql_pfs_key_t     file_format_max_mutex_key;
134
 
#endif /* UNIV_PFS_MUTEX */
135
 
 
136
 
#ifndef UNIV_HOTBACKUP
137
 
/** This is used to track the maximum file format id known to InnoDB. It's
138
 
updated via SET GLOBAL innodb_file_format_max = 'x' or when we open
139
 
or create a table. */
140
 
static  file_format_t   file_format_max;
141
 
 
142
 
/****************************************************************//**
143
 
Determines if a page number is located inside the doublewrite buffer.
144
 
@return TRUE if the location is inside the two blocks of the
145
 
doublewrite buffer */
146
 
UNIV_INTERN
147
 
ibool
148
 
trx_doublewrite_page_inside(
149
 
/*========================*/
150
 
        ulint   page_no)        /*!< in: page number */
151
 
{
152
 
        if (trx_doublewrite == NULL) {
153
 
 
154
 
                return(FALSE);
155
 
        }
156
 
 
157
 
        if (page_no >= trx_doublewrite->block1
158
 
            && page_no < trx_doublewrite->block1
159
 
            + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
160
 
                return(TRUE);
161
 
        }
162
 
 
163
 
        if (page_no >= trx_doublewrite->block2
164
 
            && page_no < trx_doublewrite->block2
165
 
            + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
166
 
                return(TRUE);
167
 
        }
168
 
 
169
 
        return(FALSE);
170
 
}
171
 
 
172
 
/****************************************************************//**
173
 
Creates or initialializes the doublewrite buffer at a database start. */
174
 
static
175
 
void
176
 
trx_doublewrite_init(
177
 
/*=================*/
178
 
        byte*   doublewrite)    /*!< in: pointer to the doublewrite buf
179
 
                                header on trx sys page */
180
 
{
181
 
        trx_doublewrite = mem_alloc(sizeof(trx_doublewrite_t));
182
 
 
183
 
        /* Since we now start to use the doublewrite buffer, no need to call
184
 
        fsync() after every write to a data file */
185
 
#ifdef UNIV_DO_FLUSH
186
 
        os_do_not_call_flush_at_each_write = TRUE;
187
 
#endif /* UNIV_DO_FLUSH */
188
 
 
189
 
        mutex_create(trx_doublewrite_mutex_key,
190
 
                     &trx_doublewrite->mutex, SYNC_DOUBLEWRITE);
191
 
 
192
 
        trx_doublewrite->first_free = 0;
193
 
 
194
 
        trx_doublewrite->block1 = mach_read_from_4(
195
 
                doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK1);
196
 
        trx_doublewrite->block2 = mach_read_from_4(
197
 
                doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK2);
198
 
        trx_doublewrite->write_buf_unaligned = ut_malloc(
199
 
                (1 + 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) * UNIV_PAGE_SIZE);
200
 
 
201
 
        trx_doublewrite->write_buf = ut_align(
202
 
                trx_doublewrite->write_buf_unaligned, UNIV_PAGE_SIZE);
203
 
        trx_doublewrite->buf_block_arr = mem_alloc(
204
 
                2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * sizeof(void*));
205
 
}
206
 
 
207
 
/****************************************************************//**
208
 
Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
209
 
multiple tablespace format. */
210
 
UNIV_INTERN
211
 
void
212
 
trx_sys_mark_upgraded_to_multiple_tablespaces(void)
213
 
/*===============================================*/
214
 
{
215
 
        buf_block_t*    block;
216
 
        byte*           doublewrite;
217
 
        mtr_t           mtr;
218
 
 
219
 
        /* We upgraded to 4.1.x and reset the space id fields in the
220
 
        doublewrite buffer. Let us mark to the trx_sys header that the upgrade
221
 
        has been done. */
222
 
 
223
 
        mtr_start(&mtr);
224
 
 
225
 
        block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
226
 
                             RW_X_LATCH, &mtr);
227
 
        buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
228
 
 
229
 
        doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
230
 
 
231
 
        mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
232
 
                         TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
233
 
                         MLOG_4BYTES, &mtr);
234
 
        mtr_commit(&mtr);
235
 
 
236
 
        /* Flush the modified pages to disk and make a checkpoint */
237
 
        log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
238
 
 
239
 
        trx_sys_multiple_tablespace_format = TRUE;
240
 
}
241
 
 
242
 
/****************************************************************//**
243
 
Creates the doublewrite buffer to a new InnoDB installation. The header of the
244
 
doublewrite buffer is placed on the trx system header page. */
245
 
UNIV_INTERN
246
 
void
247
 
trx_sys_create_doublewrite_buf(void)
248
 
/*================================*/
249
 
{
250
 
        buf_block_t*    block;
251
 
        buf_block_t*    block2;
252
 
#ifdef UNIV_SYNC_DEBUG
253
 
        buf_block_t*    new_block;
254
 
#endif /* UNIV_SYNC_DEBUG */
255
 
        byte*   doublewrite;
256
 
        byte*   fseg_header;
257
 
        ulint   page_no;
258
 
        ulint   prev_page_no;
259
 
        ulint   i;
260
 
        mtr_t   mtr;
261
 
 
262
 
        if (trx_doublewrite) {
263
 
                /* Already inited */
264
 
 
265
 
                return;
266
 
        }
267
 
 
268
 
start_again:
269
 
        mtr_start(&mtr);
270
 
        trx_doublewrite_buf_is_being_created = TRUE;
271
 
 
272
 
        block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
273
 
                             RW_X_LATCH, &mtr);
274
 
        buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
275
 
 
276
 
        doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
277
 
 
278
 
        if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
279
 
            == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
280
 
                /* The doublewrite buffer has already been created:
281
 
                just read in some numbers */
282
 
 
283
 
                trx_doublewrite_init(doublewrite);
284
 
 
285
 
                mtr_commit(&mtr);
286
 
                trx_doublewrite_buf_is_being_created = FALSE;
287
 
        } else {
288
 
                fprintf(stderr,
289
 
                        "InnoDB: Doublewrite buffer not found:"
290
 
                        " creating new\n");
291
 
 
292
 
                if (buf_pool_get_curr_size()
293
 
                    < ((2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
294
 
                        + FSP_EXTENT_SIZE / 2 + 100)
295
 
                       * UNIV_PAGE_SIZE)) {
296
 
                        fprintf(stderr,
297
 
                                "InnoDB: Cannot create doublewrite buffer:"
298
 
                                " you must\n"
299
 
                                "InnoDB: increase your buffer pool size.\n"
300
 
                                "InnoDB: Cannot continue operation.\n");
301
 
 
302
 
                        exit(1);
303
 
                }
304
 
 
305
 
                block2 = fseg_create(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
306
 
                                     TRX_SYS_DOUBLEWRITE
307
 
                                     + TRX_SYS_DOUBLEWRITE_FSEG, &mtr);
308
 
 
309
 
                /* fseg_create acquires a second latch on the page,
310
 
                therefore we must declare it: */
311
 
 
312
 
                buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK);
313
 
 
314
 
                if (block2 == NULL) {
315
 
                        fprintf(stderr,
316
 
                                "InnoDB: Cannot create doublewrite buffer:"
317
 
                                " you must\n"
318
 
                                "InnoDB: increase your tablespace size.\n"
319
 
                                "InnoDB: Cannot continue operation.\n");
320
 
 
321
 
                        /* We exit without committing the mtr to prevent
322
 
                        its modifications to the database getting to disk */
323
 
 
324
 
                        exit(1);
325
 
                }
326
 
 
327
 
                fseg_header = buf_block_get_frame(block)
328
 
                        + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG;
329
 
                prev_page_no = 0;
330
 
 
331
 
                for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
332
 
                             + FSP_EXTENT_SIZE / 2; i++) {
333
 
                        page_no = fseg_alloc_free_page(fseg_header,
334
 
                                                       prev_page_no + 1,
335
 
                                                       FSP_UP, &mtr);
336
 
                        if (page_no == FIL_NULL) {
337
 
                                fprintf(stderr,
338
 
                                        "InnoDB: Cannot create doublewrite"
339
 
                                        " buffer: you must\n"
340
 
                                        "InnoDB: increase your"
341
 
                                        " tablespace size.\n"
342
 
                                        "InnoDB: Cannot continue operation.\n"
343
 
                                        );
344
 
 
345
 
                                exit(1);
346
 
                        }
347
 
 
348
 
                        /* We read the allocated pages to the buffer pool;
349
 
                        when they are written to disk in a flush, the space
350
 
                        id and page number fields are also written to the
351
 
                        pages. When we at database startup read pages
352
 
                        from the doublewrite buffer, we know that if the
353
 
                        space id and page number in them are the same as
354
 
                        the page position in the tablespace, then the page
355
 
                        has not been written to in doublewrite. */
356
 
 
357
 
#ifdef UNIV_SYNC_DEBUG
358
 
                        new_block =
359
 
#endif /* UNIV_SYNC_DEBUG */
360
 
                        buf_page_get(TRX_SYS_SPACE, 0, page_no,
361
 
                                     RW_X_LATCH, &mtr);
362
 
                        buf_block_dbg_add_level(new_block,
363
 
                                                SYNC_NO_ORDER_CHECK);
364
 
 
365
 
                        if (i == FSP_EXTENT_SIZE / 2) {
366
 
                                ut_a(page_no == FSP_EXTENT_SIZE);
367
 
                                mlog_write_ulint(doublewrite
368
 
                                                 + TRX_SYS_DOUBLEWRITE_BLOCK1,
369
 
                                                 page_no, MLOG_4BYTES, &mtr);
370
 
                                mlog_write_ulint(doublewrite
371
 
                                                 + TRX_SYS_DOUBLEWRITE_REPEAT
372
 
                                                 + TRX_SYS_DOUBLEWRITE_BLOCK1,
373
 
                                                 page_no, MLOG_4BYTES, &mtr);
374
 
                        } else if (i == FSP_EXTENT_SIZE / 2
375
 
                                   + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
376
 
                                ut_a(page_no == 2 * FSP_EXTENT_SIZE);
377
 
                                mlog_write_ulint(doublewrite
378
 
                                                 + TRX_SYS_DOUBLEWRITE_BLOCK2,
379
 
                                                 page_no, MLOG_4BYTES, &mtr);
380
 
                                mlog_write_ulint(doublewrite
381
 
                                                 + TRX_SYS_DOUBLEWRITE_REPEAT
382
 
                                                 + TRX_SYS_DOUBLEWRITE_BLOCK2,
383
 
                                                 page_no, MLOG_4BYTES, &mtr);
384
 
                        } else if (i > FSP_EXTENT_SIZE / 2) {
385
 
                                ut_a(page_no == prev_page_no + 1);
386
 
                        }
387
 
 
388
 
                        prev_page_no = page_no;
389
 
                }
390
 
 
391
 
                mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC,
392
 
                                 TRX_SYS_DOUBLEWRITE_MAGIC_N,
393
 
                                 MLOG_4BYTES, &mtr);
394
 
                mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC
395
 
                                 + TRX_SYS_DOUBLEWRITE_REPEAT,
396
 
                                 TRX_SYS_DOUBLEWRITE_MAGIC_N,
397
 
                                 MLOG_4BYTES, &mtr);
398
 
 
399
 
                mlog_write_ulint(doublewrite
400
 
                                 + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
401
 
                                 TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
402
 
                                 MLOG_4BYTES, &mtr);
403
 
                mtr_commit(&mtr);
404
 
 
405
 
                /* Flush the modified pages to disk and make a checkpoint */
406
 
                log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
407
 
 
408
 
                fprintf(stderr, "InnoDB: Doublewrite buffer created\n");
409
 
 
410
 
                trx_sys_multiple_tablespace_format = TRUE;
411
 
 
412
 
                goto start_again;
413
 
        }
414
 
}
415
 
 
416
 
/****************************************************************//**
417
 
At a database startup initializes the doublewrite buffer memory structure if
418
 
we already have a doublewrite buffer created in the data files. If we are
419
 
upgrading to an InnoDB version which supports multiple tablespaces, then this
420
 
function performs the necessary update operations. If we are in a crash
421
 
recovery, this function uses a possible doublewrite buffer to restore
422
 
half-written pages in the data files. */
423
 
UNIV_INTERN
424
 
void
425
 
trx_sys_doublewrite_init_or_restore_pages(
426
 
/*======================================*/
427
 
        ibool   restore_corrupt_pages)  /*!< in: TRUE=restore pages */
428
 
{
429
 
        byte*   buf;
430
 
        byte*   read_buf;
431
 
        byte*   unaligned_read_buf;
432
 
        ulint   block1;
433
 
        ulint   block2;
434
 
        ulint   source_page_no;
435
 
        byte*   page;
436
 
        byte*   doublewrite;
437
 
        ulint   space_id;
438
 
        ulint   page_no;
439
 
        ulint   i;
440
 
 
441
 
        /* We do the file i/o past the buffer pool */
442
 
 
443
 
        unaligned_read_buf = ut_malloc(2 * UNIV_PAGE_SIZE);
444
 
        read_buf = ut_align(unaligned_read_buf, UNIV_PAGE_SIZE);
445
 
 
446
 
        /* Read the trx sys header to check if we are using the doublewrite
447
 
        buffer */
448
 
 
449
 
        fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
450
 
               UNIV_PAGE_SIZE, read_buf, NULL);
451
 
        doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
452
 
 
453
 
        if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
454
 
            == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
455
 
                /* The doublewrite buffer has been created */
456
 
 
457
 
                trx_doublewrite_init(doublewrite);
458
 
 
459
 
                block1 = trx_doublewrite->block1;
460
 
                block2 = trx_doublewrite->block2;
461
 
 
462
 
                buf = trx_doublewrite->write_buf;
463
 
        } else {
464
 
                goto leave_func;
465
 
        }
466
 
 
467
 
        if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED)
468
 
            != TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) {
469
 
 
470
 
                /* We are upgrading from a version < 4.1.x to a version where
471
 
                multiple tablespaces are supported. We must reset the space id
472
 
                field in the pages in the doublewrite buffer because starting
473
 
                from this version the space id is stored to
474
 
                FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */
475
 
 
476
 
                trx_doublewrite_must_reset_space_ids = TRUE;
477
 
 
478
 
                fprintf(stderr,
479
 
                        "InnoDB: Resetting space id's in the"
480
 
                        " doublewrite buffer\n");
481
 
        } else {
482
 
                trx_sys_multiple_tablespace_format = TRUE;
483
 
        }
484
 
 
485
 
        /* Read the pages from the doublewrite buffer to memory */
486
 
 
487
 
        fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block1, 0,
488
 
               TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
489
 
               buf, NULL);
490
 
        fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block2, 0,
491
 
               TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
492
 
               buf + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
493
 
               NULL);
494
 
        /* Check if any of these pages is half-written in data files, in the
495
 
        intended position */
496
 
 
497
 
        page = buf;
498
 
 
499
 
        for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) {
500
 
 
501
 
                page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
502
 
 
503
 
                if (trx_doublewrite_must_reset_space_ids) {
504
 
 
505
 
                        space_id = 0;
506
 
                        mach_write_to_4(page
507
 
                                        + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0);
508
 
                        /* We do not need to calculate new checksums for the
509
 
                        pages because the field .._SPACE_ID does not affect
510
 
                        them. Write the page back to where we read it from. */
511
 
 
512
 
                        if (i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
513
 
                                source_page_no = block1 + i;
514
 
                        } else {
515
 
                                source_page_no = block2
516
 
                                        + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
517
 
                        }
518
 
 
519
 
                        fil_io(OS_FILE_WRITE, TRUE, 0, 0, source_page_no, 0,
520
 
                               UNIV_PAGE_SIZE, page, NULL);
521
 
                        /* printf("Resetting space id in page %lu\n",
522
 
                        source_page_no); */
523
 
                } else {
524
 
                        space_id = mach_read_from_4(
525
 
                                page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
526
 
                }
527
 
 
528
 
                if (!restore_corrupt_pages) {
529
 
                        /* The database was shut down gracefully: no need to
530
 
                        restore pages */
531
 
 
532
 
                } else if (!fil_tablespace_exists_in_mem(space_id)) {
533
 
                        /* Maybe we have dropped the single-table tablespace
534
 
                        and this page once belonged to it: do nothing */
535
 
 
536
 
                } else if (!fil_check_adress_in_tablespace(space_id,
537
 
                                                           page_no)) {
538
 
                        fprintf(stderr,
539
 
                                "InnoDB: Warning: a page in the"
540
 
                                " doublewrite buffer is not within space\n"
541
 
                                "InnoDB: bounds; space id %lu"
542
 
                                " page number %lu, page %lu in"
543
 
                                " doublewrite buf.\n",
544
 
                                (ulong) space_id, (ulong) page_no, (ulong) i);
545
 
 
546
 
                } else if (space_id == TRX_SYS_SPACE
547
 
                           && ((page_no >= block1
548
 
                                && page_no
549
 
                                < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
550
 
                               || (page_no >= block2
551
 
                                   && page_no
552
 
                                   < (block2
553
 
                                      + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) {
554
 
 
555
 
                        /* It is an unwritten doublewrite buffer page:
556
 
                        do nothing */
557
 
                } else {
558
 
                        ulint   zip_size = fil_space_get_zip_size(space_id);
559
 
 
560
 
                        /* Read in the actual page from the file */
561
 
                        fil_io(OS_FILE_READ, TRUE, space_id, zip_size,
562
 
                               page_no, 0,
563
 
                               zip_size ? zip_size : UNIV_PAGE_SIZE,
564
 
                               read_buf, NULL);
565
 
 
566
 
                        /* Check if the page is corrupt */
567
 
 
568
 
                        if (UNIV_UNLIKELY
569
 
                            (buf_page_is_corrupted(read_buf, zip_size))) {
570
 
 
571
 
                                fprintf(stderr,
572
 
                                        "InnoDB: Warning: database page"
573
 
                                        " corruption or a failed\n"
574
 
                                        "InnoDB: file read of"
575
 
                                        " space %lu page %lu.\n"
576
 
                                        "InnoDB: Trying to recover it from"
577
 
                                        " the doublewrite buffer.\n",
578
 
                                        (ulong) space_id, (ulong) page_no);
579
 
 
580
 
                                if (buf_page_is_corrupted(page, zip_size)) {
581
 
                                        fprintf(stderr,
582
 
                                                "InnoDB: Dump of the page:\n");
583
 
                                        buf_page_print(read_buf, zip_size);
584
 
                                        fprintf(stderr,
585
 
                                                "InnoDB: Dump of"
586
 
                                                " corresponding page"
587
 
                                                " in doublewrite buffer:\n");
588
 
                                        buf_page_print(page, zip_size);
589
 
 
590
 
                                        fprintf(stderr,
591
 
                                                "InnoDB: Also the page in the"
592
 
                                                " doublewrite buffer"
593
 
                                                " is corrupt.\n"
594
 
                                                "InnoDB: Cannot continue"
595
 
                                                " operation.\n"
596
 
                                                "InnoDB: You can try to"
597
 
                                                " recover the database"
598
 
                                                " with the my.cnf\n"
599
 
                                                "InnoDB: option:\n"
600
 
                                                "InnoDB:"
601
 
                                                " innodb_force_recovery=6\n");
602
 
                                        exit(1);
603
 
                                }
604
 
 
605
 
                                /* Write the good page from the
606
 
                                doublewrite buffer to the intended
607
 
                                position */
608
 
 
609
 
                                fil_io(OS_FILE_WRITE, TRUE, space_id,
610
 
                                       zip_size, page_no, 0,
611
 
                                       zip_size ? zip_size : UNIV_PAGE_SIZE,
612
 
                                       page, NULL);
613
 
                                fprintf(stderr,
614
 
                                        "InnoDB: Recovered the page from"
615
 
                                        " the doublewrite buffer.\n");
616
 
                        }
617
 
                }
618
 
 
619
 
                page += UNIV_PAGE_SIZE;
620
 
        }
621
 
 
622
 
        fil_flush_file_spaces(FIL_TABLESPACE);
623
 
 
624
 
leave_func:
625
 
        ut_free(unaligned_read_buf);
626
 
}
627
 
 
628
 
/****************************************************************//**
629
 
Checks that trx is in the trx list.
630
 
@return TRUE if is in */
631
 
UNIV_INTERN
632
 
ibool
633
 
trx_in_trx_list(
634
 
/*============*/
635
 
        trx_t*  in_trx) /*!< in: trx */
636
 
{
637
 
        trx_t*  trx;
638
 
 
639
 
        ut_ad(mutex_own(&(kernel_mutex)));
640
 
 
641
 
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
642
 
 
643
 
        while (trx != NULL) {
644
 
 
645
 
                if (trx == in_trx) {
646
 
 
647
 
                        return(TRUE);
648
 
                }
649
 
 
650
 
                trx = UT_LIST_GET_NEXT(trx_list, trx);
651
 
        }
652
 
 
653
 
        return(FALSE);
654
 
}
655
 
 
656
 
/*****************************************************************//**
657
 
Writes the value of max_trx_id to the file based trx system header. */
658
 
UNIV_INTERN
659
 
void
660
 
trx_sys_flush_max_trx_id(void)
661
 
/*==========================*/
662
 
{
663
 
        trx_sysf_t*     sys_header;
664
 
        mtr_t           mtr;
665
 
 
666
 
        ut_ad(mutex_own(&kernel_mutex));
667
 
 
668
 
        mtr_start(&mtr);
669
 
 
670
 
        sys_header = trx_sysf_get(&mtr);
671
 
 
672
 
        mlog_write_ull(sys_header + TRX_SYS_TRX_ID_STORE,
673
 
                       trx_sys->max_trx_id, &mtr);
674
 
        mtr_commit(&mtr);
675
 
}
676
 
 
677
 
/*****************************************************************//**
678
 
Updates the offset information about the end of the MySQL binlog entry
679
 
which corresponds to the transaction just being committed. In a MySQL
680
 
replication slave updates the latest master binlog position up to which
681
 
replication has proceeded. */
682
 
UNIV_INTERN
683
 
void
684
 
trx_sys_update_mysql_binlog_offset(
685
 
/*===============================*/
686
 
        const char*     file_name,/*!< in: MySQL log file name */
687
 
        ib_int64_t      offset, /*!< in: position in that log file */
688
 
        ulint           field,  /*!< in: offset of the MySQL log info field in
689
 
                                the trx sys header */
690
 
        mtr_t*          mtr)    /*!< in: mtr */
691
 
{
692
 
        trx_sysf_t*     sys_header;
693
 
 
694
 
        if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
695
 
 
696
 
                /* We cannot fit the name to the 512 bytes we have reserved */
697
 
 
698
 
                return;
699
 
        }
700
 
 
701
 
        sys_header = trx_sysf_get(mtr);
702
 
 
703
 
        if (mach_read_from_4(sys_header + field
704
 
                             + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
705
 
            != TRX_SYS_MYSQL_LOG_MAGIC_N) {
706
 
 
707
 
                mlog_write_ulint(sys_header + field
708
 
                                 + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD,
709
 
                                 TRX_SYS_MYSQL_LOG_MAGIC_N,
710
 
                                 MLOG_4BYTES, mtr);
711
 
        }
712
 
 
713
 
        if (0 != strcmp((char*) (sys_header + field + TRX_SYS_MYSQL_LOG_NAME),
714
 
                        file_name)) {
715
 
 
716
 
                mlog_write_string(sys_header + field
717
 
                                  + TRX_SYS_MYSQL_LOG_NAME,
718
 
                                  (byte*) file_name, 1 + ut_strlen(file_name),
719
 
                                  mtr);
720
 
        }
721
 
 
722
 
        if (mach_read_from_4(sys_header + field
723
 
                             + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0
724
 
            || (offset >> 32) > 0) {
725
 
 
726
 
                mlog_write_ulint(sys_header + field
727
 
                                 + TRX_SYS_MYSQL_LOG_OFFSET_HIGH,
728
 
                                 (ulint)(offset >> 32),
729
 
                                 MLOG_4BYTES, mtr);
730
 
        }
731
 
 
732
 
        mlog_write_ulint(sys_header + field
733
 
                         + TRX_SYS_MYSQL_LOG_OFFSET_LOW,
734
 
                         (ulint)(offset & 0xFFFFFFFFUL),
735
 
                         MLOG_4BYTES, mtr);
736
 
}
737
 
 
738
 
/*****************************************************************//**
739
 
Stores the MySQL binlog offset info in the trx system header if
740
 
the magic number shows it valid, and print the info to stderr */
741
 
UNIV_INTERN
742
 
void
743
 
trx_sys_print_mysql_binlog_offset(void)
744
 
/*===================================*/
745
 
{
746
 
        trx_sysf_t*     sys_header;
747
 
        mtr_t           mtr;
748
 
        ulint           trx_sys_mysql_bin_log_pos_high;
749
 
        ulint           trx_sys_mysql_bin_log_pos_low;
750
 
 
751
 
        mtr_start(&mtr);
752
 
 
753
 
        sys_header = trx_sysf_get(&mtr);
754
 
 
755
 
        if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
756
 
                             + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
757
 
            != TRX_SYS_MYSQL_LOG_MAGIC_N) {
758
 
 
759
 
                mtr_commit(&mtr);
760
 
 
761
 
                return;
762
 
        }
763
 
 
764
 
        trx_sys_mysql_bin_log_pos_high = mach_read_from_4(
765
 
                sys_header + TRX_SYS_MYSQL_LOG_INFO
766
 
                + TRX_SYS_MYSQL_LOG_OFFSET_HIGH);
767
 
        trx_sys_mysql_bin_log_pos_low = mach_read_from_4(
768
 
                sys_header + TRX_SYS_MYSQL_LOG_INFO
769
 
                + TRX_SYS_MYSQL_LOG_OFFSET_LOW);
770
 
 
771
 
        trx_sys_mysql_bin_log_pos
772
 
                = (((ib_int64_t)trx_sys_mysql_bin_log_pos_high) << 32)
773
 
                + (ib_int64_t)trx_sys_mysql_bin_log_pos_low;
774
 
 
775
 
        ut_memcpy(trx_sys_mysql_bin_log_name,
776
 
                  sys_header + TRX_SYS_MYSQL_LOG_INFO
777
 
                  + TRX_SYS_MYSQL_LOG_NAME, TRX_SYS_MYSQL_LOG_NAME_LEN);
778
 
 
779
 
        fprintf(stderr,
780
 
                "InnoDB: Last MySQL binlog file position %lu %lu,"
781
 
                " file name %s\n",
782
 
                trx_sys_mysql_bin_log_pos_high, trx_sys_mysql_bin_log_pos_low,
783
 
                trx_sys_mysql_bin_log_name);
784
 
 
785
 
        mtr_commit(&mtr);
786
 
}
787
 
 
788
 
/*****************************************************************//**
789
 
Prints to stderr the MySQL master log offset info in the trx system header if
790
 
the magic number shows it valid. */
791
 
UNIV_INTERN
792
 
void
793
 
trx_sys_print_mysql_master_log_pos(void)
794
 
/*====================================*/
795
 
{
796
 
        trx_sysf_t*     sys_header;
797
 
        mtr_t           mtr;
798
 
 
799
 
        mtr_start(&mtr);
800
 
 
801
 
        sys_header = trx_sysf_get(&mtr);
802
 
 
803
 
        if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
804
 
                             + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
805
 
            != TRX_SYS_MYSQL_LOG_MAGIC_N) {
806
 
 
807
 
                mtr_commit(&mtr);
808
 
 
809
 
                return;
810
 
        }
811
 
 
812
 
        fprintf(stderr,
813
 
                "InnoDB: In a MySQL replication slave the last"
814
 
                " master binlog file\n"
815
 
                "InnoDB: position %lu %lu, file name %s\n",
816
 
                (ulong) mach_read_from_4(sys_header
817
 
                                         + TRX_SYS_MYSQL_MASTER_LOG_INFO
818
 
                                         + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
819
 
                (ulong) mach_read_from_4(sys_header
820
 
                                         + TRX_SYS_MYSQL_MASTER_LOG_INFO
821
 
                                         + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
822
 
                sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
823
 
                + TRX_SYS_MYSQL_LOG_NAME);
824
 
        /* Copy the master log position info to global variables we can
825
 
        use in ha_innobase.cc to initialize glob_mi to right values */
826
 
 
827
 
        ut_memcpy(trx_sys_mysql_master_log_name,
828
 
                  sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
829
 
                  + TRX_SYS_MYSQL_LOG_NAME,
830
 
                  TRX_SYS_MYSQL_LOG_NAME_LEN);
831
 
 
832
 
        trx_sys_mysql_master_log_pos
833
 
                = (((ib_int64_t) mach_read_from_4(
834
 
                            sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
835
 
                            + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
836
 
                + ((ib_int64_t) mach_read_from_4(
837
 
                           sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
838
 
                           + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
839
 
        mtr_commit(&mtr);
840
 
}
841
 
 
842
 
/****************************************************************//**
843
 
Looks for a free slot for a rollback segment in the trx system file copy.
844
 
@return slot index or ULINT_UNDEFINED if not found */
845
 
UNIV_INTERN
846
 
ulint
847
 
trx_sysf_rseg_find_free(
848
 
/*====================*/
849
 
        mtr_t*  mtr)    /*!< in: mtr */
850
 
{
851
 
        trx_sysf_t*     sys_header;
852
 
        ulint           page_no;
853
 
        ulint           i;
854
 
 
855
 
        ut_ad(mutex_own(&(kernel_mutex)));
856
 
 
857
 
        sys_header = trx_sysf_get(mtr);
858
 
 
859
 
        for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
860
 
 
861
 
                page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
862
 
 
863
 
                if (page_no == FIL_NULL) {
864
 
 
865
 
                        return(i);
866
 
                }
867
 
        }
868
 
 
869
 
        return(ULINT_UNDEFINED);
870
 
}
871
 
 
872
 
/*****************************************************************//**
873
 
Creates the file page for the transaction system. This function is called only
874
 
at the database creation, before trx_sys_init. */
875
 
static
876
 
void
877
 
trx_sysf_create(
878
 
/*============*/
879
 
        mtr_t*  mtr)    /*!< in: mtr */
880
 
{
881
 
        trx_sysf_t*     sys_header;
882
 
        ulint           slot_no;
883
 
        buf_block_t*    block;
884
 
        page_t*         page;
885
 
        ulint           page_no;
886
 
        byte*           ptr;
887
 
        ulint           len;
888
 
 
889
 
        ut_ad(mtr);
890
 
 
891
 
        /* Note that below we first reserve the file space x-latch, and
892
 
        then enter the kernel: we must do it in this order to conform
893
 
        to the latching order rules. */
894
 
 
895
 
        mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), mtr);
896
 
        mutex_enter(&kernel_mutex);
897
 
 
898
 
        /* Create the trx sys file block in a new allocated file segment */
899
 
        block = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER,
900
 
                            mtr);
901
 
        buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
902
 
 
903
 
        ut_a(buf_block_get_page_no(block) == TRX_SYS_PAGE_NO);
904
 
 
905
 
        page = buf_block_get_frame(block);
906
 
 
907
 
        mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_TRX_SYS,
908
 
                         MLOG_2BYTES, mtr);
909
 
 
910
 
        /* Reset the doublewrite buffer magic number to zero so that we
911
 
        know that the doublewrite buffer has not yet been created (this
912
 
        suppresses a Valgrind warning) */
913
 
 
914
 
        mlog_write_ulint(page + TRX_SYS_DOUBLEWRITE
915
 
                         + TRX_SYS_DOUBLEWRITE_MAGIC, 0, MLOG_4BYTES, mtr);
916
 
 
917
 
        sys_header = trx_sysf_get(mtr);
918
 
 
919
 
        /* Start counting transaction ids from number 1 up */
920
 
        mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, 1);
921
 
 
922
 
        /* Reset the rollback segment slots.  Old versions of InnoDB
923
 
        define TRX_SYS_N_RSEGS as 256 (TRX_SYS_OLD_N_RSEGS) and expect
924
 
        that the whole array is initialized. */
925
 
        ptr = TRX_SYS_RSEGS + sys_header;
926
 
        len = ut_max(TRX_SYS_OLD_N_RSEGS, TRX_SYS_N_RSEGS)
927
 
                * TRX_SYS_RSEG_SLOT_SIZE;
928
 
        memset(ptr, 0xff, len);
929
 
        ptr += len;
930
 
        ut_a(ptr <= page + (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END));
931
 
 
932
 
        /* Initialize all of the page.  This part used to be uninitialized. */
933
 
        memset(ptr, 0, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page - ptr);
934
 
 
935
 
        mlog_log_string(sys_header, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
936
 
                        + page - sys_header, mtr);
937
 
 
938
 
        /* Create the first rollback segment in the SYSTEM tablespace */
939
 
        slot_no = trx_sysf_rseg_find_free(mtr);
940
 
        page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, slot_no,
941
 
                                         mtr);
942
 
        ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
943
 
        ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO);
944
 
 
945
 
        mutex_exit(&kernel_mutex);
946
 
}
947
 
 
948
 
/*****************************************************************//**
949
 
Creates and initializes the central memory structures for the transaction
950
 
system. This is called when the database is started. */
951
 
UNIV_INTERN
952
 
void
953
 
trx_sys_init_at_db_start(void)
954
 
/*==========================*/
955
 
{
956
 
        trx_sysf_t*     sys_header;
957
 
        ib_uint64_t     rows_to_undo    = 0;
958
 
        const char*     unit            = "";
959
 
        trx_t*          trx;
960
 
        mtr_t           mtr;
961
 
 
962
 
        mtr_start(&mtr);
963
 
 
964
 
        ut_ad(trx_sys == NULL);
965
 
 
966
 
        mutex_enter(&kernel_mutex);
967
 
 
968
 
        trx_sys = mem_alloc(sizeof(trx_sys_t));
969
 
 
970
 
        sys_header = trx_sysf_get(&mtr);
971
 
 
972
 
        trx_rseg_list_and_array_init(sys_header, &mtr);
973
 
 
974
 
        trx_sys->latest_rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
975
 
 
976
 
        /* VERY important: after the database is started, max_trx_id value is
977
 
        divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the 'if' in
978
 
        trx_sys_get_new_trx_id will evaluate to TRUE when the function
979
 
        is first time called, and the value for trx id will be written
980
 
        to the disk-based header! Thus trx id values will not overlap when
981
 
        the database is repeatedly started! */
982
 
 
983
 
        trx_sys->max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN
984
 
                + ut_uint64_align_up(mach_read_from_8(sys_header
985
 
                                                   + TRX_SYS_TRX_ID_STORE),
986
 
                                     TRX_SYS_TRX_ID_WRITE_MARGIN);
987
 
 
988
 
        UT_LIST_INIT(trx_sys->mysql_trx_list);
989
 
        trx_dummy_sess = sess_open();
990
 
        trx_lists_init_at_db_start();
991
 
 
992
 
        if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
993
 
                trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
994
 
 
995
 
                for (;;) {
996
 
 
997
 
                        if (trx->conc_state != TRX_PREPARED) {
998
 
                                rows_to_undo += trx->undo_no;
999
 
                        }
1000
 
 
1001
 
                        trx = UT_LIST_GET_NEXT(trx_list, trx);
1002
 
 
1003
 
                        if (!trx) {
1004
 
                                break;
1005
 
                        }
1006
 
                }
1007
 
 
1008
 
                if (rows_to_undo > 1000000000) {
1009
 
                        unit = "M";
1010
 
                        rows_to_undo = rows_to_undo / 1000000;
1011
 
                }
1012
 
 
1013
 
                fprintf(stderr,
1014
 
                        "InnoDB: %lu transaction(s) which must be"
1015
 
                        " rolled back or cleaned up\n"
1016
 
                        "InnoDB: in total %lu%s row operations to undo\n",
1017
 
                        (ulong) UT_LIST_GET_LEN(trx_sys->trx_list),
1018
 
                        (ulong) rows_to_undo, unit);
1019
 
 
1020
 
                fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n",
1021
 
                        trx_sys->max_trx_id);
1022
 
        }
1023
 
 
1024
 
        UT_LIST_INIT(trx_sys->view_list);
1025
 
 
1026
 
        trx_purge_sys_create();
1027
 
 
1028
 
        mutex_exit(&kernel_mutex);
1029
 
 
1030
 
        mtr_commit(&mtr);
1031
 
}
1032
 
 
1033
 
/*****************************************************************//**
1034
 
Creates and initializes the transaction system at the database creation. */
1035
 
UNIV_INTERN
1036
 
void
1037
 
trx_sys_create(void)
1038
 
/*================*/
1039
 
{
1040
 
        mtr_t   mtr;
1041
 
 
1042
 
        mtr_start(&mtr);
1043
 
 
1044
 
        trx_sysf_create(&mtr);
1045
 
 
1046
 
        mtr_commit(&mtr);
1047
 
 
1048
 
        trx_sys_init_at_db_start();
1049
 
}
1050
 
 
1051
 
/*****************************************************************//**
1052
 
Update the file format tag.
1053
 
@return always TRUE */
1054
 
static
1055
 
ibool
1056
 
trx_sys_file_format_max_write(
1057
 
/*==========================*/
1058
 
        ulint           format_id,      /*!< in: file format id */
1059
 
        const char**    name)           /*!< out: max file format name, can
1060
 
                                        be NULL */
1061
 
{
1062
 
        mtr_t           mtr;
1063
 
        byte*           ptr;
1064
 
        buf_block_t*    block;
1065
 
        ib_uint64_t     tag_value;
1066
 
 
1067
 
        mtr_start(&mtr);
1068
 
 
1069
 
        block = buf_page_get(
1070
 
                TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
1071
 
 
1072
 
        file_format_max.id = format_id;
1073
 
        file_format_max.name = trx_sys_file_format_id_to_name(format_id);
1074
 
 
1075
 
        ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
1076
 
        tag_value = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
1077
 
 
1078
 
        if (name) {
1079
 
                *name = file_format_max.name;
1080
 
        }
1081
 
 
1082
 
        mlog_write_ull(ptr, tag_value, &mtr);
1083
 
 
1084
 
        mtr_commit(&mtr);
1085
 
 
1086
 
        return(TRUE);
1087
 
}
1088
 
 
1089
 
/*****************************************************************//**
1090
 
Read the file format tag.
1091
 
@return the file format or ULINT_UNDEFINED if not set. */
1092
 
static
1093
 
ulint
1094
 
trx_sys_file_format_max_read(void)
1095
 
/*==============================*/
1096
 
{
1097
 
        mtr_t                   mtr;
1098
 
        const byte*             ptr;
1099
 
        const buf_block_t*      block;
1100
 
        ib_id_t                 file_format_id;
1101
 
 
1102
 
        /* Since this is called during the startup phase it's safe to
1103
 
        read the value without a covering mutex. */
1104
 
        mtr_start(&mtr);
1105
 
 
1106
 
        block = buf_page_get(
1107
 
                TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
1108
 
 
1109
 
        ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
1110
 
        file_format_id = mach_read_from_8(ptr);
1111
 
 
1112
 
        mtr_commit(&mtr);
1113
 
 
1114
 
        file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
1115
 
 
1116
 
        if (file_format_id >= FILE_FORMAT_NAME_N) {
1117
 
 
1118
 
                /* Either it has never been tagged, or garbage in it. */
1119
 
                return(ULINT_UNDEFINED);
1120
 
        }
1121
 
 
1122
 
        return((ulint) file_format_id);
1123
 
}
1124
 
 
1125
 
/*****************************************************************//**
1126
 
Get the name representation of the file format from its id.
1127
 
@return pointer to the name */
1128
 
UNIV_INTERN
1129
 
const char*
1130
 
trx_sys_file_format_id_to_name(
1131
 
/*===========================*/
1132
 
        const ulint     id)     /*!< in: id of the file format */
1133
 
{
1134
 
        ut_a(id < FILE_FORMAT_NAME_N);
1135
 
 
1136
 
        return(file_format_name_map[id]);
1137
 
}
1138
 
 
1139
 
/*****************************************************************//**
1140
 
Check for the max file format tag stored on disk. Note: If max_format_id
1141
 
is == DICT_TF_FORMAT_MAX + 1 then we only print a warning.
1142
 
@return DB_SUCCESS or error code */
1143
 
UNIV_INTERN
1144
 
ulint
1145
 
trx_sys_file_format_max_check(
1146
 
/*==========================*/
1147
 
        ulint   max_format_id)  /*!< in: max format id to check */
1148
 
{
1149
 
        ulint   format_id;
1150
 
 
1151
 
        /* Check the file format in the tablespace. Do not try to
1152
 
        recover if the file format is not supported by the engine
1153
 
        unless forced by the user. */
1154
 
        format_id = trx_sys_file_format_max_read();
1155
 
        if (format_id == ULINT_UNDEFINED) {
1156
 
                /* Format ID was not set. Set it to minimum possible
1157
 
                value. */
1158
 
                format_id = DICT_TF_FORMAT_MIN;
1159
 
        }
1160
 
 
1161
 
        ut_print_timestamp(stderr);
1162
 
        fprintf(stderr,
1163
 
                "  InnoDB: highest supported file format is %s.\n",
1164
 
                trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
1165
 
 
1166
 
        if (format_id > DICT_TF_FORMAT_MAX) {
1167
 
 
1168
 
                ut_a(format_id < FILE_FORMAT_NAME_N);
1169
 
 
1170
 
                ut_print_timestamp(stderr);
1171
 
                fprintf(stderr,
1172
 
                        "  InnoDB: %s: the system tablespace is in a file "
1173
 
                        "format that this version doesn't support - %s\n",
1174
 
                        ((max_format_id <= DICT_TF_FORMAT_MAX)
1175
 
                                ? "Error" : "Warning"),
1176
 
                        trx_sys_file_format_id_to_name(format_id));
1177
 
 
1178
 
                if (max_format_id <= DICT_TF_FORMAT_MAX) {
1179
 
                        return(DB_ERROR);
1180
 
                }
1181
 
        }
1182
 
 
1183
 
        format_id = (format_id > max_format_id) ? format_id : max_format_id;
1184
 
 
1185
 
        /* We don't need a mutex here, as this function should only
1186
 
        be called once at start up. */
1187
 
        file_format_max.id = format_id;
1188
 
        file_format_max.name = trx_sys_file_format_id_to_name(format_id);
1189
 
 
1190
 
        return(DB_SUCCESS);
1191
 
}
1192
 
 
1193
 
/*****************************************************************//**
1194
 
Set the file format id unconditionally except if it's already the
1195
 
same value.
1196
 
@return TRUE if value updated */
1197
 
UNIV_INTERN
1198
 
ibool
1199
 
trx_sys_file_format_max_set(
1200
 
/*========================*/
1201
 
        ulint           format_id,      /*!< in: file format id */
1202
 
        const char**    name)           /*!< out: max file format name or
1203
 
                                        NULL if not needed. */
1204
 
{
1205
 
        ibool           ret = FALSE;
1206
 
 
1207
 
        ut_a(format_id <= DICT_TF_FORMAT_MAX);
1208
 
 
1209
 
        mutex_enter(&file_format_max.mutex);
1210
 
 
1211
 
        /* Only update if not already same value. */
1212
 
        if (format_id != file_format_max.id) {
1213
 
 
1214
 
                ret = trx_sys_file_format_max_write(format_id, name);
1215
 
        }
1216
 
 
1217
 
        mutex_exit(&file_format_max.mutex);
1218
 
 
1219
 
        return(ret);
1220
 
}
1221
 
 
1222
 
/********************************************************************//**
1223
 
Tags the system table space with minimum format id if it has not been
1224
 
tagged yet.
1225
 
WARNING: This function is only called during the startup and AFTER the
1226
 
redo log application during recovery has finished. */
1227
 
UNIV_INTERN
1228
 
void
1229
 
trx_sys_file_format_tag_init(void)
1230
 
/*==============================*/
1231
 
{
1232
 
        ulint   format_id;
1233
 
 
1234
 
        format_id = trx_sys_file_format_max_read();
1235
 
 
1236
 
        /* If format_id is not set then set it to the minimum. */
1237
 
        if (format_id == ULINT_UNDEFINED) {
1238
 
                trx_sys_file_format_max_set(DICT_TF_FORMAT_MIN, NULL);
1239
 
        }
1240
 
}
1241
 
 
1242
 
/********************************************************************//**
1243
 
Update the file format tag in the system tablespace only if the given
1244
 
format id is greater than the known max id.
1245
 
@return TRUE if format_id was bigger than the known max id */
1246
 
UNIV_INTERN
1247
 
ibool
1248
 
trx_sys_file_format_max_upgrade(
1249
 
/*============================*/
1250
 
        const char**    name,           /*!< out: max file format name */
1251
 
        ulint           format_id)      /*!< in: file format identifier */
1252
 
{
1253
 
        ibool           ret = FALSE;
1254
 
 
1255
 
        ut_a(name);
1256
 
        ut_a(file_format_max.name != NULL);
1257
 
        ut_a(format_id <= DICT_TF_FORMAT_MAX);
1258
 
 
1259
 
        mutex_enter(&file_format_max.mutex);
1260
 
 
1261
 
        if (format_id > file_format_max.id) {
1262
 
 
1263
 
                ret = trx_sys_file_format_max_write(format_id, name);
1264
 
        }
1265
 
 
1266
 
        mutex_exit(&file_format_max.mutex);
1267
 
 
1268
 
        return(ret);
1269
 
}
1270
 
 
1271
 
/*****************************************************************//**
1272
 
Get the name representation of the file format from its id.
1273
 
@return pointer to the max format name */
1274
 
UNIV_INTERN
1275
 
const char*
1276
 
trx_sys_file_format_max_get(void)
1277
 
/*=============================*/
1278
 
{
1279
 
        return(file_format_max.name);
1280
 
}
1281
 
 
1282
 
/*****************************************************************//**
1283
 
Initializes the tablespace tag system. */
1284
 
UNIV_INTERN
1285
 
void
1286
 
trx_sys_file_format_init(void)
1287
 
/*==========================*/
1288
 
{
1289
 
        mutex_create(file_format_max_mutex_key,
1290
 
                     &file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
1291
 
 
1292
 
        /* We don't need a mutex here, as this function should only
1293
 
        be called once at start up. */
1294
 
        file_format_max.id = DICT_TF_FORMAT_MIN;
1295
 
 
1296
 
        file_format_max.name = trx_sys_file_format_id_to_name(
1297
 
                file_format_max.id);
1298
 
}
1299
 
 
1300
 
/*****************************************************************//**
1301
 
Closes the tablespace tag system. */
1302
 
UNIV_INTERN
1303
 
void
1304
 
trx_sys_file_format_close(void)
1305
 
/*===========================*/
1306
 
{
1307
 
        /* Does nothing at the moment */
1308
 
}
1309
 
 
1310
 
/*********************************************************************
1311
 
Creates the rollback segments */
1312
 
UNIV_INTERN
1313
 
void
1314
 
trx_sys_create_rsegs(
1315
 
/*=================*/
1316
 
        ulint   n_rsegs)        /*!< number of rollback segments to create */
1317
 
{
1318
 
        ulint   new_rsegs = 0;
1319
 
 
1320
 
        /* Do not create additional rollback segments if
1321
 
        innodb_force_recovery has been set and the database
1322
 
        was not shutdown cleanly. */
1323
 
        if (!srv_force_recovery && !recv_needed_recovery) {
1324
 
                ulint   i;
1325
 
 
1326
 
                for (i = 0;  i < n_rsegs; ++i) {
1327
 
 
1328
 
                        if (trx_rseg_create() != NULL) {
1329
 
                                ++new_rsegs;
1330
 
                        } else {
1331
 
                                break;
1332
 
                        }
1333
 
                }
1334
 
        }
1335
 
 
1336
 
        if (new_rsegs > 0) {
1337
 
                fprintf(stderr,
1338
 
                        "InnoDB: %lu rollback segment(s) active.\n",
1339
 
                        new_rsegs);
1340
 
        }
1341
 
}
1342
 
 
1343
 
#else /* !UNIV_HOTBACKUP */
1344
 
/*****************************************************************//**
1345
 
Prints to stderr the MySQL binlog info in the system header if the
1346
 
magic number shows it valid. */
1347
 
UNIV_INTERN
1348
 
void
1349
 
trx_sys_print_mysql_binlog_offset_from_page(
1350
 
/*========================================*/
1351
 
        const byte*     page)   /*!< in: buffer containing the trx
1352
 
                                system header page, i.e., page number
1353
 
                                TRX_SYS_PAGE_NO in the tablespace */
1354
 
{
1355
 
        const trx_sysf_t*       sys_header;
1356
 
 
1357
 
        sys_header = page + TRX_SYS;
1358
 
 
1359
 
        if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
1360
 
                             + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
1361
 
            == TRX_SYS_MYSQL_LOG_MAGIC_N) {
1362
 
 
1363
 
                fprintf(stderr,
1364
 
                        "ibbackup: Last MySQL binlog file position %lu %lu,"
1365
 
                        " file name %s\n",
1366
 
                        (ulong) mach_read_from_4(
1367
 
                                sys_header + TRX_SYS_MYSQL_LOG_INFO
1368
 
                                + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
1369
 
                        (ulong) mach_read_from_4(
1370
 
                                sys_header + TRX_SYS_MYSQL_LOG_INFO
1371
 
                                + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
1372
 
                        sys_header + TRX_SYS_MYSQL_LOG_INFO
1373
 
                        + TRX_SYS_MYSQL_LOG_NAME);
1374
 
        }
1375
 
}
1376
 
 
1377
 
 
1378
 
/* THESE ARE COPIED FROM NON-HOTBACKUP PART OF THE INNODB SOURCE TREE
1379
 
   (This code duplicaton should be fixed at some point!)
1380
 
*/
1381
 
 
1382
 
#define TRX_SYS_SPACE   0       /* the SYSTEM tablespace */
1383
 
/* The offset of the file format tag on the trx system header page */
1384
 
#define TRX_SYS_FILE_FORMAT_TAG         (UNIV_PAGE_SIZE - 16)
1385
 
/* We use these random constants to reduce the probability of reading
1386
 
garbage (from previous versions) that maps to an actual format id. We
1387
 
use these as bit masks at the time of  reading and writing from/to disk. */
1388
 
#define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW     3645922177UL
1389
 
#define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH    2745987765UL
1390
 
 
1391
 
/* END OF COPIED DEFINITIONS */
1392
 
 
1393
 
 
1394
 
/*****************************************************************//**
1395
 
Reads the file format id from the first system table space file.
1396
 
Even if the call succeeds and returns TRUE, the returned format id
1397
 
may be ULINT_UNDEFINED signalling that the format id was not present
1398
 
in the data file.
1399
 
@return TRUE if call succeeds */
1400
 
UNIV_INTERN
1401
 
ibool
1402
 
trx_sys_read_file_format_id(
1403
 
/*========================*/
1404
 
        const char *pathname,  /*!< in: pathname of the first system
1405
 
                                        table space file */
1406
 
        ulint *format_id)      /*!< out: file format of the system table
1407
 
                                         space */
1408
 
{
1409
 
        os_file_t       file;
1410
 
        ibool           success;
1411
 
        byte            buf[UNIV_PAGE_SIZE * 2];
1412
 
        page_t*         page = ut_align(buf, UNIV_PAGE_SIZE);
1413
 
        const byte*     ptr;
1414
 
        ib_id_t         file_format_id;
1415
 
 
1416
 
        *format_id = ULINT_UNDEFINED;
1417
 
 
1418
 
        file = os_file_create_simple_no_error_handling(
1419
 
                innodb_file_data_key,
1420
 
                pathname,
1421
 
                OS_FILE_OPEN,
1422
 
                OS_FILE_READ_ONLY,
1423
 
                &success
1424
 
        );
1425
 
        if (!success) {
1426
 
                /* The following call prints an error message */
1427
 
                os_file_get_last_error(TRUE);
1428
 
 
1429
 
                ut_print_timestamp(stderr);
1430
 
 
1431
 
                fprintf(stderr,
1432
 
"  ibbackup: Error: trying to read system tablespace file format,\n"
1433
 
"  ibbackup: but could not open the tablespace file %s!\n",
1434
 
                        pathname
1435
 
                );
1436
 
                return(FALSE);
1437
 
        }
1438
 
 
1439
 
        /* Read the page on which file format is stored */
1440
 
 
1441
 
        success = os_file_read_no_error_handling(
1442
 
                file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, 0, UNIV_PAGE_SIZE
1443
 
        );
1444
 
        if (!success) {
1445
 
                /* The following call prints an error message */
1446
 
                os_file_get_last_error(TRUE);
1447
 
 
1448
 
                ut_print_timestamp(stderr);
1449
 
 
1450
 
                fprintf(stderr,
1451
 
"  ibbackup: Error: trying to read system table space file format,\n"
1452
 
"  ibbackup: but failed to read the tablespace file %s!\n",
1453
 
                        pathname
1454
 
                );
1455
 
                os_file_close(file);
1456
 
                return(FALSE);
1457
 
        }
1458
 
        os_file_close(file);
1459
 
 
1460
 
        /* get the file format from the page */
1461
 
        ptr = page + TRX_SYS_FILE_FORMAT_TAG;
1462
 
        file_format_id = mach_read_from_8(ptr);
1463
 
        file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
1464
 
 
1465
 
        if (file_format_id >= FILE_FORMAT_NAME_N) {
1466
 
 
1467
 
                /* Either it has never been tagged, or garbage in it. */
1468
 
                return(TRUE);
1469
 
        }
1470
 
 
1471
 
        *format_id = (ulint) file_format_id;
1472
 
 
1473
 
        return(TRUE);
1474
 
}
1475
 
 
1476
 
 
1477
 
/*****************************************************************//**
1478
 
Reads the file format id from the given per-table data file.
1479
 
@return TRUE if call succeeds */
1480
 
UNIV_INTERN
1481
 
ibool
1482
 
trx_sys_read_pertable_file_format_id(
1483
 
/*=================================*/
1484
 
        const char *pathname,  /*!< in: pathname of a per-table
1485
 
                                        datafile */
1486
 
        ulint *format_id)      /*!< out: file format of the per-table
1487
 
                                         data file */
1488
 
{
1489
 
        os_file_t       file;
1490
 
        ibool           success;
1491
 
        byte            buf[UNIV_PAGE_SIZE * 2];
1492
 
        page_t*         page = ut_align(buf, UNIV_PAGE_SIZE);
1493
 
        const byte*     ptr;
1494
 
        ib_uint32_t     flags;
1495
 
 
1496
 
        *format_id = ULINT_UNDEFINED;
1497
 
 
1498
 
        file = os_file_create_simple_no_error_handling(
1499
 
                innodb_file_data_key,
1500
 
                pathname,
1501
 
                OS_FILE_OPEN,
1502
 
                OS_FILE_READ_ONLY,
1503
 
                &success
1504
 
        );
1505
 
        if (!success) {
1506
 
                /* The following call prints an error message */
1507
 
                os_file_get_last_error(TRUE);
1508
 
        
1509
 
                ut_print_timestamp(stderr);
1510
 
        
1511
 
                fprintf(stderr,
1512
 
"  ibbackup: Error: trying to read per-table tablespace format,\n"
1513
 
"  ibbackup: but could not open the tablespace file %s!\n",
1514
 
                        pathname
1515
 
                );
1516
 
                return(FALSE);
1517
 
        }
1518
 
 
1519
 
        /* Read the first page of the per-table datafile */
1520
 
 
1521
 
        success = os_file_read_no_error_handling(
1522
 
                file, page, 0, 0, UNIV_PAGE_SIZE
1523
 
        );
1524
 
        if (!success) {
1525
 
                /* The following call prints an error message */
1526
 
                os_file_get_last_error(TRUE);
1527
 
        
1528
 
                ut_print_timestamp(stderr);
1529
 
        
1530
 
                fprintf(stderr,
1531
 
"  ibbackup: Error: trying to per-table data file format,\n"
1532
 
"  ibbackup: but failed to read the tablespace file %s!\n",
1533
 
                        pathname
1534
 
                );
1535
 
                os_file_close(file);
1536
 
                return(FALSE);
1537
 
        }
1538
 
        os_file_close(file);
1539
 
 
1540
 
        /* get the file format from the page */
1541
 
        ptr = page + 54;
1542
 
        flags = mach_read_from_4(ptr);
1543
 
        if (flags == 0) {
1544
 
                /* file format is Antelope */
1545
 
                *format_id = 0;
1546
 
                return (TRUE);
1547
 
        } else if (flags & 1) {
1548
 
                /* tablespace flags are ok */
1549
 
                *format_id = (flags / 32) % 128;
1550
 
                return (TRUE);
1551
 
        } else {
1552
 
                /* bad tablespace flags */
1553
 
                return(FALSE);
1554
 
        }
1555
 
}
1556
 
 
1557
 
 
1558
 
/*****************************************************************//**
1559
 
Get the name representation of the file format from its id.
1560
 
@return pointer to the name */
1561
 
UNIV_INTERN
1562
 
const char*
1563
 
trx_sys_file_format_id_to_name(
1564
 
/*===========================*/
1565
 
        const ulint     id)     /*!< in: id of the file format */
1566
 
{
1567
 
        if (!(id < FILE_FORMAT_NAME_N)) {
1568
 
                /* unknown id */
1569
 
                return ("Unknown");
1570
 
        }
1571
 
 
1572
 
        return(file_format_name_map[id]);
1573
 
}
1574
 
 
1575
 
#endif /* !UNIV_HOTBACKUP */
1576
 
 
1577
 
#ifndef UNIV_HOTBACKUP
1578
 
/*********************************************************************
1579
 
Shutdown/Close the transaction system. */
1580
 
UNIV_INTERN
1581
 
void
1582
 
trx_sys_close(void)
1583
 
/*===============*/
1584
 
{
1585
 
        trx_rseg_t*     rseg;
1586
 
        read_view_t*    view;
1587
 
 
1588
 
        ut_ad(trx_sys != NULL);
1589
 
 
1590
 
        /* Check that all read views are closed except read view owned
1591
 
        by a purge. */
1592
 
 
1593
 
        if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
1594
 
                fprintf(stderr,
1595
 
                        "InnoDB: Error: all read views were not closed"
1596
 
                        " before shutdown:\n"
1597
 
                        "InnoDB: %lu read views open \n",
1598
 
                        UT_LIST_GET_LEN(trx_sys->view_list) - 1);
1599
 
        }
1600
 
 
1601
 
        sess_close(trx_dummy_sess);
1602
 
        trx_dummy_sess = NULL;
1603
 
 
1604
 
        trx_purge_sys_close();
1605
 
 
1606
 
        mutex_enter(&kernel_mutex);
1607
 
 
1608
 
        /* Free the double write data structures. */
1609
 
        ut_a(trx_doublewrite != NULL);
1610
 
        ut_free(trx_doublewrite->write_buf_unaligned);
1611
 
        trx_doublewrite->write_buf_unaligned = NULL;
1612
 
 
1613
 
        mem_free(trx_doublewrite->buf_block_arr);
1614
 
        trx_doublewrite->buf_block_arr = NULL;
1615
 
 
1616
 
        mutex_free(&trx_doublewrite->mutex);
1617
 
        mem_free(trx_doublewrite);
1618
 
        trx_doublewrite = NULL;
1619
 
 
1620
 
        /* There can't be any active transactions. */
1621
 
        rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
1622
 
 
1623
 
        while (rseg != NULL) {
1624
 
                trx_rseg_t*     prev_rseg = rseg;
1625
 
 
1626
 
                rseg = UT_LIST_GET_NEXT(rseg_list, prev_rseg);
1627
 
                UT_LIST_REMOVE(rseg_list, trx_sys->rseg_list, prev_rseg);
1628
 
 
1629
 
                trx_rseg_mem_free(prev_rseg);
1630
 
        }
1631
 
 
1632
 
        view = UT_LIST_GET_FIRST(trx_sys->view_list);
1633
 
 
1634
 
        while (view != NULL) {
1635
 
                read_view_t*    prev_view = view;
1636
 
 
1637
 
                view = UT_LIST_GET_NEXT(view_list, prev_view);
1638
 
 
1639
 
                /* Views are allocated from the trx_sys->global_read_view_heap.
1640
 
                So, we simply remove the element here. */
1641
 
                UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
1642
 
        }
1643
 
 
1644
 
        ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == 0);
1645
 
        ut_a(UT_LIST_GET_LEN(trx_sys->rseg_list) == 0);
1646
 
        ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
1647
 
        ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
1648
 
 
1649
 
        mem_free(trx_sys);
1650
 
 
1651
 
        trx_sys = NULL;
1652
 
        mutex_exit(&kernel_mutex);
1653
 
}
1654
 
#endif /* !UNIV_HOTBACKUP */