1
/*****************************************************************************
3
Copyright (C) 1996, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
23
Created 3/26/1996 Heikki Tuuri
24
*******************************************************/
29
#include "trx0undo.ic"
33
#ifndef UNIV_HOTBACKUP
34
#include "mach0data.h"
40
#include "trx0purge.h"
42
/* How should the old versions in the history list be managed?
43
----------------------------------------------------------
44
If each transaction is given a whole page for its update undo log, file
45
space consumption can be 10 times higher than necessary. Therefore,
46
partly filled update undo log pages should be reusable. But then there
47
is no way individual pages can be ordered so that the ordering agrees
48
with the serialization numbers of the transactions on the pages. Thus,
49
the history list must be formed of undo logs, not their header pages as
50
it was in the old implementation.
51
However, on a single header page the transactions are placed in
52
the order of their serialization numbers. As old versions are purged, we
53
may free the page when the last transaction on the page has been purged.
54
A problem is that the purge has to go through the transactions
55
in the serialization order. This means that we have to look through all
56
rollback segments for the one that has the smallest transaction number
58
When should we do a purge? A purge is necessary when space is
59
running out in any of the rollback segments. Then we may have to purge
60
also old version which might be needed by some consistent read. How do
61
we trigger the start of a purge? When a transaction writes to an undo log,
62
it may notice that the space is running out. When a read view is closed,
63
it may make some history superfluous. The server can have an utility which
64
periodically checks if it can purge some history.
65
In a parallellized purge we have the problem that a query thread
66
can remove a delete marked clustered index record before another query
67
thread has processed an earlier version of the record, which cannot then
68
be done because the row cannot be constructed from the clustered index
69
record. To avoid this problem, we will store in the update and delete mark
70
undo record also the columns necessary to construct the secondary index
71
entries which are modified.
72
We can latch the stack of versions of a single clustered index record
73
by taking a latch on the clustered index page. As long as the latch is held,
74
no new versions can be added and no versions removed by undo. But, a purge
75
can still remove old versions from the bottom of the stack. */
77
/* How to protect rollback segments, undo logs, and history lists with
78
-------------------------------------------------------------------
81
The contention of the kernel mutex should be minimized. When a transaction
82
does its first insert or modify in an index, an undo log is assigned for it.
83
Then we must have an x-latch to the rollback segment header.
84
When the transaction does more modifys or rolls back, the undo log is
85
protected with undo_mutex in the transaction.
86
When the transaction commits, its insert undo log is either reset and
87
cached for a fast reuse, or freed. In these cases we must have an x-latch on
88
the rollback segment page. The update undo log is put to the history list. If
89
it is not suitable for reuse, its slot in the rollback segment is reset. In
90
both cases, an x-latch must be acquired on the rollback segment.
91
The purge operation steps through the history list without modifying
92
it until a truncate operation occurs, which can remove undo logs from the end
93
of the list and release undo log segments. In stepping through the list,
94
s-latches on the undo log pages are enough, but in a truncate, x-latches must
95
be obtained on the rollback segment and individual pages. */
96
#endif /* !UNIV_HOTBACKUP */
98
/********************************************************************//**
99
Initializes the fields in an undo log segment page. */
104
page_t* undo_page, /*!< in: undo log segment page */
105
ulint type, /*!< in: undo log segment type */
106
mtr_t* mtr); /*!< in: mtr */
108
#ifndef UNIV_HOTBACKUP
109
/********************************************************************//**
110
Creates and initializes an undo log memory object.
111
@return own: the undo log memory object */
116
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
117
ulint id, /*!< in: slot index within rseg */
118
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
120
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
122
const XID* xid, /*!< in: X/Open XA transaction identification*/
123
ulint page_no,/*!< in: undo log header page number */
124
ulint offset);/*!< in: undo log header byte offset on page */
125
#endif /* !UNIV_HOTBACKUP */
126
/***************************************************************//**
127
Initializes a cached insert undo log header page for new use. NOTE that this
128
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
129
the operation of this function!
130
@return undo log header byte offset on page */
133
trx_undo_insert_header_reuse(
134
/*=========================*/
135
page_t* undo_page, /*!< in/out: insert undo log segment
136
header page, x-latched */
137
trx_id_t trx_id, /*!< in: transaction id */
138
mtr_t* mtr); /*!< in: mtr */
139
/**********************************************************************//**
140
If an update undo log can be discarded immediately, this function frees the
141
space, resetting the page to the proper state for caching. */
144
trx_undo_discard_latest_update_undo(
145
/*================================*/
146
page_t* undo_page, /*!< in: header page of an undo log of size 1 */
147
mtr_t* mtr); /*!< in: mtr */
149
#ifndef UNIV_HOTBACKUP
150
/***********************************************************************//**
151
Gets the previous record in an undo log from the previous page.
152
@return undo log record, the page s-latched, NULL if none */
155
trx_undo_get_prev_rec_from_prev_page(
156
/*=================================*/
157
trx_undo_rec_t* rec, /*!< in: undo record */
158
ulint page_no,/*!< in: undo log header page number */
159
ulint offset, /*!< in: undo log header offset on page */
160
mtr_t* mtr) /*!< in: mtr */
168
undo_page = page_align(rec);
170
prev_page_no = flst_get_prev_addr(undo_page + TRX_UNDO_PAGE_HDR
171
+ TRX_UNDO_PAGE_NODE, mtr)
174
if (prev_page_no == FIL_NULL) {
179
space = page_get_space_id(undo_page);
180
zip_size = fil_space_get_zip_size(space);
182
prev_page = trx_undo_page_get_s_latched(space, zip_size,
185
return(trx_undo_page_get_last_rec(prev_page, page_no, offset));
188
/***********************************************************************//**
189
Gets the previous record in an undo log.
190
@return undo log record, the page s-latched, NULL if none */
193
trx_undo_get_prev_rec(
194
/*==================*/
195
trx_undo_rec_t* rec, /*!< in: undo record */
196
ulint page_no,/*!< in: undo log header page number */
197
ulint offset, /*!< in: undo log header offset on page */
198
mtr_t* mtr) /*!< in: mtr */
200
trx_undo_rec_t* prev_rec;
202
prev_rec = trx_undo_page_get_prev_rec(rec, page_no, offset);
209
/* We have to go to the previous undo log page to look for the
212
return(trx_undo_get_prev_rec_from_prev_page(rec, page_no, offset,
216
/***********************************************************************//**
217
Gets the next record in an undo log from the next page.
218
@return undo log record, the page latched, NULL if none */
221
trx_undo_get_next_rec_from_next_page(
222
/*=================================*/
223
ulint space, /*!< in: undo log header space */
224
ulint zip_size,/*!< in: compressed page size in bytes
225
or 0 for uncompressed pages */
226
page_t* undo_page, /*!< in: undo log page */
227
ulint page_no,/*!< in: undo log header page number */
228
ulint offset, /*!< in: undo log header offset on page */
229
ulint mode, /*!< in: latch mode: RW_S_LATCH or RW_X_LATCH */
230
mtr_t* mtr) /*!< in: mtr */
232
trx_ulogf_t* log_hdr;
237
if (page_no == page_get_page_no(undo_page)) {
239
log_hdr = undo_page + offset;
240
next = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
248
next_page_no = flst_get_next_addr(undo_page + TRX_UNDO_PAGE_HDR
249
+ TRX_UNDO_PAGE_NODE, mtr)
251
if (next_page_no == FIL_NULL) {
256
if (mode == RW_S_LATCH) {
257
next_page = trx_undo_page_get_s_latched(space, zip_size,
260
ut_ad(mode == RW_X_LATCH);
261
next_page = trx_undo_page_get(space, zip_size,
265
return(trx_undo_page_get_first_rec(next_page, page_no, offset));
268
/***********************************************************************//**
269
Gets the next record in an undo log.
270
@return undo log record, the page s-latched, NULL if none */
273
trx_undo_get_next_rec(
274
/*==================*/
275
trx_undo_rec_t* rec, /*!< in: undo record */
276
ulint page_no,/*!< in: undo log header page number */
277
ulint offset, /*!< in: undo log header offset on page */
278
mtr_t* mtr) /*!< in: mtr */
282
trx_undo_rec_t* next_rec;
284
next_rec = trx_undo_page_get_next_rec(rec, page_no, offset);
290
space = page_get_space_id(page_align(rec));
291
zip_size = fil_space_get_zip_size(space);
293
return(trx_undo_get_next_rec_from_next_page(space, zip_size,
299
/***********************************************************************//**
300
Gets the first record in an undo log.
301
@return undo log record, the page latched, NULL if none */
304
trx_undo_get_first_rec(
305
/*===================*/
306
ulint space, /*!< in: undo log header space */
307
ulint zip_size,/*!< in: compressed page size in bytes
308
or 0 for uncompressed pages */
309
ulint page_no,/*!< in: undo log header page number */
310
ulint offset, /*!< in: undo log header offset on page */
311
ulint mode, /*!< in: latching mode: RW_S_LATCH or RW_X_LATCH */
312
mtr_t* mtr) /*!< in: mtr */
317
if (mode == RW_S_LATCH) {
318
undo_page = trx_undo_page_get_s_latched(space, zip_size,
321
undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
324
rec = trx_undo_page_get_first_rec(undo_page, page_no, offset);
330
return(trx_undo_get_next_rec_from_next_page(space, zip_size,
331
undo_page, page_no, offset,
335
/*============== UNDO LOG FILE COPY CREATION AND FREEING ==================*/
337
/**********************************************************************//**
338
Writes the mtr log entry of an undo log page initialization. */
341
trx_undo_page_init_log(
342
/*===================*/
343
page_t* undo_page, /*!< in: undo log page */
344
ulint type, /*!< in: undo log type */
345
mtr_t* mtr) /*!< in: mtr */
347
mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
349
mlog_catenate_ulint_compressed(mtr, type);
351
#else /* !UNIV_HOTBACKUP */
352
# define trx_undo_page_init_log(undo_page,type,mtr) ((void) 0)
353
#endif /* !UNIV_HOTBACKUP */
355
/***********************************************************//**
356
Parses the redo log entry of an undo log page initialization.
357
@return end of log record or NULL */
360
trx_undo_parse_page_init(
361
/*=====================*/
362
byte* ptr, /*!< in: buffer */
363
byte* end_ptr,/*!< in: buffer end */
364
page_t* page, /*!< in: page or NULL */
365
mtr_t* mtr) /*!< in: mtr or NULL */
369
ptr = mach_parse_compressed(ptr, end_ptr, &type);
377
trx_undo_page_init(page, type, mtr);
383
/********************************************************************//**
384
Initializes the fields in an undo log segment page. */
389
page_t* undo_page, /*!< in: undo log segment page */
390
ulint type, /*!< in: undo log segment type */
391
mtr_t* mtr) /*!< in: mtr */
393
trx_upagef_t* page_hdr;
395
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
397
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_TYPE, type);
399
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
400
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
401
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
402
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
404
fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
406
trx_undo_page_init_log(undo_page, type, mtr);
409
#ifndef UNIV_HOTBACKUP
410
/***************************************************************//**
411
Creates a new undo log segment in file.
412
@return DB_SUCCESS if page creation OK possible error codes are:
413
DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE */
418
trx_rseg_t* /*rseg*/,/*!< in: rollback segment */
419
trx_rsegf_t* rseg_hdr,/*!< in: rollback segment header, page
421
ulint type, /*!< in: type of the segment: TRX_UNDO_INSERT or
423
ulint* id, /*!< out: slot index within rseg header */
425
/*!< out: segment header page x-latched, NULL
426
if there was an error */
427
mtr_t* mtr) /*!< in: mtr */
432
trx_upagef_t* page_hdr;
433
trx_usegf_t* seg_hdr;
436
ulint err = DB_SUCCESS;
438
ut_ad(mtr && id && rseg_hdr);
439
ut_ad(mutex_own(&(rseg->mutex)));
441
/* fputs(type == TRX_UNDO_INSERT
442
? "Creating insert undo log segment\n"
443
: "Creating update undo log segment\n", stderr); */
444
slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
446
if (slot_no == ULINT_UNDEFINED) {
447
ut_print_timestamp(stderr);
449
" InnoDB: Warning: cannot find a free slot for"
450
" an undo log. Do you have too\n"
451
"InnoDB: many active transactions"
452
" running concurrently?\n");
454
return(DB_TOO_MANY_CONCURRENT_TRXS);
457
space = page_get_space_id(page_align(rseg_hdr));
459
success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
463
return(DB_OUT_OF_FILE_SPACE);
466
/* Allocate a new file segment for the undo log */
467
block = fseg_create_general(space, 0,
469
+ TRX_UNDO_FSEG_HEADER, TRUE, mtr);
471
fil_space_release_free_extents(space, n_reserved);
476
return(DB_OUT_OF_FILE_SPACE);
479
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
481
*undo_page = buf_block_get_frame(block);
483
page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
484
seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
486
trx_undo_page_init(*undo_page, type, mtr);
488
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
489
TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
492
mlog_write_ulint(seg_hdr + TRX_UNDO_LAST_LOG, 0, MLOG_2BYTES, mtr);
494
flst_init(seg_hdr + TRX_UNDO_PAGE_LIST, mtr);
496
flst_add_last(seg_hdr + TRX_UNDO_PAGE_LIST,
497
page_hdr + TRX_UNDO_PAGE_NODE, mtr);
499
trx_rsegf_set_nth_undo(rseg_hdr, slot_no,
500
page_get_page_no(*undo_page), mtr);
506
/**********************************************************************//**
507
Writes the mtr log entry of an undo log header initialization. */
510
trx_undo_header_create_log(
511
/*=======================*/
512
const page_t* undo_page, /*!< in: undo log header page */
513
trx_id_t trx_id, /*!< in: transaction id */
514
mtr_t* mtr) /*!< in: mtr */
516
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_CREATE, mtr);
518
mlog_catenate_ull_compressed(mtr, trx_id);
520
#else /* !UNIV_HOTBACKUP */
521
# define trx_undo_header_create_log(undo_page,trx_id,mtr) ((void) 0)
522
#endif /* !UNIV_HOTBACKUP */
524
/***************************************************************//**
525
Creates a new undo log header in file. NOTE that this function has its own
526
log record type MLOG_UNDO_HDR_CREATE. You must NOT change the operation of
528
@return header byte offset on page */
531
trx_undo_header_create(
532
/*===================*/
533
page_t* undo_page, /*!< in/out: undo log segment
534
header page, x-latched; it is
535
assumed that there is
536
TRX_UNDO_LOG_XA_HDR_SIZE bytes
538
trx_id_t trx_id, /*!< in: transaction id */
539
mtr_t* mtr) /*!< in: mtr */
541
trx_upagef_t* page_hdr;
542
trx_usegf_t* seg_hdr;
543
trx_ulogf_t* log_hdr;
544
trx_ulogf_t* prev_log_hdr;
549
ut_ad(mtr && undo_page);
551
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
552
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
554
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
556
log_hdr = undo_page + free;
558
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
560
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
562
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
564
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
566
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
568
prev_log = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
571
prev_log_hdr = undo_page + prev_log;
573
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, free);
576
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, free);
578
log_hdr = undo_page + free;
580
mach_write_to_2(log_hdr + TRX_UNDO_DEL_MARKS, TRUE);
582
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
583
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
585
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
586
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
588
mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
589
mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
591
/* Write the log record about the header creation */
592
trx_undo_header_create_log(undo_page, trx_id, mtr);
597
#ifndef UNIV_HOTBACKUP
598
/********************************************************************//**
599
Write X/Open XA Transaction Identification (XID) to undo log header */
604
trx_ulogf_t* log_hdr,/*!< in: undo log header */
605
const XID* xid, /*!< in: X/Open XA Transaction Identification */
606
mtr_t* mtr) /*!< in: mtr */
608
mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT,
609
(ulint)xid->formatID, MLOG_4BYTES, mtr);
611
mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN,
612
(ulint)xid->gtrid_length, MLOG_4BYTES, mtr);
614
mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN,
615
(ulint)xid->bqual_length, MLOG_4BYTES, mtr);
617
mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data,
621
/********************************************************************//**
622
Read X/Open XA Transaction Identification (XID) from undo log header */
627
trx_ulogf_t* log_hdr,/*!< in: undo log header */
628
XID* xid) /*!< out: X/Open XA Transaction Identification */
630
xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
633
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
635
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
637
memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE);
640
/***************************************************************//**
641
Adds space for the XA XID after an undo log old-style header. */
644
trx_undo_header_add_space_for_xid(
645
/*==============================*/
646
page_t* undo_page,/*!< in: undo log segment header page */
647
trx_ulogf_t* log_hdr,/*!< in: undo log header */
648
mtr_t* mtr) /*!< in: mtr */
650
trx_upagef_t* page_hdr;
654
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
656
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
658
/* free is now the end offset of the old style undo log header */
660
ut_a(free == (ulint)(log_hdr - undo_page) + TRX_UNDO_LOG_OLD_HDR_SIZE);
662
new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
663
- TRX_UNDO_LOG_OLD_HDR_SIZE);
665
/* Add space for a XID after the header, update the free offset
666
fields on the undo log page and in the undo log header */
668
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
671
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free,
674
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
678
/**********************************************************************//**
679
Writes the mtr log entry of an undo log header reuse. */
682
trx_undo_insert_header_reuse_log(
683
/*=============================*/
684
const page_t* undo_page, /*!< in: undo log header page */
685
trx_id_t trx_id, /*!< in: transaction id */
686
mtr_t* mtr) /*!< in: mtr */
688
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr);
690
mlog_catenate_ull_compressed(mtr, trx_id);
692
#else /* !UNIV_HOTBACKUP */
693
# define trx_undo_insert_header_reuse_log(undo_page,trx_id,mtr) ((void) 0)
694
#endif /* !UNIV_HOTBACKUP */
696
/***********************************************************//**
697
Parses the redo log entry of an undo log page header create or reuse.
698
@return end of log record or NULL */
701
trx_undo_parse_page_header(
702
/*=======================*/
703
ulint type, /*!< in: MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE */
704
byte* ptr, /*!< in: buffer */
705
byte* end_ptr,/*!< in: buffer end */
706
page_t* page, /*!< in: page or NULL */
707
mtr_t* mtr) /*!< in: mtr or NULL */
710
/* Silence a GCC warning about possibly uninitialized variable
711
when mach_ull_parse_compressed() is not inlined. */
713
/* Declare the variable uninitialized in Valgrind, so that the
714
above initialization will not mask any bugs. */
715
UNIV_MEM_INVALID(&trx_id, sizeof trx_id);
717
ptr = mach_ull_parse_compressed(ptr, end_ptr, &trx_id);
725
if (type == MLOG_UNDO_HDR_CREATE) {
726
trx_undo_header_create(page, trx_id, mtr);
728
ut_ad(type == MLOG_UNDO_HDR_REUSE);
729
trx_undo_insert_header_reuse(page, trx_id, mtr);
736
/***************************************************************//**
737
Initializes a cached insert undo log header page for new use. NOTE that this
738
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
739
the operation of this function!
740
@return undo log header byte offset on page */
743
trx_undo_insert_header_reuse(
744
/*=========================*/
745
page_t* undo_page, /*!< in/out: insert undo log segment
746
header page, x-latched */
747
trx_id_t trx_id, /*!< in: transaction id */
748
mtr_t* mtr) /*!< in: mtr */
750
trx_upagef_t* page_hdr;
751
trx_usegf_t* seg_hdr;
752
trx_ulogf_t* log_hdr;
756
ut_ad(mtr && undo_page);
758
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
759
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
761
free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
763
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
765
log_hdr = undo_page + free;
767
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
769
/* Insert undo data is not needed after commit: we may free all
770
the space on the page */
772
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
773
+ TRX_UNDO_PAGE_TYPE)
776
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
778
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
780
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
782
log_hdr = undo_page + free;
784
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
785
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
787
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
788
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
790
/* Write the log record MLOG_UNDO_HDR_REUSE */
791
trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
796
#ifndef UNIV_HOTBACKUP
797
/**********************************************************************//**
798
Writes the redo log entry of an update undo log header discard. */
801
trx_undo_discard_latest_log(
802
/*========================*/
803
page_t* undo_page, /*!< in: undo log header page */
804
mtr_t* mtr) /*!< in: mtr */
806
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_DISCARD, mtr);
808
#else /* !UNIV_HOTBACKUP */
809
# define trx_undo_discard_latest_log(undo_page, mtr) ((void) 0)
810
#endif /* !UNIV_HOTBACKUP */
812
/***********************************************************//**
813
Parses the redo log entry of an undo log page header discard.
814
@return end of log record or NULL */
817
trx_undo_parse_discard_latest(
818
/*==========================*/
819
byte* ptr, /*!< in: buffer */
820
byte* /*end_ptr*/, /*!< in: buffer end */
821
page_t* page, /*!< in: page or NULL */
822
mtr_t* mtr) /*!< in: mtr or NULL */
827
trx_undo_discard_latest_update_undo(page, mtr);
833
/**********************************************************************//**
834
If an update undo log can be discarded immediately, this function frees the
835
space, resetting the page to the proper state for caching. */
838
trx_undo_discard_latest_update_undo(
839
/*================================*/
840
page_t* undo_page, /*!< in: header page of an undo log of size 1 */
841
mtr_t* mtr) /*!< in: mtr */
843
trx_usegf_t* seg_hdr;
844
trx_upagef_t* page_hdr;
845
trx_ulogf_t* log_hdr;
846
trx_ulogf_t* prev_log_hdr;
848
ulint prev_hdr_offset;
850
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
851
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
853
free = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
854
log_hdr = undo_page + free;
856
prev_hdr_offset = mach_read_from_2(log_hdr + TRX_UNDO_PREV_LOG);
858
if (prev_hdr_offset != 0) {
859
prev_log_hdr = undo_page + prev_hdr_offset;
861
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
862
mach_read_from_2(prev_log_hdr
863
+ TRX_UNDO_LOG_START));
864
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, 0);
867
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, free);
869
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_CACHED);
870
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, prev_hdr_offset);
872
trx_undo_discard_latest_log(undo_page, mtr);
875
#ifndef UNIV_HOTBACKUP
876
/********************************************************************//**
877
Tries to add a page to the undo log segment where the undo log is placed.
878
@return page number if success, else FIL_NULL */
883
trx_t* trx, /*!< in: transaction */
884
trx_undo_t* undo, /*!< in: undo log memory object */
885
mtr_t* mtr) /*!< in: mtr which does not have a latch to any
886
undo log page; the caller must have reserved
887
the rollback segment mutex */
896
ut_ad(mutex_own(&(trx->undo_mutex)));
897
ut_ad(!mutex_own(&kernel_mutex));
898
ut_ad(mutex_own(&(trx->rseg->mutex)));
902
if (rseg->curr_size == rseg->max_size) {
907
header_page = trx_undo_page_get(undo->space, undo->zip_size,
908
undo->hdr_page_no, mtr);
910
success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
917
page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
918
+ TRX_UNDO_FSEG_HEADER,
919
undo->top_page_no + 1, FSP_UP,
922
fil_space_release_free_extents(undo->space, n_reserved);
924
if (page_no == FIL_NULL) {
931
undo->last_page_no = page_no;
933
new_page = trx_undo_page_get(undo->space, undo->zip_size,
936
trx_undo_page_init(new_page, undo->type, mtr);
938
flst_add_last(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
939
new_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
946
/********************************************************************//**
947
Frees an undo log page that is not the header page.
948
@return last page number in remaining log */
953
trx_rseg_t* rseg, /*!< in: rollback segment */
954
ibool in_history, /*!< in: TRUE if the undo log is in the history
956
ulint space, /*!< in: space */
957
ulint hdr_page_no, /*!< in: header page number */
958
ulint page_no, /*!< in: page number to free: must not be the
960
mtr_t* mtr) /*!< in: mtr which does not have a latch to any
961
undo log page; the caller must have reserved
962
the rollback segment mutex */
966
fil_addr_t last_addr;
967
trx_rsegf_t* rseg_header;
971
ut_a(hdr_page_no != page_no);
972
ut_ad(!mutex_own(&kernel_mutex));
973
ut_ad(mutex_own(&(rseg->mutex)));
975
zip_size = rseg->zip_size;
977
undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
979
header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
981
flst_remove(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
982
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
984
fseg_free_page(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER,
985
space, page_no, mtr);
987
last_addr = flst_get_last(header_page + TRX_UNDO_SEG_HDR
988
+ TRX_UNDO_PAGE_LIST, mtr);
992
rseg_header = trx_rsegf_get(space, zip_size,
995
hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
997
ut_ad(hist_size > 0);
998
mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
999
hist_size - 1, MLOG_4BYTES, mtr);
1002
return(last_addr.page);
1005
/********************************************************************//**
1006
Frees an undo log page when there is also the memory object for the undo
1010
trx_undo_free_page_in_rollback(
1011
/*===========================*/
1012
trx_t* /*trx*/, /*!< in: transaction */
1013
trx_undo_t* undo, /*!< in: undo log memory copy */
1014
ulint page_no,/*!< in: page number to free: must not be the
1016
mtr_t* mtr) /*!< in: mtr which does not have a latch to any
1017
undo log page; the caller must have reserved
1018
the rollback segment mutex */
1022
ut_ad(undo->hdr_page_no != page_no);
1023
ut_ad(mutex_own(&(trx->undo_mutex)));
1025
last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
1026
undo->hdr_page_no, page_no, mtr);
1028
undo->last_page_no = last_page_no;
1032
/********************************************************************//**
1033
Empties an undo log header page of undo records for that undo log. Other
1034
undo logs may still have records on that page, if it is an update undo log. */
1037
trx_undo_empty_header_page(
1038
/*=======================*/
1039
ulint space, /*!< in: space */
1040
ulint zip_size, /*!< in: compressed page size in bytes
1041
or 0 for uncompressed pages */
1042
ulint hdr_page_no, /*!< in: header page number */
1043
ulint hdr_offset, /*!< in: header offset */
1044
mtr_t* mtr) /*!< in: mtr */
1046
page_t* header_page;
1047
trx_ulogf_t* log_hdr;
1050
header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
1052
log_hdr = header_page + hdr_offset;
1054
end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
1056
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
1059
/***********************************************************************//**
1060
Truncates an undo log from the end. This function is used during a rollback
1061
to free space from an undo log. */
1064
trx_undo_truncate_end(
1065
/*==================*/
1066
trx_t* trx, /*!< in: transaction whose undo log it is */
1067
trx_undo_t* undo, /*!< in: undo log */
1068
undo_no_t limit) /*!< in: all undo records with undo number
1069
>= this value should be truncated */
1073
trx_undo_rec_t* rec;
1074
trx_undo_rec_t* trunc_here;
1077
ut_ad(mutex_own(&(trx->undo_mutex)));
1078
ut_ad(mutex_own(&(trx->rseg->mutex)));
1085
last_page_no = undo->last_page_no;
1087
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1088
last_page_no, &mtr);
1090
rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
1094
if (last_page_no == undo->hdr_page_no) {
1099
trx_undo_free_page_in_rollback(
1100
trx, undo, last_page_no, &mtr);
1104
if (trx_undo_rec_get_undo_no(rec) >= limit) {
1105
/* Truncate at least this record off, maybe
1112
rec = trx_undo_page_get_prev_rec(rec,
1122
mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
1123
+ TRX_UNDO_PAGE_FREE,
1124
trunc_here - undo_page, MLOG_2BYTES, &mtr);
1130
/***********************************************************************//**
1131
Truncates an undo log from the start. This function is used during a purge
1135
trx_undo_truncate_start(
1136
/*====================*/
1137
trx_rseg_t* rseg, /*!< in: rollback segment */
1138
ulint space, /*!< in: space id of the log */
1139
ulint hdr_page_no, /*!< in: header page number */
1140
ulint hdr_offset, /*!< in: header offset on the page */
1141
undo_no_t limit) /*!< in: all undo pages with
1142
undo numbers < this value
1143
should be truncated; NOTE that
1144
the function only frees whole
1145
pages; the header page is not
1146
freed, but emptied, if all the
1147
records there are < limit */
1150
trx_undo_rec_t* rec;
1151
trx_undo_rec_t* last_rec;
1155
ut_ad(mutex_own(&(rseg->mutex)));
1164
rec = trx_undo_get_first_rec(space, rseg->zip_size,
1165
hdr_page_no, hdr_offset,
1175
undo_page = page_align(rec);
1177
last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no,
1179
if (trx_undo_rec_get_undo_no(last_rec) >= limit) {
1186
page_no = page_get_page_no(undo_page);
1188
if (page_no == hdr_page_no) {
1189
trx_undo_empty_header_page(space, rseg->zip_size,
1190
hdr_page_no, hdr_offset,
1193
trx_undo_free_page(rseg, TRUE, space, hdr_page_no,
1202
/**********************************************************************//**
1203
Frees an undo log segment which is not in the history list. */
1208
trx_undo_t* undo) /*!< in: undo log */
1211
fseg_header_t* file_seg;
1212
trx_rsegf_t* rseg_header;
1213
trx_usegf_t* seg_header;
1223
ut_ad(!mutex_own(&kernel_mutex));
1225
mutex_enter(&(rseg->mutex));
1227
seg_header = trx_undo_page_get(undo->space, undo->zip_size,
1229
&mtr) + TRX_UNDO_SEG_HDR;
1231
file_seg = seg_header + TRX_UNDO_FSEG_HEADER;
1233
finished = fseg_free_step(file_seg, &mtr);
1236
/* Update the rseg header */
1237
rseg_header = trx_rsegf_get(
1238
rseg->space, rseg->zip_size, rseg->page_no,
1240
trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL,
1244
mutex_exit(&(rseg->mutex));
1246
} while (!finished);
1249
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
1251
/********************************************************************//**
1252
Creates and initializes an undo log memory object according to the values
1253
in the header in file, when the database is started. The memory object is
1254
inserted in the appropriate list of rseg.
1255
@return own: the undo log memory object */
1258
trx_undo_mem_create_at_db_start(
1259
/*============================*/
1260
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1261
ulint id, /*!< in: slot index within rseg */
1262
ulint page_no,/*!< in: undo log segment page number */
1263
mtr_t* mtr) /*!< in: mtr */
1266
trx_upagef_t* page_header;
1267
trx_usegf_t* seg_header;
1268
trx_ulogf_t* undo_header;
1274
fil_addr_t last_addr;
1276
trx_undo_rec_t* rec;
1278
ibool xid_exists = FALSE;
1280
if (id >= TRX_RSEG_N_SLOTS) {
1282
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1286
undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
1289
page_header = undo_page + TRX_UNDO_PAGE_HDR;
1291
type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES,
1293
seg_header = undo_page + TRX_UNDO_SEG_HDR;
1295
state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
1297
offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG);
1299
undo_header = undo_page + offset;
1301
trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
1303
xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1306
/* Read X/Open XA transaction identification if it exists, or
1309
memset(&xid, 0, sizeof(xid));
1312
if (xid_exists == TRUE) {
1313
trx_undo_read_xid(undo_header, &xid);
1316
mutex_enter(&(rseg->mutex));
1318
undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
1320
mutex_exit(&(rseg->mutex));
1322
undo->dict_operation = mtr_read_ulint(
1323
undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr);
1325
undo->table_id = mach_read_from_8(undo_header + TRX_UNDO_TABLE_ID);
1326
undo->state = state;
1327
undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1329
/* If the log segment is being freed, the page list is inconsistent! */
1330
if (state == TRX_UNDO_TO_FREE) {
1335
last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1337
undo->last_page_no = last_addr.page;
1338
undo->top_page_no = last_addr.page;
1340
last_page = trx_undo_page_get(rseg->space, rseg->zip_size,
1341
undo->last_page_no, mtr);
1343
rec = trx_undo_page_get_last_rec(last_page, page_no, offset);
1348
undo->empty = FALSE;
1349
undo->top_offset = rec - last_page;
1350
undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
1353
if (type == TRX_UNDO_INSERT) {
1354
if (state != TRX_UNDO_CACHED) {
1355
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list,
1358
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_cached,
1362
ut_ad(type == TRX_UNDO_UPDATE);
1363
if (state != TRX_UNDO_CACHED) {
1364
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_list,
1367
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_cached,
1375
/********************************************************************//**
1376
Initializes the undo log lists for a rollback segment memory copy. This
1377
function is only called when the database is started or a new rollback
1379
@return the combined size of undo log segments in pages */
1382
trx_undo_lists_init(
1383
/*================*/
1384
trx_rseg_t* rseg) /*!< in: rollback segment memory object */
1389
trx_rsegf_t* rseg_header;
1393
UT_LIST_INIT(rseg->update_undo_list);
1394
UT_LIST_INIT(rseg->update_undo_cached);
1395
UT_LIST_INIT(rseg->insert_undo_list);
1396
UT_LIST_INIT(rseg->insert_undo_cached);
1400
rseg_header = trx_rsegf_get_new(rseg->space, rseg->zip_size,
1401
rseg->page_no, &mtr);
1403
for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
1404
page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr);
1406
/* In forced recovery: try to avoid operations which look
1407
at database pages; undo logs are rapidly changing data, and
1408
the probability that they are in an inconsistent state is
1411
if (page_no != FIL_NULL
1412
&& srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
1414
undo = trx_undo_mem_create_at_db_start(rseg, i,
1422
rseg_header = trx_rsegf_get(
1423
rseg->space, rseg->zip_size, rseg->page_no,
1433
/********************************************************************//**
1434
Creates and initializes an undo log memory object.
1435
@return own: the undo log memory object */
1438
trx_undo_mem_create(
1439
/*================*/
1440
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1441
ulint id, /*!< in: slot index within rseg */
1442
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
1444
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1446
const XID* xid, /*!< in: X/Open transaction identification */
1447
ulint page_no,/*!< in: undo log header page number */
1448
ulint offset) /*!< in: undo log header byte offset on page */
1452
ut_ad(mutex_own(&(rseg->mutex)));
1454
if (id >= TRX_RSEG_N_SLOTS) {
1456
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1460
undo = static_cast<trx_undo_t *>(mem_alloc(sizeof(trx_undo_t)));
1469
undo->state = TRX_UNDO_ACTIVE;
1470
undo->del_marks = FALSE;
1471
undo->trx_id = trx_id;
1474
undo->dict_operation = FALSE;
1478
undo->space = rseg->space;
1479
undo->zip_size = rseg->zip_size;
1480
undo->hdr_page_no = page_no;
1481
undo->hdr_offset = offset;
1482
undo->last_page_no = page_no;
1486
undo->top_page_no = page_no;
1487
undo->guess_block = NULL;
1492
/********************************************************************//**
1493
Initializes a cached undo log object for new use. */
1496
trx_undo_mem_init_for_reuse(
1497
/*========================*/
1498
trx_undo_t* undo, /*!< in: undo log to init */
1499
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1501
const XID* xid, /*!< in: X/Open XA transaction identification*/
1502
ulint offset) /*!< in: undo log header byte offset on page */
1504
ut_ad(mutex_own(&((undo->rseg)->mutex)));
1506
if (UNIV_UNLIKELY(undo->id >= TRX_RSEG_N_SLOTS)) {
1507
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1510
mem_analyze_corruption(undo);
1514
undo->state = TRX_UNDO_ACTIVE;
1515
undo->del_marks = FALSE;
1516
undo->trx_id = trx_id;
1519
undo->dict_operation = FALSE;
1521
undo->hdr_offset = offset;
1525
/********************************************************************//**
1526
Frees an undo log memory copy. */
1531
trx_undo_t* undo) /*!< in: the undo object to be freed */
1533
if (undo->id >= TRX_RSEG_N_SLOTS) {
1535
"InnoDB: Error: undo->id is %lu\n", (ulong) undo->id);
1542
/**********************************************************************//**
1543
Creates a new undo log.
1544
@return DB_SUCCESS if successful in creating the new undo lob object,
1545
possible error codes are: DB_TOO_MANY_CONCURRENT_TRXS
1546
DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY */
1551
trx_t* trx, /*!< in: transaction */
1552
trx_rseg_t* rseg, /*!< in: rollback segment memory copy */
1553
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
1555
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1557
const XID* xid, /*!< in: X/Open transaction identification*/
1558
trx_undo_t** undo, /*!< out: the new undo log object, undefined
1559
* if did not succeed */
1560
mtr_t* mtr) /*!< in: mtr */
1562
trx_rsegf_t* rseg_header;
1569
ut_ad(mutex_own(&(rseg->mutex)));
1571
if (rseg->curr_size == rseg->max_size) {
1573
return(DB_OUT_OF_FILE_SPACE);
1578
rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size, rseg->page_no,
1581
err = trx_undo_seg_create(rseg, rseg_header, type, &id,
1584
if (err != DB_SUCCESS) {
1585
/* Did not succeed */
1592
page_no = page_get_page_no(undo_page);
1594
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1596
if (trx->support_xa) {
1597
trx_undo_header_add_space_for_xid(undo_page,
1598
undo_page + offset, mtr);
1601
*undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
1603
if (*undo == NULL) {
1605
err = DB_OUT_OF_MEMORY;
1611
/*================ UNDO LOG ASSIGNMENT AND CLEANUP =====================*/
1613
/********************************************************************//**
1614
Reuses a cached undo log.
1615
@return the undo log memory object, NULL if none cached */
1618
trx_undo_reuse_cached(
1619
/*==================*/
1620
trx_t* trx, /*!< in: transaction */
1621
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1622
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
1624
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1626
const XID* xid, /*!< in: X/Open XA transaction identification */
1627
mtr_t* mtr) /*!< in: mtr */
1633
ut_ad(mutex_own(&(rseg->mutex)));
1635
if (type == TRX_UNDO_INSERT) {
1637
undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
1643
UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo);
1645
ut_ad(type == TRX_UNDO_UPDATE);
1647
undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
1653
UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo);
1656
ut_ad(undo->size == 1);
1658
if (undo->id >= TRX_RSEG_N_SLOTS) {
1659
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1661
mem_analyze_corruption(undo);
1665
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1666
undo->hdr_page_no, mtr);
1668
if (type == TRX_UNDO_INSERT) {
1669
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
1671
if (trx->support_xa) {
1672
trx_undo_header_add_space_for_xid(
1673
undo_page, undo_page + offset, mtr);
1676
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
1677
+ TRX_UNDO_PAGE_TYPE)
1678
== TRX_UNDO_UPDATE);
1680
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1682
if (trx->support_xa) {
1683
trx_undo_header_add_space_for_xid(
1684
undo_page, undo_page + offset, mtr);
1688
trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
1693
/**********************************************************************//**
1694
Marks an undo log header as a header of a data dictionary operation
1698
trx_undo_mark_as_dict_operation(
1699
/*============================*/
1700
trx_t* trx, /*!< in: dict op transaction */
1701
trx_undo_t* undo, /*!< in: assigned undo log */
1702
mtr_t* mtr) /*!< in: mtr */
1706
hdr_page = trx_undo_page_get(undo->space, undo->zip_size,
1707
undo->hdr_page_no, mtr);
1709
switch (trx_get_dict_operation(trx)) {
1710
case TRX_DICT_OP_NONE:
1712
case TRX_DICT_OP_INDEX:
1713
/* Do not discard the table on recovery. */
1716
case TRX_DICT_OP_TABLE:
1717
undo->table_id = trx->table_id;
1721
mlog_write_ulint(hdr_page + undo->hdr_offset
1722
+ TRX_UNDO_DICT_TRANS,
1723
TRUE, MLOG_1BYTE, mtr);
1725
mlog_write_ull(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
1726
undo->table_id, mtr);
1728
undo->dict_operation = TRUE;
1731
/**********************************************************************//**
1732
Assigns an undo log for a transaction. A new undo log is created or a cached
1734
@return DB_SUCCESS if undo log assign successful, possible error codes
1735
are: DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE
1739
trx_undo_assign_undo(
1740
/*=================*/
1741
trx_t* trx, /*!< in: transaction */
1742
ulint type) /*!< in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
1747
ulint err = DB_SUCCESS;
1754
ut_ad(mutex_own(&(trx->undo_mutex)));
1758
ut_ad(!mutex_own(&kernel_mutex));
1760
mutex_enter(&(rseg->mutex));
1762
undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
1765
err = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
1767
if (err != DB_SUCCESS) {
1773
if (type == TRX_UNDO_INSERT) {
1774
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_list, undo);
1775
ut_ad(trx->insert_undo == NULL);
1776
trx->insert_undo = undo;
1778
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_list, undo);
1779
ut_ad(trx->update_undo == NULL);
1780
trx->update_undo = undo;
1783
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
1784
trx_undo_mark_as_dict_operation(trx, undo, &mtr);
1788
mutex_exit(&(rseg->mutex));
1794
/******************************************************************//**
1795
Sets the state of the undo log segment at a transaction finish.
1796
@return undo log segment header page, x-latched */
1799
trx_undo_set_state_at_finish(
1800
/*=========================*/
1801
trx_undo_t* undo, /*!< in: undo log memory copy */
1802
mtr_t* mtr) /*!< in: mtr */
1804
trx_usegf_t* seg_hdr;
1805
trx_upagef_t* page_hdr;
1812
if (undo->id >= TRX_RSEG_N_SLOTS) {
1813
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1815
mem_analyze_corruption(undo);
1819
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1820
undo->hdr_page_no, mtr);
1822
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1823
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1826
&& mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE)
1827
< TRX_UNDO_PAGE_REUSE_LIMIT) {
1829
state = TRX_UNDO_CACHED;
1831
} else if (undo->type == TRX_UNDO_INSERT) {
1833
state = TRX_UNDO_TO_FREE;
1835
state = TRX_UNDO_TO_PURGE;
1838
undo->state = state;
1840
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr);
1845
/******************************************************************//**
1846
Sets the state of the undo log segment at a transaction prepare.
1847
@return undo log segment header page, x-latched */
1850
trx_undo_set_state_at_prepare(
1851
/*==========================*/
1852
trx_t* trx, /*!< in: transaction */
1853
trx_undo_t* undo, /*!< in: undo log memory copy */
1854
mtr_t* mtr) /*!< in: mtr */
1856
trx_usegf_t* seg_hdr;
1857
trx_ulogf_t* undo_header;
1861
ut_ad(trx && undo && mtr);
1863
if (undo->id >= TRX_RSEG_N_SLOTS) {
1864
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1866
mem_analyze_corruption(undo);
1870
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1871
undo->hdr_page_no, mtr);
1873
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1875
/*------------------------------*/
1876
undo->state = TRX_UNDO_PREPARED;
1877
undo->xid = trx->xid;
1878
/*------------------------------*/
1880
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
1883
offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
1884
undo_header = undo_page + offset;
1886
mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1887
TRUE, MLOG_1BYTE, mtr);
1889
trx_undo_write_xid(undo_header, &undo->xid, mtr);
1894
/**********************************************************************//**
1895
Adds the update undo log header as the first in the history list, and
1896
frees the memory object, or puts it to the list of cached update undo log
1900
trx_undo_update_cleanup(
1901
/*====================*/
1902
trx_t* trx, /*!< in: trx owning the update undo log */
1903
page_t* undo_page, /*!< in: update undo log header page,
1905
mtr_t* mtr) /*!< in: mtr */
1910
undo = trx->update_undo;
1913
ut_ad(mutex_own(&(rseg->mutex)));
1915
trx_purge_add_update_undo_to_history(trx, undo_page, mtr);
1917
UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo);
1919
trx->update_undo = NULL;
1921
if (undo->state == TRX_UNDO_CACHED) {
1923
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo);
1925
ut_ad(undo->state == TRX_UNDO_TO_PURGE
1926
|| undo->state == TRX_UNDO_TO_FREE);
1928
trx_undo_mem_free(undo);
1932
/******************************************************************//**
1933
Frees or caches an insert undo log after a transaction commit or rollback.
1934
Knowledge of inserts is not needed after a commit or rollback, therefore
1935
the data can be discarded. */
1938
trx_undo_insert_cleanup(
1939
/*====================*/
1940
trx_t* trx) /*!< in: transaction handle */
1945
undo = trx->insert_undo;
1950
mutex_enter(&(rseg->mutex));
1952
UT_LIST_REMOVE(undo_list, rseg->insert_undo_list, undo);
1953
trx->insert_undo = NULL;
1955
if (undo->state == TRX_UNDO_CACHED) {
1957
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_cached, undo);
1959
ut_ad(undo->state == TRX_UNDO_TO_FREE);
1961
/* Delete first the undo log segment in the file */
1963
mutex_exit(&(rseg->mutex));
1965
trx_undo_seg_free(undo);
1967
mutex_enter(&(rseg->mutex));
1969
ut_ad(rseg->curr_size > undo->size);
1971
rseg->curr_size -= undo->size;
1973
trx_undo_mem_free(undo);
1976
mutex_exit(&(rseg->mutex));
1978
#endif /* !UNIV_HOTBACKUP */