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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/******************************************************
22
Created 3/26/1996 Heikki Tuuri
23
*******************************************************/
28
#include "trx0undo.ic"
32
#ifndef UNIV_HOTBACKUP
33
#include "mach0data.h"
38
#include "trx0purge.h"
40
/* How should the old versions in the history list be managed?
41
----------------------------------------------------------
42
If each transaction is given a whole page for its update undo log, file
43
space consumption can be 10 times higher than necessary. Therefore,
44
partly filled update undo log pages should be reusable. But then there
45
is no way individual pages can be ordered so that the ordering agrees
46
with the serialization numbers of the transactions on the pages. Thus,
47
the history list must be formed of undo logs, not their header pages as
48
it was in the old implementation.
49
However, on a single header page the transactions are placed in
50
the order of their serialization numbers. As old versions are purged, we
51
may free the page when the last transaction on the page has been purged.
52
A problem is that the purge has to go through the transactions
53
in the serialization order. This means that we have to look through all
54
rollback segments for the one that has the smallest transaction number
56
When should we do a purge? A purge is necessary when space is
57
running out in any of the rollback segments. Then we may have to purge
58
also old version which might be needed by some consistent read. How do
59
we trigger the start of a purge? When a transaction writes to an undo log,
60
it may notice that the space is running out. When a read view is closed,
61
it may make some history superfluous. The server can have an utility which
62
periodically checks if it can purge some history.
63
In a parallellized purge we have the problem that a query thread
64
can remove a delete marked clustered index record before another query
65
thread has processed an earlier version of the record, which cannot then
66
be done because the row cannot be constructed from the clustered index
67
record. To avoid this problem, we will store in the update and delete mark
68
undo record also the columns necessary to construct the secondary index
69
entries which are modified.
70
We can latch the stack of versions of a single clustered index record
71
by taking a latch on the clustered index page. As long as the latch is held,
72
no new versions can be added and no versions removed by undo. But, a purge
73
can still remove old versions from the bottom of the stack. */
75
/* How to protect rollback segments, undo logs, and history lists with
76
-------------------------------------------------------------------
79
The contention of the kernel mutex should be minimized. When a transaction
80
does its first insert or modify in an index, an undo log is assigned for it.
81
Then we must have an x-latch to the rollback segment header.
82
When the transaction does more modifys or rolls back, the undo log is
83
protected with undo_mutex in the transaction.
84
When the transaction commits, its insert undo log is either reset and
85
cached for a fast reuse, or freed. In these cases we must have an x-latch on
86
the rollback segment page. The update undo log is put to the history list. If
87
it is not suitable for reuse, its slot in the rollback segment is reset. In
88
both cases, an x-latch must be acquired on the rollback segment.
89
The purge operation steps through the history list without modifying
90
it until a truncate operation occurs, which can remove undo logs from the end
91
of the list and release undo log segments. In stepping through the list,
92
s-latches on the undo log pages are enough, but in a truncate, x-latches must
93
be obtained on the rollback segment and individual pages. */
94
#endif /* !UNIV_HOTBACKUP */
96
/************************************************************************
97
Initializes the fields in an undo log segment page. */
102
page_t* undo_page, /* in: undo log segment page */
103
ulint type, /* in: undo log segment type */
104
mtr_t* mtr); /* in: mtr */
106
#ifndef UNIV_HOTBACKUP
107
/************************************************************************
108
Creates and initializes an undo log memory object. */
113
/* out, own: the undo log memory object */
114
trx_rseg_t* rseg, /* in: rollback segment memory object */
115
ulint id, /* in: slot index within rseg */
116
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
118
dulint trx_id, /* in: id of the trx for which the undo log
120
const XID* xid, /* in: X/Open XA transaction identification*/
121
ulint page_no,/* in: undo log header page number */
122
ulint offset);/* in: undo log header byte offset on page */
123
#endif /* !UNIV_HOTBACKUP */
124
/*******************************************************************
125
Initializes a cached insert undo log header page for new use. NOTE that this
126
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
127
the operation of this function! */
130
trx_undo_insert_header_reuse(
131
/*=========================*/
132
/* out: undo log header byte offset on page */
133
page_t* undo_page, /* in: insert undo log segment header page,
135
dulint trx_id, /* in: transaction id */
136
mtr_t* mtr); /* in: mtr */
137
/**************************************************************************
138
If an update undo log can be discarded immediately, this function frees the
139
space, resetting the page to the proper state for caching. */
142
trx_undo_discard_latest_update_undo(
143
/*================================*/
144
page_t* undo_page, /* in: header page of an undo log of size 1 */
145
mtr_t* mtr); /* in: mtr */
147
#ifndef UNIV_HOTBACKUP
148
/***************************************************************************
149
Gets the previous record in an undo log from the previous page. */
152
trx_undo_get_prev_rec_from_prev_page(
153
/*=================================*/
154
/* out: undo log record, the page s-latched,
156
trx_undo_rec_t* rec, /* in: undo record */
157
ulint page_no,/* in: undo log header page number */
158
ulint offset, /* in: undo log header offset on page */
159
mtr_t* mtr) /* in: mtr */
167
undo_page = page_align(rec);
169
prev_page_no = flst_get_prev_addr(undo_page + TRX_UNDO_PAGE_HDR
170
+ TRX_UNDO_PAGE_NODE, mtr)
173
if (prev_page_no == FIL_NULL) {
178
space = page_get_space_id(undo_page);
179
zip_size = fil_space_get_zip_size(space);
181
prev_page = trx_undo_page_get_s_latched(space, zip_size,
184
return(trx_undo_page_get_last_rec(prev_page, page_no, offset));
187
/***************************************************************************
188
Gets the previous record in an undo log. */
191
trx_undo_get_prev_rec(
192
/*==================*/
193
/* out: undo log record, the page s-latched,
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. */
220
trx_undo_get_next_rec_from_next_page(
221
/*=================================*/
222
/* out: undo log record, the page latched, NULL if
224
ulint space, /* in: undo log header space */
225
ulint zip_size,/* in: compressed page size in bytes
226
or 0 for uncompressed pages */
227
page_t* undo_page, /* in: undo log page */
228
ulint page_no,/* in: undo log header page number */
229
ulint offset, /* in: undo log header offset on page */
230
ulint mode, /* in: latch mode: RW_S_LATCH or RW_X_LATCH */
231
mtr_t* mtr) /* in: mtr */
233
trx_ulogf_t* log_hdr;
238
if (page_no == page_get_page_no(undo_page)) {
240
log_hdr = undo_page + offset;
241
next = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
249
next_page_no = flst_get_next_addr(undo_page + TRX_UNDO_PAGE_HDR
250
+ TRX_UNDO_PAGE_NODE, mtr)
252
if (next_page_no == FIL_NULL) {
257
if (mode == RW_S_LATCH) {
258
next_page = trx_undo_page_get_s_latched(space, zip_size,
261
ut_ad(mode == RW_X_LATCH);
262
next_page = trx_undo_page_get(space, zip_size,
266
return(trx_undo_page_get_first_rec(next_page, page_no, offset));
269
/***************************************************************************
270
Gets the next record in an undo log. */
273
trx_undo_get_next_rec(
274
/*==================*/
275
/* out: undo log record, the page s-latched,
277
trx_undo_rec_t* rec, /* in: undo record */
278
ulint page_no,/* in: undo log header page number */
279
ulint offset, /* in: undo log header offset on page */
280
mtr_t* mtr) /* in: mtr */
284
trx_undo_rec_t* next_rec;
286
next_rec = trx_undo_page_get_next_rec(rec, page_no, offset);
292
space = page_get_space_id(page_align(rec));
293
zip_size = fil_space_get_zip_size(space);
295
return(trx_undo_get_next_rec_from_next_page(space, zip_size,
301
/***************************************************************************
302
Gets the first record in an undo log. */
305
trx_undo_get_first_rec(
306
/*===================*/
307
/* out: undo log record, the page latched, NULL if
309
ulint space, /* in: undo log header space */
310
ulint zip_size,/* in: compressed page size in bytes
311
or 0 for uncompressed pages */
312
ulint page_no,/* in: undo log header page number */
313
ulint offset, /* in: undo log header offset on page */
314
ulint mode, /* in: latching mode: RW_S_LATCH or RW_X_LATCH */
315
mtr_t* mtr) /* in: mtr */
320
if (mode == RW_S_LATCH) {
321
undo_page = trx_undo_page_get_s_latched(space, zip_size,
324
undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
327
rec = trx_undo_page_get_first_rec(undo_page, page_no, offset);
333
return(trx_undo_get_next_rec_from_next_page(space, zip_size,
334
undo_page, page_no, offset,
338
/*============== UNDO LOG FILE COPY CREATION AND FREEING ==================*/
340
/**************************************************************************
341
Writes the mtr log entry of an undo log page initialization. */
344
trx_undo_page_init_log(
345
/*===================*/
346
page_t* undo_page, /* in: undo log page */
347
ulint type, /* in: undo log type */
348
mtr_t* mtr) /* in: mtr */
350
mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
352
mlog_catenate_ulint_compressed(mtr, type);
354
#else /* !UNIV_HOTBACKUP */
355
# define trx_undo_page_init_log(undo_page,type,mtr) ((void) 0)
356
#endif /* !UNIV_HOTBACKUP */
358
/***************************************************************
359
Parses the redo log entry of an undo log page initialization. */
362
trx_undo_parse_page_init(
363
/*=====================*/
364
/* out: end of log record or NULL */
365
byte* ptr, /* in: buffer */
366
byte* end_ptr,/* in: buffer end */
367
page_t* page, /* in: page or NULL */
368
mtr_t* mtr) /* in: mtr or NULL */
372
ptr = mach_parse_compressed(ptr, end_ptr, &type);
380
trx_undo_page_init(page, type, mtr);
386
/************************************************************************
387
Initializes the fields in an undo log segment page. */
392
page_t* undo_page, /* in: undo log segment page */
393
ulint type, /* in: undo log segment type */
394
mtr_t* mtr) /* in: mtr */
396
trx_upagef_t* page_hdr;
398
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
400
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_TYPE, type);
402
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
403
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
404
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
405
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
407
fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
409
trx_undo_page_init_log(undo_page, type, mtr);
412
#ifndef UNIV_HOTBACKUP
413
/*******************************************************************
414
Creates a new undo log segment in file. */
419
/* out: DB_SUCCESS if page creation OK
420
possible error codes are:
421
DB_TOO_MANY_CONCURRENT_TRXS
422
DB_OUT_OF_FILE_SPACE */
423
trx_rseg_t* rseg __attribute__((unused)),/* in: rollback segment */
424
trx_rsegf_t* rseg_hdr,/* in: rollback segment header, page
426
ulint type, /* in: type of the segment: TRX_UNDO_INSERT or
428
ulint* id, /* out: slot index within rseg header */
430
/* out: segment header page x-latched, NULL
431
if there was an error */
432
mtr_t* mtr) /* in: mtr */
437
trx_upagef_t* page_hdr;
438
trx_usegf_t* seg_hdr;
441
ulint err = DB_SUCCESS;
443
ut_ad(mtr && id && rseg_hdr);
444
ut_ad(mutex_own(&(rseg->mutex)));
446
/* fputs(type == TRX_UNDO_INSERT
447
? "Creating insert undo log segment\n"
448
: "Creating update undo log segment\n", stderr); */
449
slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
451
if (slot_no == ULINT_UNDEFINED) {
452
ut_print_timestamp(stderr);
454
" InnoDB: Warning: cannot find a free slot for"
455
" an undo log. Do you have too\n"
456
"InnoDB: many active transactions"
457
" running concurrently?\n");
459
return(DB_TOO_MANY_CONCURRENT_TRXS);
462
space = page_get_space_id(page_align(rseg_hdr));
464
success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
468
return(DB_OUT_OF_FILE_SPACE);
471
/* Allocate a new file segment for the undo log */
472
block = fseg_create_general(space, 0,
474
+ TRX_UNDO_FSEG_HEADER, TRUE, mtr);
476
fil_space_release_free_extents(space, n_reserved);
481
return(DB_OUT_OF_FILE_SPACE);
484
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
486
*undo_page = buf_block_get_frame(block);
488
page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
489
seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
491
trx_undo_page_init(*undo_page, type, mtr);
493
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
494
TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
497
mlog_write_ulint(seg_hdr + TRX_UNDO_LAST_LOG, 0, MLOG_2BYTES, mtr);
499
flst_init(seg_hdr + TRX_UNDO_PAGE_LIST, mtr);
501
flst_add_last(seg_hdr + TRX_UNDO_PAGE_LIST,
502
page_hdr + TRX_UNDO_PAGE_NODE, mtr);
504
trx_rsegf_set_nth_undo(rseg_hdr, slot_no,
505
page_get_page_no(*undo_page), mtr);
511
/**************************************************************************
512
Writes the mtr log entry of an undo log header initialization. */
515
trx_undo_header_create_log(
516
/*=======================*/
517
page_t* undo_page, /* in: undo log header page */
518
dulint trx_id, /* in: transaction id */
519
mtr_t* mtr) /* in: mtr */
521
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_CREATE, mtr);
523
mlog_catenate_dulint_compressed(mtr, trx_id);
525
#else /* !UNIV_HOTBACKUP */
526
# define trx_undo_header_create_log(undo_page,trx_id,mtr) ((void) 0)
527
#endif /* !UNIV_HOTBACKUP */
529
/*******************************************************************
530
Creates a new undo log header in file. NOTE that this function has its own
531
log record type MLOG_UNDO_HDR_CREATE. You must NOT change the operation of
535
trx_undo_header_create(
536
/*===================*/
537
/* out: header byte offset on page */
538
page_t* undo_page, /* in: undo log segment header page,
539
x-latched; it is assumed that there are
540
TRX_UNDO_LOG_XA_HDR_SIZE bytes free space
542
dulint trx_id, /* in: transaction id */
543
mtr_t* mtr) /* in: mtr */
545
trx_upagef_t* page_hdr;
546
trx_usegf_t* seg_hdr;
547
trx_ulogf_t* log_hdr;
548
trx_ulogf_t* prev_log_hdr;
553
ut_ad(mtr && undo_page);
555
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
556
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
558
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
560
log_hdr = undo_page + free;
562
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
564
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
566
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
568
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
570
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
572
prev_log = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
575
prev_log_hdr = undo_page + prev_log;
577
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, free);
580
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, free);
582
log_hdr = undo_page + free;
584
mach_write_to_2(log_hdr + TRX_UNDO_DEL_MARKS, TRUE);
586
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
587
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
589
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
590
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
592
mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
593
mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
595
/* Write the log record about the header creation */
596
trx_undo_header_create_log(undo_page, trx_id, mtr);
601
#ifndef UNIV_HOTBACKUP
602
/************************************************************************
603
Write X/Open XA Transaction Identification (XID) to undo log header */
608
trx_ulogf_t* log_hdr,/* in: undo log header */
609
const XID* xid, /* in: X/Open XA Transaction Identification */
610
mtr_t* mtr) /* in: mtr */
612
mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT,
613
(ulint)xid->formatID, MLOG_4BYTES, mtr);
615
mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN,
616
(ulint)xid->gtrid_length, MLOG_4BYTES, mtr);
618
mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN,
619
(ulint)xid->bqual_length, MLOG_4BYTES, mtr);
621
mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data,
625
/************************************************************************
626
Read X/Open XA Transaction Identification (XID) from undo log header */
631
trx_ulogf_t* log_hdr,/* in: undo log header */
632
XID* xid) /* out: X/Open XA Transaction Identification */
634
xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
637
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
639
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
641
memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE);
644
/*******************************************************************
645
Adds space for the XA XID after an undo log old-style header. */
648
trx_undo_header_add_space_for_xid(
649
/*==============================*/
650
page_t* undo_page,/* in: undo log segment header page */
651
trx_ulogf_t* log_hdr,/* in: undo log header */
652
mtr_t* mtr) /* in: mtr */
654
trx_upagef_t* page_hdr;
658
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
660
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
662
/* free is now the end offset of the old style undo log header */
664
ut_a(free == (ulint)(log_hdr - undo_page) + TRX_UNDO_LOG_OLD_HDR_SIZE);
666
new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
667
- TRX_UNDO_LOG_OLD_HDR_SIZE);
669
/* Add space for a XID after the header, update the free offset
670
fields on the undo log page and in the undo log header */
672
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
675
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free,
678
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
682
/**************************************************************************
683
Writes the mtr log entry of an undo log header reuse. */
686
trx_undo_insert_header_reuse_log(
687
/*=============================*/
688
page_t* undo_page, /* in: undo log header page */
689
dulint trx_id, /* in: transaction id */
690
mtr_t* mtr) /* in: mtr */
692
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr);
694
mlog_catenate_dulint_compressed(mtr, trx_id);
696
#else /* !UNIV_HOTBACKUP */
697
# define trx_undo_insert_header_reuse_log(undo_page,trx_id,mtr) ((void) 0)
698
#endif /* !UNIV_HOTBACKUP */
700
/***************************************************************
701
Parses the redo log entry of an undo log page header create or reuse. */
704
trx_undo_parse_page_header(
705
/*=======================*/
706
/* out: end of log record or NULL */
707
ulint type, /* in: MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE */
708
byte* ptr, /* in: buffer */
709
byte* end_ptr,/* in: buffer end */
710
page_t* page, /* in: page or NULL */
711
mtr_t* mtr) /* in: mtr or NULL */
715
ptr = mach_dulint_parse_compressed(ptr, end_ptr, &trx_id);
723
if (type == MLOG_UNDO_HDR_CREATE) {
724
trx_undo_header_create(page, trx_id, mtr);
726
ut_ad(type == MLOG_UNDO_HDR_REUSE);
727
trx_undo_insert_header_reuse(page, trx_id, mtr);
734
/*******************************************************************
735
Initializes a cached insert undo log header page for new use. NOTE that this
736
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
737
the operation of this function! */
740
trx_undo_insert_header_reuse(
741
/*=========================*/
742
/* out: undo log header byte offset on page */
743
page_t* undo_page, /* in: insert undo log segment header page,
745
dulint trx_id, /* in: transaction id */
746
mtr_t* mtr) /* in: mtr */
748
trx_upagef_t* page_hdr;
749
trx_usegf_t* seg_hdr;
750
trx_ulogf_t* log_hdr;
754
ut_ad(mtr && undo_page);
756
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
757
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
759
free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
761
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
763
log_hdr = undo_page + free;
765
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
767
/* Insert undo data is not needed after commit: we may free all
768
the space on the page */
770
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
771
+ TRX_UNDO_PAGE_TYPE)
774
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
776
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
778
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
780
log_hdr = undo_page + free;
782
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
783
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
785
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
786
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
788
/* Write the log record MLOG_UNDO_HDR_REUSE */
789
trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
794
#ifndef UNIV_HOTBACKUP
795
/**************************************************************************
796
Writes the redo log entry of an update undo log header discard. */
799
trx_undo_discard_latest_log(
800
/*========================*/
801
page_t* undo_page, /* in: undo log header page */
802
mtr_t* mtr) /* in: mtr */
804
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_DISCARD, mtr);
806
#else /* !UNIV_HOTBACKUP */
807
# define trx_undo_discard_latest_log(undo_page, mtr) ((void) 0)
808
#endif /* !UNIV_HOTBACKUP */
810
/***************************************************************
811
Parses the redo log entry of an undo log page header discard. */
814
trx_undo_parse_discard_latest(
815
/*==========================*/
816
/* out: end of log record or NULL */
817
byte* ptr, /* in: buffer */
818
byte* end_ptr __attribute__((unused)), /* in: buffer end */
819
page_t* page, /* in: page or NULL */
820
mtr_t* mtr) /* in: mtr or NULL */
825
trx_undo_discard_latest_update_undo(page, mtr);
831
/**************************************************************************
832
If an update undo log can be discarded immediately, this function frees the
833
space, resetting the page to the proper state for caching. */
836
trx_undo_discard_latest_update_undo(
837
/*================================*/
838
page_t* undo_page, /* in: header page of an undo log of size 1 */
839
mtr_t* mtr) /* in: mtr */
841
trx_usegf_t* seg_hdr;
842
trx_upagef_t* page_hdr;
843
trx_ulogf_t* log_hdr;
844
trx_ulogf_t* prev_log_hdr;
846
ulint prev_hdr_offset;
848
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
849
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
851
free = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
852
log_hdr = undo_page + free;
854
prev_hdr_offset = mach_read_from_2(log_hdr + TRX_UNDO_PREV_LOG);
856
if (prev_hdr_offset != 0) {
857
prev_log_hdr = undo_page + prev_hdr_offset;
859
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
860
mach_read_from_2(prev_log_hdr
861
+ TRX_UNDO_LOG_START));
862
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, 0);
865
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, free);
867
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_CACHED);
868
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, prev_hdr_offset);
870
trx_undo_discard_latest_log(undo_page, mtr);
873
#ifndef UNIV_HOTBACKUP
874
/************************************************************************
875
Tries to add a page to the undo log segment where the undo log is placed. */
880
/* out: page number if success, else
882
trx_t* trx, /* in: transaction */
883
trx_undo_t* undo, /* in: undo log memory object */
884
mtr_t* mtr) /* in: mtr which does not have a latch to any
885
undo log page; the caller must have reserved
886
the rollback segment mutex */
895
ut_ad(mutex_own(&(trx->undo_mutex)));
896
ut_ad(!mutex_own(&kernel_mutex));
897
ut_ad(mutex_own(&(trx->rseg->mutex)));
901
if (rseg->curr_size == rseg->max_size) {
906
header_page = trx_undo_page_get(undo->space, undo->zip_size,
907
undo->hdr_page_no, mtr);
909
success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
916
page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
917
+ TRX_UNDO_FSEG_HEADER,
918
undo->top_page_no + 1, FSP_UP,
921
fil_space_release_free_extents(undo->space, n_reserved);
923
if (page_no == FIL_NULL) {
930
undo->last_page_no = page_no;
932
new_page = trx_undo_page_get(undo->space, undo->zip_size,
935
trx_undo_page_init(new_page, undo->type, mtr);
937
flst_add_last(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
938
new_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
945
/************************************************************************
946
Frees an undo log page that is not the header page. */
951
/* out: last page number in remaining log */
952
trx_rseg_t* rseg, /* in: rollback segment */
953
ibool in_history, /* in: TRUE if the undo log is in the history
955
ulint space, /* in: space */
956
ulint hdr_page_no, /* in: header page number */
957
ulint page_no, /* in: page number to free: must not be the
959
mtr_t* mtr) /* in: mtr which does not have a latch to any
960
undo log page; the caller must have reserved
961
the rollback segment mutex */
965
fil_addr_t last_addr;
966
trx_rsegf_t* rseg_header;
970
ut_a(hdr_page_no != page_no);
971
ut_ad(!mutex_own(&kernel_mutex));
972
ut_ad(mutex_own(&(rseg->mutex)));
974
zip_size = rseg->zip_size;
976
undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
978
header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
980
flst_remove(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
981
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
983
fseg_free_page(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER,
984
space, page_no, mtr);
986
last_addr = flst_get_last(header_page + TRX_UNDO_SEG_HDR
987
+ TRX_UNDO_PAGE_LIST, mtr);
991
rseg_header = trx_rsegf_get(space, zip_size,
994
hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
996
ut_ad(hist_size > 0);
997
mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
998
hist_size - 1, MLOG_4BYTES, mtr);
1001
return(last_addr.page);
1004
/************************************************************************
1005
Frees an undo log page when there is also the memory object for the undo
1009
trx_undo_free_page_in_rollback(
1010
/*===========================*/
1011
trx_t* trx __attribute__((unused)), /* in: transaction */
1012
trx_undo_t* undo, /* in: undo log memory copy */
1013
ulint page_no,/* in: page number to free: must not be the
1015
mtr_t* mtr) /* in: mtr which does not have a latch to any
1016
undo log page; the caller must have reserved
1017
the rollback segment mutex */
1021
ut_ad(undo->hdr_page_no != page_no);
1022
ut_ad(mutex_own(&(trx->undo_mutex)));
1024
last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
1025
undo->hdr_page_no, page_no, mtr);
1027
undo->last_page_no = last_page_no;
1031
/************************************************************************
1032
Empties an undo log header page of undo records for that undo log. Other
1033
undo logs may still have records on that page, if it is an update undo log. */
1036
trx_undo_empty_header_page(
1037
/*=======================*/
1038
ulint space, /* in: space */
1039
ulint zip_size, /* in: compressed page size in bytes
1040
or 0 for uncompressed pages */
1041
ulint hdr_page_no, /* in: header page number */
1042
ulint hdr_offset, /* in: header offset */
1043
mtr_t* mtr) /* in: mtr */
1045
page_t* header_page;
1046
trx_ulogf_t* log_hdr;
1049
header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
1051
log_hdr = header_page + hdr_offset;
1053
end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
1055
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
1058
/***************************************************************************
1059
Truncates an undo log from the end. This function is used during a rollback
1060
to free space from an undo log. */
1063
trx_undo_truncate_end(
1064
/*==================*/
1065
trx_t* trx, /* in: transaction whose undo log it is */
1066
trx_undo_t* undo, /* in: undo log */
1067
dulint limit) /* in: all undo records with undo number
1068
>= this value should be truncated */
1072
trx_undo_rec_t* rec;
1073
trx_undo_rec_t* trunc_here;
1077
ut_ad(mutex_own(&(trx->undo_mutex)));
1078
ut_ad(mutex_own(&(trx->rseg->mutex)));
1087
last_page_no = undo->last_page_no;
1089
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1090
last_page_no, &mtr);
1092
rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
1096
if (last_page_no == undo->hdr_page_no) {
1101
trx_undo_free_page_in_rollback(
1102
trx, undo, last_page_no, &mtr);
1106
if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit)
1108
/* Truncate at least this record off, maybe
1115
rec = trx_undo_page_get_prev_rec(rec,
1125
mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
1126
+ TRX_UNDO_PAGE_FREE,
1127
trunc_here - undo_page, MLOG_2BYTES, &mtr);
1133
/***************************************************************************
1134
Truncates an undo log from the start. This function is used during a purge
1138
trx_undo_truncate_start(
1139
/*====================*/
1140
trx_rseg_t* rseg, /* in: rollback segment */
1141
ulint space, /* in: space id of the log */
1142
ulint hdr_page_no, /* in: header page number */
1143
ulint hdr_offset, /* in: header offset on the page */
1144
dulint limit) /* in: all undo pages with undo numbers <
1145
this value should be truncated; NOTE that
1146
the function only frees whole pages; the
1147
header page is not freed, but emptied, if
1148
all the records there are < limit */
1151
trx_undo_rec_t* rec;
1152
trx_undo_rec_t* last_rec;
1156
ut_ad(mutex_own(&(rseg->mutex)));
1158
if (ut_dulint_is_zero(limit)) {
1165
rec = trx_undo_get_first_rec(space, rseg->zip_size,
1166
hdr_page_no, hdr_offset,
1176
undo_page = page_align(rec);
1178
last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no,
1180
if (ut_dulint_cmp(trx_undo_rec_get_undo_no(last_rec), limit) >= 0) {
1187
page_no = page_get_page_no(undo_page);
1189
if (page_no == hdr_page_no) {
1190
trx_undo_empty_header_page(space, rseg->zip_size,
1191
hdr_page_no, hdr_offset,
1194
trx_undo_free_page(rseg, TRUE, space, hdr_page_no,
1203
/**************************************************************************
1204
Frees an undo log segment which is not in the history list. */
1209
trx_undo_t* undo) /* in: undo log */
1212
fseg_header_t* file_seg;
1213
trx_rsegf_t* rseg_header;
1214
trx_usegf_t* seg_header;
1224
ut_ad(!mutex_own(&kernel_mutex));
1226
mutex_enter(&(rseg->mutex));
1228
seg_header = trx_undo_page_get(undo->space, undo->zip_size,
1230
&mtr) + TRX_UNDO_SEG_HDR;
1232
file_seg = seg_header + TRX_UNDO_FSEG_HEADER;
1234
finished = fseg_free_step(file_seg, &mtr);
1237
/* Update the rseg header */
1238
rseg_header = trx_rsegf_get(
1239
rseg->space, rseg->zip_size, rseg->page_no,
1241
trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL,
1245
mutex_exit(&(rseg->mutex));
1247
} while (!finished);
1250
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
1252
/************************************************************************
1253
Creates and initializes an undo log memory object according to the values
1254
in the header in file, when the database is started. The memory object is
1255
inserted in the appropriate list of rseg. */
1258
trx_undo_mem_create_at_db_start(
1259
/*============================*/
1260
/* out, own: the undo log memory object */
1261
trx_rseg_t* rseg, /* in: rollback segment memory object */
1262
ulint id, /* in: slot index within rseg */
1263
ulint page_no,/* in: undo log segment page number */
1264
mtr_t* mtr) /* in: mtr */
1267
trx_upagef_t* page_header;
1268
trx_usegf_t* seg_header;
1269
trx_ulogf_t* undo_header;
1275
fil_addr_t last_addr;
1277
trx_undo_rec_t* rec;
1279
ibool xid_exists = FALSE;
1281
if (id >= TRX_RSEG_N_SLOTS) {
1283
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1287
undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
1290
page_header = undo_page + TRX_UNDO_PAGE_HDR;
1292
type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES,
1294
seg_header = undo_page + TRX_UNDO_SEG_HDR;
1296
state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
1298
offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG);
1300
undo_header = undo_page + offset;
1302
trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr);
1304
xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1307
/* Read X/Open XA transaction identification if it exists, or
1310
memset(&xid, 0, sizeof(xid));
1313
if (xid_exists == TRUE) {
1314
trx_undo_read_xid(undo_header, &xid);
1317
mutex_enter(&(rseg->mutex));
1319
undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
1321
mutex_exit(&(rseg->mutex));
1323
undo->dict_operation = mtr_read_ulint(
1324
undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr);
1326
undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr);
1327
undo->state = state;
1328
undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1330
/* If the log segment is being freed, the page list is inconsistent! */
1331
if (state == TRX_UNDO_TO_FREE) {
1336
last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1338
undo->last_page_no = last_addr.page;
1339
undo->top_page_no = last_addr.page;
1341
last_page = trx_undo_page_get(rseg->space, rseg->zip_size,
1342
undo->last_page_no, mtr);
1344
rec = trx_undo_page_get_last_rec(last_page, page_no, offset);
1349
undo->empty = FALSE;
1350
undo->top_offset = rec - last_page;
1351
undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
1354
if (type == TRX_UNDO_INSERT) {
1355
if (state != TRX_UNDO_CACHED) {
1356
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list,
1359
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_cached,
1363
ut_ad(type == TRX_UNDO_UPDATE);
1364
if (state != TRX_UNDO_CACHED) {
1365
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_list,
1368
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_cached,
1376
/************************************************************************
1377
Initializes the undo log lists for a rollback segment memory copy. This
1378
function is only called when the database is started or a new rollback
1379
segment is created. */
1382
trx_undo_lists_init(
1383
/*================*/
1384
/* out: the combined size of undo log segments
1386
trx_rseg_t* rseg) /* in: rollback segment memory object */
1391
trx_rsegf_t* rseg_header;
1395
UT_LIST_INIT(rseg->update_undo_list);
1396
UT_LIST_INIT(rseg->update_undo_cached);
1397
UT_LIST_INIT(rseg->insert_undo_list);
1398
UT_LIST_INIT(rseg->insert_undo_cached);
1402
rseg_header = trx_rsegf_get_new(rseg->space, rseg->zip_size,
1403
rseg->page_no, &mtr);
1405
for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
1406
page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr);
1408
/* In forced recovery: try to avoid operations which look
1409
at database pages; undo logs are rapidly changing data, and
1410
the probability that they are in an inconsistent state is
1413
if (page_no != FIL_NULL
1414
&& srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
1416
undo = trx_undo_mem_create_at_db_start(rseg, i,
1424
rseg_header = trx_rsegf_get(
1425
rseg->space, rseg->zip_size, rseg->page_no,
1435
/************************************************************************
1436
Creates and initializes an undo log memory object. */
1439
trx_undo_mem_create(
1440
/*================*/
1441
/* out, own: the undo log memory object */
1442
trx_rseg_t* rseg, /* in: rollback segment memory object */
1443
ulint id, /* in: slot index within rseg */
1444
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
1446
dulint trx_id, /* in: id of the trx for which the undo log
1448
const XID* xid, /* in: X/Open transaction identification */
1449
ulint page_no,/* in: undo log header page number */
1450
ulint offset) /* in: undo log header byte offset on page */
1454
ut_ad(mutex_own(&(rseg->mutex)));
1456
if (id >= TRX_RSEG_N_SLOTS) {
1458
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1462
undo = mem_alloc(sizeof(trx_undo_t));
1471
undo->state = TRX_UNDO_ACTIVE;
1472
undo->del_marks = FALSE;
1473
undo->trx_id = trx_id;
1476
undo->dict_operation = FALSE;
1480
undo->space = rseg->space;
1481
undo->zip_size = rseg->zip_size;
1482
undo->hdr_page_no = page_no;
1483
undo->hdr_offset = offset;
1484
undo->last_page_no = page_no;
1488
undo->top_page_no = page_no;
1489
undo->guess_block = NULL;
1494
/************************************************************************
1495
Initializes a cached undo log object for new use. */
1498
trx_undo_mem_init_for_reuse(
1499
/*========================*/
1500
trx_undo_t* undo, /* in: undo log to init */
1501
dulint trx_id, /* in: id of the trx for which the undo log
1503
const XID* xid, /* in: X/Open XA transaction identification*/
1504
ulint offset) /* in: undo log header byte offset on page */
1506
ut_ad(mutex_own(&((undo->rseg)->mutex)));
1508
if (UNIV_UNLIKELY(undo->id >= TRX_RSEG_N_SLOTS)) {
1509
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1515
undo->state = TRX_UNDO_ACTIVE;
1516
undo->del_marks = FALSE;
1517
undo->trx_id = trx_id;
1520
undo->dict_operation = FALSE;
1522
undo->hdr_offset = offset;
1526
/************************************************************************
1527
Frees an undo log memory copy. */
1532
trx_undo_t* undo) /* in: the undo object to be freed */
1534
if (undo->id >= TRX_RSEG_N_SLOTS) {
1536
"InnoDB: Error: undo->id is %lu\n", (ulong) undo->id);
1543
/**************************************************************************
1544
Creates a new undo log. */
1549
/* out: DB_SUCCESS if successful in creating
1550
the new undo lob object, possible error
1552
DB_TOO_MANY_CONCURRENT_TRXS
1553
DB_OUT_OF_FILE_SPACE
1555
trx_t* trx, /* in: transaction */
1556
trx_rseg_t* rseg, /* in: rollback segment memory copy */
1557
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
1559
dulint trx_id, /* in: id of the trx for which the undo log
1561
const XID* xid, /* in: X/Open transaction identification*/
1562
trx_undo_t** undo, /* out: the new undo log object, undefined
1563
* if did not succeed */
1564
mtr_t* mtr) /* in: mtr */
1566
trx_rsegf_t* rseg_header;
1573
ut_ad(mutex_own(&(rseg->mutex)));
1575
if (rseg->curr_size == rseg->max_size) {
1577
return(DB_OUT_OF_FILE_SPACE);
1582
rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size, rseg->page_no,
1585
err = trx_undo_seg_create(rseg, rseg_header, type, &id,
1588
if (err != DB_SUCCESS) {
1589
/* Did not succeed */
1596
page_no = page_get_page_no(undo_page);
1598
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1600
if (trx->support_xa) {
1601
trx_undo_header_add_space_for_xid(undo_page,
1602
undo_page + offset, mtr);
1605
*undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
1607
if (*undo == NULL) {
1609
err = DB_OUT_OF_MEMORY;
1615
/*================ UNDO LOG ASSIGNMENT AND CLEANUP =====================*/
1617
/************************************************************************
1618
Reuses a cached undo log. */
1621
trx_undo_reuse_cached(
1622
/*==================*/
1623
/* out: the undo log memory object, NULL if
1625
trx_t* trx, /* in: transaction */
1626
trx_rseg_t* rseg, /* in: rollback segment memory object */
1627
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
1629
dulint trx_id, /* in: id of the trx for which the undo log
1631
const XID* xid, /* in: X/Open XA transaction identification */
1632
mtr_t* mtr) /* in: mtr */
1638
ut_ad(mutex_own(&(rseg->mutex)));
1640
if (type == TRX_UNDO_INSERT) {
1642
undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
1648
UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo);
1650
ut_ad(type == TRX_UNDO_UPDATE);
1652
undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
1658
UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo);
1661
ut_ad(undo->size == 1);
1663
if (undo->id >= TRX_RSEG_N_SLOTS) {
1664
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1669
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1670
undo->hdr_page_no, mtr);
1672
if (type == TRX_UNDO_INSERT) {
1673
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
1675
if (trx->support_xa) {
1676
trx_undo_header_add_space_for_xid(
1677
undo_page, undo_page + offset, mtr);
1680
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
1681
+ TRX_UNDO_PAGE_TYPE)
1682
== TRX_UNDO_UPDATE);
1684
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1686
if (trx->support_xa) {
1687
trx_undo_header_add_space_for_xid(
1688
undo_page, undo_page + offset, mtr);
1692
trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
1697
/**************************************************************************
1698
Marks an undo log header as a header of a data dictionary operation
1702
trx_undo_mark_as_dict_operation(
1703
/*============================*/
1704
trx_t* trx, /* in: dict op transaction */
1705
trx_undo_t* undo, /* in: assigned undo log */
1706
mtr_t* mtr) /* in: mtr */
1710
hdr_page = trx_undo_page_get(undo->space, undo->zip_size,
1711
undo->hdr_page_no, mtr);
1713
switch (trx_get_dict_operation(trx)) {
1714
case TRX_DICT_OP_NONE:
1716
case TRX_DICT_OP_INDEX:
1717
/* Do not discard the table on recovery. */
1718
undo->table_id = ut_dulint_zero;
1720
case TRX_DICT_OP_TABLE:
1721
undo->table_id = trx->table_id;
1725
mlog_write_ulint(hdr_page + undo->hdr_offset
1726
+ TRX_UNDO_DICT_TRANS,
1727
TRUE, MLOG_1BYTE, mtr);
1729
mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
1730
undo->table_id, mtr);
1732
undo->dict_operation = TRUE;
1735
/**************************************************************************
1736
Assigns an undo log for a transaction. A new undo log is created or a cached
1740
trx_undo_assign_undo(
1741
/*=================*/
1742
/* out: DB_SUCCESS if undo log assign
1743
successful, possible error codes are:
1744
DB_TOO_MANY_CONCURRENT_TRXS
1745
DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY*/
1746
trx_t* trx, /* in: transaction */
1747
ulint type) /* in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
1752
ulint err = DB_SUCCESS;
1759
ut_ad(mutex_own(&(trx->undo_mutex)));
1763
ut_ad(!mutex_own(&kernel_mutex));
1765
mutex_enter(&(rseg->mutex));
1767
undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
1770
err = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
1772
if (err != DB_SUCCESS) {
1778
if (type == TRX_UNDO_INSERT) {
1779
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_list, undo);
1780
ut_ad(trx->insert_undo == NULL);
1781
trx->insert_undo = undo;
1783
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_list, undo);
1784
ut_ad(trx->update_undo == NULL);
1785
trx->update_undo = undo;
1788
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
1789
trx_undo_mark_as_dict_operation(trx, undo, &mtr);
1793
mutex_exit(&(rseg->mutex));
1799
/**********************************************************************
1800
Sets the state of the undo log segment at a transaction finish. */
1803
trx_undo_set_state_at_finish(
1804
/*=========================*/
1805
/* out: undo log segment header page,
1807
trx_rseg_t* rseg, /* in: rollback segment memory object */
1808
trx_t* trx __attribute__((unused)), /* in: transaction */
1809
trx_undo_t* undo, /* in: undo log memory copy */
1810
mtr_t* mtr) /* in: mtr */
1812
trx_usegf_t* seg_hdr;
1813
trx_upagef_t* page_hdr;
1820
ut_ad(mutex_own(&rseg->mutex));
1822
if (undo->id >= TRX_RSEG_N_SLOTS) {
1823
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1828
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1829
undo->hdr_page_no, mtr);
1831
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1832
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1835
&& mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE)
1836
< TRX_UNDO_PAGE_REUSE_LIMIT) {
1838
/* This is a heuristic to avoid the problem of all UNDO
1839
slots ending up in one of the UNDO lists. Previously if
1840
the server crashed with all the slots in one of the lists,
1841
transactions that required the slots of a different type
1842
would fail for lack of slots. */
1844
if (UT_LIST_GET_LEN(rseg->update_undo_list) < 500
1845
&& UT_LIST_GET_LEN(rseg->insert_undo_list) < 500) {
1847
state = TRX_UNDO_CACHED;
1849
state = TRX_UNDO_TO_FREE;
1852
} else if (undo->type == TRX_UNDO_INSERT) {
1854
state = TRX_UNDO_TO_FREE;
1856
state = TRX_UNDO_TO_PURGE;
1859
undo->state = state;
1861
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr);
1866
/**********************************************************************
1867
Sets the state of the undo log segment at a transaction prepare. */
1870
trx_undo_set_state_at_prepare(
1871
/*==========================*/
1872
/* out: undo log segment header page,
1874
trx_t* trx, /* in: transaction */
1875
trx_undo_t* undo, /* in: undo log memory copy */
1876
mtr_t* mtr) /* in: mtr */
1878
trx_usegf_t* seg_hdr;
1879
trx_upagef_t* page_hdr;
1880
trx_ulogf_t* undo_header;
1884
ut_ad(trx && undo && mtr);
1886
if (undo->id >= TRX_RSEG_N_SLOTS) {
1887
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1892
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1893
undo->hdr_page_no, mtr);
1895
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1896
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1898
/*------------------------------*/
1899
undo->state = TRX_UNDO_PREPARED;
1900
undo->xid = trx->xid;
1901
/*------------------------------*/
1903
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
1906
offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
1907
undo_header = undo_page + offset;
1909
mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1910
TRUE, MLOG_1BYTE, mtr);
1912
trx_undo_write_xid(undo_header, &undo->xid, mtr);
1917
/**************************************************************************
1918
Adds the update undo log header as the first in the history list, and
1919
frees the memory object, or puts it to the list of cached update undo log
1923
trx_undo_update_cleanup(
1924
/*====================*/
1925
trx_t* trx, /* in: trx owning the update undo log */
1926
page_t* undo_page, /* in: update undo log header page,
1928
mtr_t* mtr) /* in: mtr */
1933
undo = trx->update_undo;
1936
ut_ad(mutex_own(&(rseg->mutex)));
1938
trx_purge_add_update_undo_to_history(trx, undo_page, mtr);
1940
UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo);
1942
trx->update_undo = NULL;
1944
if (undo->state == TRX_UNDO_CACHED) {
1946
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo);
1948
ut_ad(undo->state == TRX_UNDO_TO_PURGE);
1950
trx_undo_mem_free(undo);
1954
/**********************************************************************
1955
Frees or caches an insert undo log after a transaction commit or rollback.
1956
Knowledge of inserts is not needed after a commit or rollback, therefore
1957
the data can be discarded. */
1960
trx_undo_insert_cleanup(
1961
/*====================*/
1962
trx_t* trx) /* in: transaction handle */
1967
undo = trx->insert_undo;
1972
mutex_enter(&(rseg->mutex));
1974
UT_LIST_REMOVE(undo_list, rseg->insert_undo_list, undo);
1975
trx->insert_undo = NULL;
1977
if (undo->state == TRX_UNDO_CACHED) {
1979
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_cached, undo);
1981
ut_ad(undo->state == TRX_UNDO_TO_FREE);
1983
/* Delete first the undo log segment in the file */
1985
mutex_exit(&(rseg->mutex));
1987
trx_undo_seg_free(undo);
1989
mutex_enter(&(rseg->mutex));
1991
ut_ad(rseg->curr_size > undo->size);
1993
rseg->curr_size -= undo->size;
1995
trx_undo_mem_free(undo);
1998
mutex_exit(&(rseg->mutex));
2000
#endif /* !UNIV_HOTBACKUP */