1
/******************************************************
6
Created 3/26/1996 Heikki Tuuri
7
*******************************************************/
12
#include "trx0undo.ic"
16
#include "mach0data.h"
21
#include "trx0purge.h"
24
/* How should the old versions in the history list be managed?
25
----------------------------------------------------------
26
If each transaction is given a whole page for its update undo log, file
27
space consumption can be 10 times higher than necessary. Therefore,
28
partly filled update undo log pages should be reusable. But then there
29
is no way individual pages can be ordered so that the ordering agrees
30
with the serialization numbers of the transactions on the pages. Thus,
31
the history list must be formed of undo logs, not their header pages as
32
it was in the old implementation.
33
However, on a single header page the transactions are placed in
34
the order of their serialization numbers. As old versions are purged, we
35
may free the page when the last transaction on the page has been purged.
36
A problem is that the purge has to go through the transactions
37
in the serialization order. This means that we have to look through all
38
rollback segments for the one that has the smallest transaction number
40
When should we do a purge? A purge is necessary when space is
41
running out in any of the rollback segments. Then we may have to purge
42
also old version which might be needed by some consistent read. How do
43
we trigger the start of a purge? When a transaction writes to an undo log,
44
it may notice that the space is running out. When a read view is closed,
45
it may make some history superfluous. The server can have an utility which
46
periodically checks if it can purge some history.
47
In a parallellized purge we have the problem that a query thread
48
can remove a delete marked clustered index record before another query
49
thread has processed an earlier version of the record, which cannot then
50
be done because the row cannot be constructed from the clustered index
51
record. To avoid this problem, we will store in the update and delete mark
52
undo record also the columns necessary to construct the secondary index
53
entries which are modified.
54
We can latch the stack of versions of a single clustered index record
55
by taking a latch on the clustered index page. As long as the latch is held,
56
no new versions can be added and no versions removed by undo. But, a purge
57
can still remove old versions from the bottom of the stack. */
59
/* How to protect rollback segments, undo logs, and history lists with
60
-------------------------------------------------------------------
63
The contention of the kernel mutex should be minimized. When a transaction
64
does its first insert or modify in an index, an undo log is assigned for it.
65
Then we must have an x-latch to the rollback segment header.
66
When the transaction does more modifys or rolls back, the undo log is
67
protected with undo_mutex in the transaction.
68
When the transaction commits, its insert undo log is either reset and
69
cached for a fast reuse, or freed. In these cases we must have an x-latch on
70
the rollback segment page. The update undo log is put to the history list. If
71
it is not suitable for reuse, its slot in the rollback segment is reset. In
72
both cases, an x-latch must be acquired on the rollback segment.
73
The purge operation steps through the history list without modifying
74
it until a truncate operation occurs, which can remove undo logs from the end
75
of the list and release undo log segments. In stepping through the list,
76
s-latches on the undo log pages are enough, but in a truncate, x-latches must
77
be obtained on the rollback segment and individual pages. */
79
/************************************************************************
80
Initializes the fields in an undo log segment page. */
85
page_t* undo_page, /* in: undo log segment page */
86
ulint type, /* in: undo log segment type */
87
mtr_t* mtr); /* in: mtr */
88
/************************************************************************
89
Creates and initializes an undo log memory object. */
94
/* out, own: the undo log memory object */
95
trx_rseg_t* rseg, /* in: rollback segment memory object */
96
ulint id, /* in: slot index within rseg */
97
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
99
dulint trx_id, /* in: id of the trx for which the undo log
101
XID* xid, /* in: X/Open XA transaction identification*/
102
ulint page_no,/* in: undo log header page number */
103
ulint offset);/* in: undo log header byte offset on page */
104
/*******************************************************************
105
Initializes a cached insert undo log header page for new use. NOTE that this
106
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
107
the operation of this function! */
110
trx_undo_insert_header_reuse(
111
/*=========================*/
112
/* out: undo log header byte offset on page */
113
page_t* undo_page, /* in: insert undo log segment header page,
115
dulint trx_id, /* in: transaction id */
116
mtr_t* mtr); /* in: mtr */
117
/**************************************************************************
118
If an update undo log can be discarded immediately, this function frees the
119
space, resetting the page to the proper state for caching. */
122
trx_undo_discard_latest_update_undo(
123
/*================================*/
124
page_t* undo_page, /* in: header page of an undo log of size 1 */
125
mtr_t* mtr); /* in: mtr */
128
/***************************************************************************
129
Gets the previous record in an undo log from the previous page. */
132
trx_undo_get_prev_rec_from_prev_page(
133
/*=================================*/
134
/* out: undo log record, the page s-latched,
136
trx_undo_rec_t* rec, /* in: undo record */
137
ulint page_no,/* in: undo log header page number */
138
ulint offset, /* in: undo log header offset on page */
139
mtr_t* mtr) /* in: mtr */
145
undo_page = buf_frame_align(rec);
147
prev_page_no = flst_get_prev_addr(undo_page + TRX_UNDO_PAGE_HDR
148
+ TRX_UNDO_PAGE_NODE, mtr)
151
if (prev_page_no == FIL_NULL) {
156
prev_page = trx_undo_page_get_s_latched(
157
buf_frame_get_space_id(undo_page), prev_page_no, mtr);
159
return(trx_undo_page_get_last_rec(prev_page, page_no, offset));
162
/***************************************************************************
163
Gets the previous record in an undo log. */
166
trx_undo_get_prev_rec(
167
/*==================*/
168
/* out: undo log record, the page s-latched,
170
trx_undo_rec_t* rec, /* in: undo record */
171
ulint page_no,/* in: undo log header page number */
172
ulint offset, /* in: undo log header offset on page */
173
mtr_t* mtr) /* in: mtr */
175
trx_undo_rec_t* prev_rec;
177
prev_rec = trx_undo_page_get_prev_rec(rec, page_no, offset);
184
/* We have to go to the previous undo log page to look for the
187
return(trx_undo_get_prev_rec_from_prev_page(rec, page_no, offset,
191
/***************************************************************************
192
Gets the next record in an undo log from the next page. */
195
trx_undo_get_next_rec_from_next_page(
196
/*=================================*/
197
/* out: undo log record, the page latched, NULL if
199
page_t* undo_page, /* in: undo log page */
200
ulint page_no,/* in: undo log header page number */
201
ulint offset, /* in: undo log header offset on page */
202
ulint mode, /* in: latch mode: RW_S_LATCH or RW_X_LATCH */
203
mtr_t* mtr) /* in: mtr */
205
trx_ulogf_t* log_hdr;
211
if (page_no == buf_frame_get_page_no(undo_page)) {
213
log_hdr = undo_page + offset;
214
next = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
222
space = buf_frame_get_space_id(undo_page);
224
next_page_no = flst_get_next_addr(undo_page + TRX_UNDO_PAGE_HDR
225
+ TRX_UNDO_PAGE_NODE, mtr)
227
if (next_page_no == FIL_NULL) {
232
if (mode == RW_S_LATCH) {
233
next_page = trx_undo_page_get_s_latched(space, next_page_no,
236
ut_ad(mode == RW_X_LATCH);
237
next_page = trx_undo_page_get(space, next_page_no, mtr);
240
return(trx_undo_page_get_first_rec(next_page, page_no, offset));
243
/***************************************************************************
244
Gets the next record in an undo log. */
247
trx_undo_get_next_rec(
248
/*==================*/
249
/* out: undo log record, the page s-latched,
251
trx_undo_rec_t* rec, /* in: undo record */
252
ulint page_no,/* in: undo log header page number */
253
ulint offset, /* in: undo log header offset on page */
254
mtr_t* mtr) /* in: mtr */
256
trx_undo_rec_t* next_rec;
258
next_rec = trx_undo_page_get_next_rec(rec, page_no, offset);
264
return(trx_undo_get_next_rec_from_next_page(buf_frame_align(rec),
269
/***************************************************************************
270
Gets the first record in an undo log. */
273
trx_undo_get_first_rec(
274
/*===================*/
275
/* out: undo log record, the page latched, NULL if
277
ulint space, /* in: undo log header space */
278
ulint page_no,/* in: undo log header page number */
279
ulint offset, /* in: undo log header offset on page */
280
ulint mode, /* in: latching mode: RW_S_LATCH or RW_X_LATCH */
281
mtr_t* mtr) /* in: mtr */
286
if (mode == RW_S_LATCH) {
287
undo_page = trx_undo_page_get_s_latched(space, page_no, mtr);
289
undo_page = trx_undo_page_get(space, page_no, mtr);
292
rec = trx_undo_page_get_first_rec(undo_page, page_no, offset);
298
return(trx_undo_get_next_rec_from_next_page(undo_page, page_no, offset,
302
/*============== UNDO LOG FILE COPY CREATION AND FREEING ==================*/
304
/**************************************************************************
305
Writes the mtr log entry of an undo log page initialization. */
308
trx_undo_page_init_log(
309
/*===================*/
310
page_t* undo_page, /* in: undo log page */
311
ulint type, /* in: undo log type */
312
mtr_t* mtr) /* in: mtr */
314
mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
316
mlog_catenate_ulint_compressed(mtr, type);
319
/***************************************************************
320
Parses the redo log entry of an undo log page initialization. */
323
trx_undo_parse_page_init(
324
/*=====================*/
325
/* out: end of log record or NULL */
326
byte* ptr, /* in: buffer */
327
byte* end_ptr,/* in: buffer end */
328
page_t* page, /* in: page or NULL */
329
mtr_t* mtr) /* in: mtr or NULL */
333
ptr = mach_parse_compressed(ptr, end_ptr, &type);
341
trx_undo_page_init(page, type, mtr);
347
/************************************************************************
348
Initializes the fields in an undo log segment page. */
353
page_t* undo_page, /* in: undo log segment page */
354
ulint type, /* in: undo log segment type */
355
mtr_t* mtr) /* in: mtr */
357
trx_upagef_t* page_hdr;
359
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
361
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_TYPE, type);
363
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
364
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
365
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
366
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
368
fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
370
trx_undo_page_init_log(undo_page, type, mtr);
373
/*******************************************************************
374
Creates a new undo log segment in file. */
379
/* out: DB_SUCCESS if page creation OK
380
possible error codes are:
381
DB_TOO_MANY_CONCURRENT_TRXS
382
DB_OUT_OF_FILE_SPACE */
383
trx_rseg_t* rseg __attribute__((unused)),/* in: rollback segment */
384
trx_rsegf_t* rseg_hdr,/* in: rollback segment header, page
386
ulint type, /* in: type of the segment: TRX_UNDO_INSERT or
388
ulint* id, /* out: slot index within rseg header */
390
/* out: segment header page x-latched, NULL
391
if there was an error */
392
mtr_t* mtr) /* in: mtr */
396
trx_upagef_t* page_hdr;
397
trx_usegf_t* seg_hdr;
400
ulint err = DB_SUCCESS;
402
ut_ad(mtr && id && rseg_hdr);
403
ut_ad(mutex_own(&(rseg->mutex)));
405
/* fputs(type == TRX_UNDO_INSERT
406
? "Creating insert undo log segment\n"
407
: "Creating update undo log segment\n", stderr); */
408
slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
410
if (slot_no == ULINT_UNDEFINED) {
411
ut_print_timestamp(stderr);
413
"InnoDB: Warning: cannot find a free slot for"
414
" an undo log. Do you have too\n"
415
"InnoDB: many active transactions"
416
" running concurrently?\n");
418
return(DB_TOO_MANY_CONCURRENT_TRXS);
421
space = buf_frame_get_space_id(rseg_hdr);
423
success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
427
return(DB_OUT_OF_FILE_SPACE);
430
/* Allocate a new file segment for the undo log */
431
*undo_page = fseg_create_general(space, 0,
433
+ TRX_UNDO_FSEG_HEADER, TRUE, mtr);
435
fil_space_release_free_extents(space, n_reserved);
437
if (*undo_page == NULL) {
440
return(DB_OUT_OF_FILE_SPACE);
443
#ifdef UNIV_SYNC_DEBUG
444
buf_page_dbg_add_level(*undo_page, SYNC_TRX_UNDO_PAGE);
445
#endif /* UNIV_SYNC_DEBUG */
447
page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
448
seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
450
trx_undo_page_init(*undo_page, type, mtr);
452
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
453
TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
456
mlog_write_ulint(seg_hdr + TRX_UNDO_LAST_LOG, 0, MLOG_2BYTES, mtr);
458
flst_init(seg_hdr + TRX_UNDO_PAGE_LIST, mtr);
460
flst_add_last(seg_hdr + TRX_UNDO_PAGE_LIST,
461
page_hdr + TRX_UNDO_PAGE_NODE, mtr);
463
trx_rsegf_set_nth_undo(rseg_hdr, slot_no,
464
buf_frame_get_page_no(*undo_page), mtr);
471
/**************************************************************************
472
Writes the mtr log entry of an undo log header initialization. */
475
trx_undo_header_create_log(
476
/*=======================*/
477
page_t* undo_page, /* in: undo log header page */
478
dulint trx_id, /* in: transaction id */
479
mtr_t* mtr) /* in: mtr */
481
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_CREATE, mtr);
483
mlog_catenate_dulint_compressed(mtr, trx_id);
486
/*******************************************************************
487
Creates a new undo log header in file. NOTE that this function has its own
488
log record type MLOG_UNDO_HDR_CREATE. You must NOT change the operation of
492
trx_undo_header_create(
493
/*===================*/
494
/* out: header byte offset on page */
495
page_t* undo_page, /* in: undo log segment header page,
496
x-latched; it is assumed that there are
497
TRX_UNDO_LOG_XA_HDR_SIZE bytes free space
499
dulint trx_id, /* in: transaction id */
500
mtr_t* mtr) /* in: mtr */
502
trx_upagef_t* page_hdr;
503
trx_usegf_t* seg_hdr;
504
trx_ulogf_t* log_hdr;
505
trx_ulogf_t* prev_log_hdr;
510
ut_ad(mtr && undo_page);
512
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
513
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
515
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
517
log_hdr = undo_page + free;
519
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
521
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
523
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
525
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
527
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
529
prev_log = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
532
prev_log_hdr = undo_page + prev_log;
534
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, free);
537
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, free);
539
log_hdr = undo_page + free;
541
mach_write_to_2(log_hdr + TRX_UNDO_DEL_MARKS, TRUE);
543
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
544
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
546
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
547
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
549
mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
550
mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
552
/* Write the log record about the header creation */
553
trx_undo_header_create_log(undo_page, trx_id, mtr);
558
/************************************************************************
559
Write X/Open XA Transaction Identification (XID) to undo log header */
564
trx_ulogf_t* log_hdr,/* in: undo log header */
565
const XID* xid, /* in: X/Open XA Transaction Identification */
566
mtr_t* mtr) /* in: mtr */
568
mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT,
569
(ulint)xid->formatID, MLOG_4BYTES, mtr);
571
mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN,
572
(ulint)xid->gtrid_length, MLOG_4BYTES, mtr);
574
mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN,
575
(ulint)xid->bqual_length, MLOG_4BYTES, mtr);
577
mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data,
581
/************************************************************************
582
Read X/Open XA Transaction Identification (XID) from undo log header */
587
trx_ulogf_t* log_hdr,/* in: undo log header */
588
XID* xid) /* out: X/Open XA Transaction Identification */
590
xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
593
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
595
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
597
memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE);
600
/*******************************************************************
601
Adds space for the XA XID after an undo log old-style header. */
604
trx_undo_header_add_space_for_xid(
605
/*==============================*/
606
page_t* undo_page,/* in: undo log segment header page */
607
trx_ulogf_t* log_hdr,/* in: undo log header */
608
mtr_t* mtr) /* in: mtr */
610
trx_upagef_t* page_hdr;
614
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
616
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
618
/* free is now the end offset of the old style undo log header */
620
ut_a(free == (ulint)(log_hdr - undo_page) + TRX_UNDO_LOG_OLD_HDR_SIZE);
622
new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
623
- TRX_UNDO_LOG_OLD_HDR_SIZE);
625
/* Add space for a XID after the header, update the free offset
626
fields on the undo log page and in the undo log header */
628
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
631
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free,
634
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
638
/**************************************************************************
639
Writes the mtr log entry of an undo log header reuse. */
642
trx_undo_insert_header_reuse_log(
643
/*=============================*/
644
page_t* undo_page, /* in: undo log header page */
645
dulint trx_id, /* in: transaction id */
646
mtr_t* mtr) /* in: mtr */
648
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr);
650
mlog_catenate_dulint_compressed(mtr, trx_id);
653
/***************************************************************
654
Parses the redo log entry of an undo log page header create or reuse. */
657
trx_undo_parse_page_header(
658
/*=======================*/
659
/* out: end of log record or NULL */
660
ulint type, /* in: MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE */
661
byte* ptr, /* in: buffer */
662
byte* end_ptr,/* in: buffer end */
663
page_t* page, /* in: page or NULL */
664
mtr_t* mtr) /* in: mtr or NULL */
668
ptr = mach_dulint_parse_compressed(ptr, end_ptr, &trx_id);
676
if (type == MLOG_UNDO_HDR_CREATE) {
677
trx_undo_header_create(page, trx_id, mtr);
679
ut_ad(type == MLOG_UNDO_HDR_REUSE);
680
trx_undo_insert_header_reuse(page, trx_id, mtr);
687
/*******************************************************************
688
Initializes a cached insert undo log header page for new use. NOTE that this
689
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
690
the operation of this function! */
693
trx_undo_insert_header_reuse(
694
/*=========================*/
695
/* out: undo log header byte offset on page */
696
page_t* undo_page, /* in: insert undo log segment header page,
698
dulint trx_id, /* in: transaction id */
699
mtr_t* mtr) /* in: mtr */
701
trx_upagef_t* page_hdr;
702
trx_usegf_t* seg_hdr;
703
trx_ulogf_t* log_hdr;
707
ut_ad(mtr && undo_page);
709
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
710
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
712
free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
714
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
716
log_hdr = undo_page + free;
718
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
720
/* Insert undo data is not needed after commit: we may free all
721
the space on the page */
723
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
724
+ TRX_UNDO_PAGE_TYPE)
727
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
729
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
731
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
733
log_hdr = undo_page + free;
735
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
736
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
738
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
739
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
741
/* Write the log record MLOG_UNDO_HDR_REUSE */
742
trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
747
/**************************************************************************
748
Writes the redo log entry of an update undo log header discard. */
751
trx_undo_discard_latest_log(
752
/*========================*/
753
page_t* undo_page, /* in: undo log header page */
754
mtr_t* mtr) /* in: mtr */
756
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_DISCARD, mtr);
759
/***************************************************************
760
Parses the redo log entry of an undo log page header discard. */
763
trx_undo_parse_discard_latest(
764
/*==========================*/
765
/* out: end of log record or NULL */
766
byte* ptr, /* in: buffer */
767
byte* end_ptr __attribute__((unused)), /* in: buffer end */
768
page_t* page, /* in: page or NULL */
769
mtr_t* mtr) /* in: mtr or NULL */
774
trx_undo_discard_latest_update_undo(page, mtr);
780
/**************************************************************************
781
If an update undo log can be discarded immediately, this function frees the
782
space, resetting the page to the proper state for caching. */
785
trx_undo_discard_latest_update_undo(
786
/*================================*/
787
page_t* undo_page, /* in: header page of an undo log of size 1 */
788
mtr_t* mtr) /* in: mtr */
790
trx_usegf_t* seg_hdr;
791
trx_upagef_t* page_hdr;
792
trx_ulogf_t* log_hdr;
793
trx_ulogf_t* prev_log_hdr;
795
ulint prev_hdr_offset;
797
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
798
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
800
free = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
801
log_hdr = undo_page + free;
803
prev_hdr_offset = mach_read_from_2(log_hdr + TRX_UNDO_PREV_LOG);
805
if (prev_hdr_offset != 0) {
806
prev_log_hdr = undo_page + prev_hdr_offset;
808
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
809
mach_read_from_2(prev_log_hdr
810
+ TRX_UNDO_LOG_START));
811
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, 0);
814
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, free);
816
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_CACHED);
817
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, prev_hdr_offset);
819
trx_undo_discard_latest_log(undo_page, mtr);
822
/************************************************************************
823
Tries to add a page to the undo log segment where the undo log is placed. */
828
/* out: page number if success, else
830
trx_t* trx, /* in: transaction */
831
trx_undo_t* undo, /* in: undo log memory object */
832
mtr_t* mtr) /* in: mtr which does not have a latch to any
833
undo log page; the caller must have reserved
834
the rollback segment mutex */
843
ut_ad(mutex_own(&(trx->undo_mutex)));
844
ut_ad(!mutex_own(&kernel_mutex));
845
ut_ad(mutex_own(&(trx->rseg->mutex)));
849
if (rseg->curr_size == rseg->max_size) {
854
header_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
856
success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
863
page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
864
+ TRX_UNDO_FSEG_HEADER,
865
undo->top_page_no + 1, FSP_UP,
868
fil_space_release_free_extents(undo->space, n_reserved);
870
if (page_no == FIL_NULL) {
877
undo->last_page_no = page_no;
879
new_page = trx_undo_page_get(undo->space, page_no, mtr);
881
trx_undo_page_init(new_page, undo->type, mtr);
883
flst_add_last(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
884
new_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
891
/************************************************************************
892
Frees an undo log page that is not the header page. */
897
/* out: last page number in remaining log */
898
trx_rseg_t* rseg, /* in: rollback segment */
899
ibool in_history, /* in: TRUE if the undo log is in the history
901
ulint space, /* in: space */
902
ulint hdr_page_no, /* in: header page number */
903
ulint page_no, /* in: page number to free: must not be the
905
mtr_t* mtr) /* in: mtr which does not have a latch to any
906
undo log page; the caller must have reserved
907
the rollback segment mutex */
911
fil_addr_t last_addr;
912
trx_rsegf_t* rseg_header;
915
ut_a(hdr_page_no != page_no);
916
ut_ad(!mutex_own(&kernel_mutex));
917
ut_ad(mutex_own(&(rseg->mutex)));
919
undo_page = trx_undo_page_get(space, page_no, mtr);
921
header_page = trx_undo_page_get(space, hdr_page_no, mtr);
923
flst_remove(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
924
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
926
fseg_free_page(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER,
927
space, page_no, mtr);
929
last_addr = flst_get_last(header_page + TRX_UNDO_SEG_HDR
930
+ TRX_UNDO_PAGE_LIST, mtr);
934
rseg_header = trx_rsegf_get(space, rseg->page_no, mtr);
936
hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
938
ut_ad(hist_size > 0);
939
mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
940
hist_size - 1, MLOG_4BYTES, mtr);
943
return(last_addr.page);
946
/************************************************************************
947
Frees an undo log page when there is also the memory object for the undo
951
trx_undo_free_page_in_rollback(
952
/*===========================*/
953
trx_t* trx __attribute__((unused)), /* in: transaction */
954
trx_undo_t* undo, /* in: undo log memory copy */
955
ulint page_no,/* in: page number to free: must not be the
957
mtr_t* mtr) /* in: mtr which does not have a latch to any
958
undo log page; the caller must have reserved
959
the rollback segment mutex */
963
ut_ad(undo->hdr_page_no != page_no);
964
ut_ad(mutex_own(&(trx->undo_mutex)));
966
last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
967
undo->hdr_page_no, page_no, mtr);
969
undo->last_page_no = last_page_no;
973
/************************************************************************
974
Empties an undo log header page of undo records for that undo log. Other
975
undo logs may still have records on that page, if it is an update undo log. */
978
trx_undo_empty_header_page(
979
/*=======================*/
980
ulint space, /* in: space */
981
ulint hdr_page_no, /* in: header page number */
982
ulint hdr_offset, /* in: header offset */
983
mtr_t* mtr) /* in: mtr */
986
trx_ulogf_t* log_hdr;
989
header_page = trx_undo_page_get(space, hdr_page_no, mtr);
991
log_hdr = header_page + hdr_offset;
993
end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
995
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
998
/***************************************************************************
999
Truncates an undo log from the end. This function is used during a rollback
1000
to free space from an undo log. */
1003
trx_undo_truncate_end(
1004
/*==================*/
1005
trx_t* trx, /* in: transaction whose undo log it is */
1006
trx_undo_t* undo, /* in: undo log */
1007
dulint limit) /* in: all undo records with undo number
1008
>= this value should be truncated */
1012
trx_undo_rec_t* rec;
1013
trx_undo_rec_t* trunc_here;
1017
ut_ad(mutex_own(&(trx->undo_mutex)));
1018
ut_ad(mutex_own(&(trx->rseg->mutex)));
1027
last_page_no = undo->last_page_no;
1029
undo_page = trx_undo_page_get(undo->space, last_page_no, &mtr);
1031
rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
1035
if (last_page_no == undo->hdr_page_no) {
1040
trx_undo_free_page_in_rollback(
1041
trx, undo, last_page_no, &mtr);
1045
if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit)
1047
/* Truncate at least this record off, maybe
1054
rec = trx_undo_page_get_prev_rec(rec,
1064
mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
1065
+ TRX_UNDO_PAGE_FREE,
1066
trunc_here - undo_page, MLOG_2BYTES, &mtr);
1072
/***************************************************************************
1073
Truncates an undo log from the start. This function is used during a purge
1077
trx_undo_truncate_start(
1078
/*====================*/
1079
trx_rseg_t* rseg, /* in: rollback segment */
1080
ulint space, /* in: space id of the log */
1081
ulint hdr_page_no, /* in: header page number */
1082
ulint hdr_offset, /* in: header offset on the page */
1083
dulint limit) /* in: all undo pages with undo numbers <
1084
this value should be truncated; NOTE that
1085
the function only frees whole pages; the
1086
header page is not freed, but emptied, if
1087
all the records there are < limit */
1090
trx_undo_rec_t* rec;
1091
trx_undo_rec_t* last_rec;
1095
ut_ad(mutex_own(&(rseg->mutex)));
1097
if (0 == ut_dulint_cmp(limit, ut_dulint_zero)) {
1104
rec = trx_undo_get_first_rec(space, hdr_page_no, hdr_offset,
1114
undo_page = buf_frame_align(rec);
1116
last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no,
1118
if (ut_dulint_cmp(trx_undo_rec_get_undo_no(last_rec), limit) >= 0) {
1125
page_no = buf_frame_get_page_no(undo_page);
1127
if (page_no == hdr_page_no) {
1128
trx_undo_empty_header_page(space, hdr_page_no, hdr_offset,
1131
trx_undo_free_page(rseg, TRUE, space, hdr_page_no,
1140
/**************************************************************************
1141
Frees an undo log segment which is not in the history list. */
1146
trx_undo_t* undo) /* in: undo log */
1149
fseg_header_t* file_seg;
1150
trx_rsegf_t* rseg_header;
1151
trx_usegf_t* seg_header;
1162
ut_ad(!mutex_own(&kernel_mutex));
1164
mutex_enter(&(rseg->mutex));
1166
seg_header = trx_undo_page_get(undo->space, undo->hdr_page_no,
1167
&mtr) + TRX_UNDO_SEG_HDR;
1169
file_seg = seg_header + TRX_UNDO_FSEG_HEADER;
1171
finished = fseg_free_step(file_seg, &mtr);
1174
/* Update the rseg header */
1175
rseg_header = trx_rsegf_get(rseg->space, rseg->page_no,
1177
trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL,
1181
mutex_exit(&(rseg->mutex));
1186
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
1188
/************************************************************************
1189
Creates and initializes an undo log memory object according to the values
1190
in the header in file, when the database is started. The memory object is
1191
inserted in the appropriate list of rseg. */
1194
trx_undo_mem_create_at_db_start(
1195
/*============================*/
1196
/* out, own: the undo log memory object */
1197
trx_rseg_t* rseg, /* in: rollback segment memory object */
1198
ulint id, /* in: slot index within rseg */
1199
ulint page_no,/* in: undo log segment page number */
1200
mtr_t* mtr) /* in: mtr */
1203
trx_upagef_t* page_header;
1204
trx_usegf_t* seg_header;
1205
trx_ulogf_t* undo_header;
1211
fil_addr_t last_addr;
1213
trx_undo_rec_t* rec;
1215
ibool xid_exists = FALSE;
1217
if (id >= TRX_RSEG_N_SLOTS) {
1219
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1223
undo_page = trx_undo_page_get(rseg->space, page_no, mtr);
1225
page_header = undo_page + TRX_UNDO_PAGE_HDR;
1227
type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES,
1229
seg_header = undo_page + TRX_UNDO_SEG_HDR;
1231
state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
1233
offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG);
1235
undo_header = undo_page + offset;
1237
trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr);
1239
xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1242
/* Read X/Open XA transaction identification if it exists, or
1245
memset(&xid, 0, sizeof(xid));
1248
if (xid_exists == TRUE) {
1249
trx_undo_read_xid(undo_header, &xid);
1252
mutex_enter(&(rseg->mutex));
1254
undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
1256
mutex_exit(&(rseg->mutex));
1258
undo->dict_operation = mtr_read_ulint(
1259
undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr);
1261
undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr);
1262
undo->state = state;
1263
undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1265
/* If the log segment is being freed, the page list is inconsistent! */
1266
if (state == TRX_UNDO_TO_FREE) {
1271
last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1273
undo->last_page_no = last_addr.page;
1274
undo->top_page_no = last_addr.page;
1276
last_page = trx_undo_page_get(rseg->space, undo->last_page_no, mtr);
1278
rec = trx_undo_page_get_last_rec(last_page, page_no, offset);
1283
undo->empty = FALSE;
1284
undo->top_offset = rec - last_page;
1285
undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
1288
if (type == TRX_UNDO_INSERT) {
1289
if (state != TRX_UNDO_CACHED) {
1290
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list,
1293
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_cached,
1297
ut_ad(type == TRX_UNDO_UPDATE);
1298
if (state != TRX_UNDO_CACHED) {
1299
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_list,
1302
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_cached,
1310
/************************************************************************
1311
Initializes the undo log lists for a rollback segment memory copy. This
1312
function is only called when the database is started or a new rollback
1313
segment is created. */
1316
trx_undo_lists_init(
1317
/*================*/
1318
/* out: the combined size of undo log segments
1320
trx_rseg_t* rseg) /* in: rollback segment memory object */
1325
trx_rsegf_t* rseg_header;
1329
UT_LIST_INIT(rseg->update_undo_list);
1330
UT_LIST_INIT(rseg->update_undo_cached);
1331
UT_LIST_INIT(rseg->insert_undo_list);
1332
UT_LIST_INIT(rseg->insert_undo_cached);
1336
rseg_header = trx_rsegf_get_new(rseg->space, rseg->page_no, &mtr);
1338
for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
1339
page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr);
1341
/* In forced recovery: try to avoid operations which look
1342
at database pages; undo logs are rapidly changing data, and
1343
the probability that they are in an inconsistent state is
1346
if (page_no != FIL_NULL
1347
&& srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
1349
undo = trx_undo_mem_create_at_db_start(rseg, i,
1357
rseg_header = trx_rsegf_get(rseg->space,
1358
rseg->page_no, &mtr);
1367
/************************************************************************
1368
Creates and initializes an undo log memory object. */
1371
trx_undo_mem_create(
1372
/*================*/
1373
/* out, own: the undo log memory object */
1374
trx_rseg_t* rseg, /* in: rollback segment memory object */
1375
ulint id, /* in: slot index within rseg */
1376
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
1378
dulint trx_id, /* in: id of the trx for which the undo log
1380
XID* xid, /* in: X/Open transaction identification */
1381
ulint page_no,/* in: undo log header page number */
1382
ulint offset) /* in: undo log header byte offset on page */
1386
ut_ad(mutex_own(&(rseg->mutex)));
1388
if (id >= TRX_RSEG_N_SLOTS) {
1390
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1394
undo = mem_alloc(sizeof(trx_undo_t));
1403
undo->state = TRX_UNDO_ACTIVE;
1404
undo->del_marks = FALSE;
1405
undo->trx_id = trx_id;
1408
undo->dict_operation = FALSE;
1412
undo->space = rseg->space;
1413
undo->hdr_page_no = page_no;
1414
undo->hdr_offset = offset;
1415
undo->last_page_no = page_no;
1419
undo->top_page_no = page_no;
1420
undo->guess_page = NULL;
1425
/************************************************************************
1426
Initializes a cached undo log object for new use. */
1429
trx_undo_mem_init_for_reuse(
1430
/*========================*/
1431
trx_undo_t* undo, /* in: undo log to init */
1432
dulint trx_id, /* in: id of the trx for which the undo log
1434
XID* xid, /* in: X/Open XA transaction identification*/
1435
ulint offset) /* in: undo log header byte offset on page */
1437
ut_ad(mutex_own(&((undo->rseg)->mutex)));
1439
if (UNIV_UNLIKELY(undo->id >= TRX_RSEG_N_SLOTS)) {
1440
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1443
mem_analyze_corruption(undo);
1447
undo->state = TRX_UNDO_ACTIVE;
1448
undo->del_marks = FALSE;
1449
undo->trx_id = trx_id;
1452
undo->dict_operation = FALSE;
1454
undo->hdr_offset = offset;
1458
/************************************************************************
1459
Frees an undo log memory copy. */
1464
trx_undo_t* undo) /* in: the undo object to be freed */
1466
if (undo->id >= TRX_RSEG_N_SLOTS) {
1468
"InnoDB: Error: undo->id is %lu\n", (ulong) undo->id);
1475
/**************************************************************************
1476
Creates a new undo log. */
1481
/* out: DB_SUCCESS if successful in creating
1482
the new undo lob object, possible error
1484
DB_TOO_MANY_CONCURRENT_TRXS
1485
DB_OUT_OF_FILE_SPACE
1487
trx_t* trx, /* in: transaction */
1488
trx_rseg_t* rseg, /* in: rollback segment memory copy */
1489
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
1491
dulint trx_id, /* in: id of the trx for which the undo log
1493
XID* xid, /* in: X/Open transaction identification*/
1494
trx_undo_t** undo, /* out: the new undo log object, undefined
1495
* if did not succeed */
1496
mtr_t* mtr) /* in: mtr */
1498
trx_rsegf_t* rseg_header;
1505
ut_ad(mutex_own(&(rseg->mutex)));
1507
if (rseg->curr_size == rseg->max_size) {
1509
return(DB_OUT_OF_FILE_SPACE);
1514
rseg_header = trx_rsegf_get(rseg->space, rseg->page_no, mtr);
1516
err = trx_undo_seg_create(rseg, rseg_header, type, &id,
1519
if (err != DB_SUCCESS) {
1520
/* Did not succeed */
1527
page_no = buf_frame_get_page_no(undo_page);
1529
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1531
if (trx->support_xa) {
1532
trx_undo_header_add_space_for_xid(undo_page,
1533
undo_page + offset, mtr);
1536
*undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
1538
if (*undo == NULL) {
1540
err = DB_OUT_OF_MEMORY;
1546
/*================ UNDO LOG ASSIGNMENT AND CLEANUP =====================*/
1548
/************************************************************************
1549
Reuses a cached undo log. */
1552
trx_undo_reuse_cached(
1553
/*==================*/
1554
/* out: the undo log memory object, NULL if
1556
trx_t* trx, /* in: transaction */
1557
trx_rseg_t* rseg, /* in: rollback segment memory object */
1558
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
1560
dulint trx_id, /* in: id of the trx for which the undo log
1562
XID* xid, /* in: X/Open XA transaction identification */
1563
mtr_t* mtr) /* in: mtr */
1569
ut_ad(mutex_own(&(rseg->mutex)));
1571
if (type == TRX_UNDO_INSERT) {
1573
undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
1579
UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo);
1581
ut_ad(type == TRX_UNDO_UPDATE);
1583
undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
1589
UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo);
1592
ut_ad(undo->size == 1);
1594
if (undo->id >= TRX_RSEG_N_SLOTS) {
1595
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1597
mem_analyze_corruption(undo);
1601
undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
1603
if (type == TRX_UNDO_INSERT) {
1604
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
1606
if (trx->support_xa) {
1607
trx_undo_header_add_space_for_xid(
1608
undo_page, undo_page + offset, mtr);
1611
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
1612
+ TRX_UNDO_PAGE_TYPE)
1613
== TRX_UNDO_UPDATE);
1615
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1617
if (trx->support_xa) {
1618
trx_undo_header_add_space_for_xid(
1619
undo_page, undo_page + offset, mtr);
1623
trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
1628
/**************************************************************************
1629
Marks an undo log header as a header of a data dictionary operation
1633
trx_undo_mark_as_dict_operation(
1634
/*============================*/
1635
trx_t* trx, /* in: dict op transaction */
1636
trx_undo_t* undo, /* in: assigned undo log */
1637
mtr_t* mtr) /* in: mtr */
1641
ut_a(trx->dict_operation);
1643
hdr_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
1645
mlog_write_ulint(hdr_page + undo->hdr_offset
1646
+ TRX_UNDO_DICT_TRANS,
1647
trx->dict_operation, MLOG_1BYTE, mtr);
1649
mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
1650
trx->table_id, mtr);
1652
undo->dict_operation = trx->dict_operation;
1653
undo->table_id = trx->table_id;
1656
/**************************************************************************
1657
Assigns an undo log for a transaction. A new undo log is created or a cached
1661
trx_undo_assign_undo(
1662
/*=================*/
1663
/* out: DB_SUCCESS if undo log assign
1664
successful, possible error codes are:
1665
DD_TOO_MANY_CONCURRENT_TRXS
1666
DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY*/
1667
trx_t* trx, /* in: transaction */
1668
ulint type) /* in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
1673
ulint err = DB_SUCCESS;
1680
ut_ad(mutex_own(&(trx->undo_mutex)));
1684
ut_ad(!mutex_own(&kernel_mutex));
1686
mutex_enter(&(rseg->mutex));
1688
undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
1691
err = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
1693
if (err != DB_SUCCESS) {
1699
if (type == TRX_UNDO_INSERT) {
1700
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_list, undo);
1701
ut_ad(trx->insert_undo == NULL);
1702
trx->insert_undo = undo;
1704
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_list, undo);
1705
ut_ad(trx->update_undo == NULL);
1706
trx->update_undo = undo;
1709
if (trx->dict_operation) {
1710
trx_undo_mark_as_dict_operation(trx, undo, &mtr);
1714
mutex_exit(&(rseg->mutex));
1720
/**********************************************************************
1721
Sets the state of the undo log segment at a transaction finish. */
1724
trx_undo_set_state_at_finish(
1725
/*=========================*/
1726
/* out: undo log segment header page,
1728
trx_rseg_t* rseg, /* in: rollback segment memory object */
1729
trx_t* trx __attribute__((unused)), /* in: transaction */
1730
trx_undo_t* undo, /* in: undo log memory copy */
1731
mtr_t* mtr) /* in: mtr */
1733
trx_usegf_t* seg_hdr;
1734
trx_upagef_t* page_hdr;
1741
ut_ad(mutex_own(&rseg->mutex));
1743
if (undo->id >= TRX_RSEG_N_SLOTS) {
1744
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1746
mem_analyze_corruption(undo);
1750
undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
1752
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1753
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1756
&& mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE)
1757
< TRX_UNDO_PAGE_REUSE_LIMIT) {
1759
/* This is a heuristic to avoid the problem of all UNDO
1760
slots ending up in one of the UNDO lists. Previously if
1761
the server crashed with all the slots in one of the lists,
1762
transactions that required the slots of a different type
1763
would fail for lack of slots. */
1765
if (UT_LIST_GET_LEN(rseg->update_undo_list) < 500
1766
&& UT_LIST_GET_LEN(rseg->insert_undo_list) < 500) {
1768
state = TRX_UNDO_CACHED;
1770
state = TRX_UNDO_TO_FREE;
1773
} else if (undo->type == TRX_UNDO_INSERT) {
1775
state = TRX_UNDO_TO_FREE;
1777
state = TRX_UNDO_TO_PURGE;
1780
undo->state = state;
1782
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr);
1787
/**********************************************************************
1788
Sets the state of the undo log segment at a transaction prepare. */
1791
trx_undo_set_state_at_prepare(
1792
/*==========================*/
1793
/* out: undo log segment header page,
1795
trx_t* trx, /* in: transaction */
1796
trx_undo_t* undo, /* in: undo log memory copy */
1797
mtr_t* mtr) /* in: mtr */
1799
trx_usegf_t* seg_hdr;
1800
trx_upagef_t* page_hdr;
1801
trx_ulogf_t* undo_header;
1805
ut_ad(trx && undo && mtr);
1807
if (undo->id >= TRX_RSEG_N_SLOTS) {
1808
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1810
mem_analyze_corruption(undo);
1814
undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
1816
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1817
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1819
/*------------------------------*/
1820
undo->state = TRX_UNDO_PREPARED;
1821
undo->xid = trx->xid;
1822
/*------------------------------*/
1824
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
1827
offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
1828
undo_header = undo_page + offset;
1830
mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1831
TRUE, MLOG_1BYTE, mtr);
1833
trx_undo_write_xid(undo_header, &undo->xid, mtr);
1838
/**************************************************************************
1839
Adds the update undo log header as the first in the history list, and
1840
frees the memory object, or puts it to the list of cached update undo log
1844
trx_undo_update_cleanup(
1845
/*====================*/
1846
trx_t* trx, /* in: trx owning the update undo log */
1847
page_t* undo_page, /* in: update undo log header page,
1849
mtr_t* mtr) /* in: mtr */
1854
undo = trx->update_undo;
1857
ut_ad(mutex_own(&(rseg->mutex)));
1859
trx_purge_add_update_undo_to_history(trx, undo_page, mtr);
1861
UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo);
1863
trx->update_undo = NULL;
1865
if (undo->state == TRX_UNDO_CACHED) {
1867
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo);
1869
ut_ad(undo->state == TRX_UNDO_TO_PURGE);
1871
trx_undo_mem_free(undo);
1875
/**********************************************************************
1876
Frees or caches an insert undo log after a transaction commit or rollback.
1877
Knowledge of inserts is not needed after a commit or rollback, therefore
1878
the data can be discarded. */
1881
trx_undo_insert_cleanup(
1882
/*====================*/
1883
trx_t* trx) /* in: transaction handle */
1888
undo = trx->insert_undo;
1893
mutex_enter(&(rseg->mutex));
1895
UT_LIST_REMOVE(undo_list, rseg->insert_undo_list, undo);
1896
trx->insert_undo = NULL;
1898
if (undo->state == TRX_UNDO_CACHED) {
1900
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_cached, undo);
1902
ut_ad(undo->state == TRX_UNDO_TO_FREE);
1904
/* Delete first the undo log segment in the file */
1906
mutex_exit(&(rseg->mutex));
1908
trx_undo_seg_free(undo);
1910
mutex_enter(&(rseg->mutex));
1912
ut_ad(rseg->curr_size > undo->size);
1914
rseg->curr_size -= undo->size;
1916
trx_undo_mem_free(undo);
1919
mutex_exit(&(rseg->mutex));