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
/**************************************************//**
23
Created 3/26/1996 Heikki Tuuri
24
*******************************************************/
29
#include "trx0undo.ic"
33
#ifndef UNIV_HOTBACKUP
34
#include "mach0data.h"
40
#include "trx0purge.h"
42
/* How should the old versions in the history list be managed?
43
----------------------------------------------------------
44
If each transaction is given a whole page for its update undo log, file
45
space consumption can be 10 times higher than necessary. Therefore,
46
partly filled update undo log pages should be reusable. But then there
47
is no way individual pages can be ordered so that the ordering agrees
48
with the serialization numbers of the transactions on the pages. Thus,
49
the history list must be formed of undo logs, not their header pages as
50
it was in the old implementation.
51
However, on a single header page the transactions are placed in
52
the order of their serialization numbers. As old versions are purged, we
53
may free the page when the last transaction on the page has been purged.
54
A problem is that the purge has to go through the transactions
55
in the serialization order. This means that we have to look through all
56
rollback segments for the one that has the smallest transaction number
58
When should we do a purge? A purge is necessary when space is
59
running out in any of the rollback segments. Then we may have to purge
60
also old version which might be needed by some consistent read. How do
61
we trigger the start of a purge? When a transaction writes to an undo log,
62
it may notice that the space is running out. When a read view is closed,
63
it may make some history superfluous. The server can have an utility which
64
periodically checks if it can purge some history.
65
In a parallellized purge we have the problem that a query thread
66
can remove a delete marked clustered index record before another query
67
thread has processed an earlier version of the record, which cannot then
68
be done because the row cannot be constructed from the clustered index
69
record. To avoid this problem, we will store in the update and delete mark
70
undo record also the columns necessary to construct the secondary index
71
entries which are modified.
72
We can latch the stack of versions of a single clustered index record
73
by taking a latch on the clustered index page. As long as the latch is held,
74
no new versions can be added and no versions removed by undo. But, a purge
75
can still remove old versions from the bottom of the stack. */
77
/* How to protect rollback segments, undo logs, and history lists with
78
-------------------------------------------------------------------
81
The contention of the kernel mutex should be minimized. When a transaction
82
does its first insert or modify in an index, an undo log is assigned for it.
83
Then we must have an x-latch to the rollback segment header.
84
When the transaction does more modifys or rolls back, the undo log is
85
protected with undo_mutex in the transaction.
86
When the transaction commits, its insert undo log is either reset and
87
cached for a fast reuse, or freed. In these cases we must have an x-latch on
88
the rollback segment page. The update undo log is put to the history list. If
89
it is not suitable for reuse, its slot in the rollback segment is reset. In
90
both cases, an x-latch must be acquired on the rollback segment.
91
The purge operation steps through the history list without modifying
92
it until a truncate operation occurs, which can remove undo logs from the end
93
of the list and release undo log segments. In stepping through the list,
94
s-latches on the undo log pages are enough, but in a truncate, x-latches must
95
be obtained on the rollback segment and individual pages. */
96
#endif /* !UNIV_HOTBACKUP */
98
/********************************************************************//**
99
Initializes the fields in an undo log segment page. */
104
page_t* undo_page, /*!< in: undo log segment page */
105
ulint type, /*!< in: undo log segment type */
106
mtr_t* mtr); /*!< in: mtr */
108
#ifndef UNIV_HOTBACKUP
109
/********************************************************************//**
110
Creates and initializes an undo log memory object.
111
@return own: the undo log memory object */
116
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
117
ulint id, /*!< in: slot index within rseg */
118
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
120
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
122
const XID* xid, /*!< in: X/Open XA transaction identification*/
123
ulint page_no,/*!< in: undo log header page number */
124
ulint offset);/*!< in: undo log header byte offset on page */
125
#endif /* !UNIV_HOTBACKUP */
126
/***************************************************************//**
127
Initializes a cached insert undo log header page for new use. NOTE that this
128
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
129
the operation of this function!
130
@return undo log header byte offset on page */
133
trx_undo_insert_header_reuse(
134
/*=========================*/
135
page_t* undo_page, /*!< in/out: insert undo log segment
136
header page, x-latched */
137
trx_id_t trx_id, /*!< in: transaction id */
138
mtr_t* mtr); /*!< in: mtr */
139
/**********************************************************************//**
140
If an update undo log can be discarded immediately, this function frees the
141
space, resetting the page to the proper state for caching. */
144
trx_undo_discard_latest_update_undo(
145
/*================================*/
146
page_t* undo_page, /*!< in: header page of an undo log of size 1 */
147
mtr_t* mtr); /*!< in: mtr */
149
#ifndef UNIV_HOTBACKUP
150
/***********************************************************************//**
151
Gets the previous record in an undo log from the previous page.
152
@return undo log record, the page s-latched, NULL if none */
155
trx_undo_get_prev_rec_from_prev_page(
156
/*=================================*/
157
trx_undo_rec_t* rec, /*!< in: undo record */
158
ulint page_no,/*!< in: undo log header page number */
159
ulint offset, /*!< in: undo log header offset on page */
160
mtr_t* mtr) /*!< in: mtr */
168
undo_page = page_align(rec);
170
prev_page_no = flst_get_prev_addr(undo_page + TRX_UNDO_PAGE_HDR
171
+ TRX_UNDO_PAGE_NODE, mtr)
174
if (prev_page_no == FIL_NULL) {
179
space = page_get_space_id(undo_page);
180
zip_size = fil_space_get_zip_size(space);
182
prev_page = trx_undo_page_get_s_latched(space, zip_size,
185
return(trx_undo_page_get_last_rec(prev_page, page_no, offset));
188
/***********************************************************************//**
189
Gets the previous record in an undo log.
190
@return undo log record, the page s-latched, NULL if none */
193
trx_undo_get_prev_rec(
194
/*==================*/
195
trx_undo_rec_t* rec, /*!< in: undo record */
196
ulint page_no,/*!< in: undo log header page number */
197
ulint offset, /*!< in: undo log header offset on page */
198
mtr_t* mtr) /*!< in: mtr */
200
trx_undo_rec_t* prev_rec;
202
prev_rec = trx_undo_page_get_prev_rec(rec, page_no, offset);
209
/* We have to go to the previous undo log page to look for the
212
return(trx_undo_get_prev_rec_from_prev_page(rec, page_no, offset,
216
/***********************************************************************//**
217
Gets the next record in an undo log from the next page.
218
@return undo log record, the page latched, NULL if none */
221
trx_undo_get_next_rec_from_next_page(
222
/*=================================*/
223
ulint space, /*!< in: undo log header space */
224
ulint zip_size,/*!< in: compressed page size in bytes
225
or 0 for uncompressed pages */
226
page_t* undo_page, /*!< in: undo log page */
227
ulint page_no,/*!< in: undo log header page number */
228
ulint offset, /*!< in: undo log header offset on page */
229
ulint mode, /*!< in: latch mode: RW_S_LATCH or RW_X_LATCH */
230
mtr_t* mtr) /*!< in: mtr */
232
trx_ulogf_t* log_hdr;
237
if (page_no == page_get_page_no(undo_page)) {
239
log_hdr = undo_page + offset;
240
next = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
248
next_page_no = flst_get_next_addr(undo_page + TRX_UNDO_PAGE_HDR
249
+ TRX_UNDO_PAGE_NODE, mtr)
251
if (next_page_no == FIL_NULL) {
256
if (mode == RW_S_LATCH) {
257
next_page = trx_undo_page_get_s_latched(space, zip_size,
260
ut_ad(mode == RW_X_LATCH);
261
next_page = trx_undo_page_get(space, zip_size,
265
return(trx_undo_page_get_first_rec(next_page, page_no, offset));
268
/***********************************************************************//**
269
Gets the next record in an undo log.
270
@return undo log record, the page s-latched, NULL if none */
273
trx_undo_get_next_rec(
274
/*==================*/
275
trx_undo_rec_t* rec, /*!< in: undo record */
276
ulint page_no,/*!< in: undo log header page number */
277
ulint offset, /*!< in: undo log header offset on page */
278
mtr_t* mtr) /*!< in: mtr */
282
trx_undo_rec_t* next_rec;
284
next_rec = trx_undo_page_get_next_rec(rec, page_no, offset);
290
space = page_get_space_id(page_align(rec));
291
zip_size = fil_space_get_zip_size(space);
293
return(trx_undo_get_next_rec_from_next_page(space, zip_size,
299
/***********************************************************************//**
300
Gets the first record in an undo log.
301
@return undo log record, the page latched, NULL if none */
304
trx_undo_get_first_rec(
305
/*===================*/
306
ulint space, /*!< in: undo log header space */
307
ulint zip_size,/*!< in: compressed page size in bytes
308
or 0 for uncompressed pages */
309
ulint page_no,/*!< in: undo log header page number */
310
ulint offset, /*!< in: undo log header offset on page */
311
ulint mode, /*!< in: latching mode: RW_S_LATCH or RW_X_LATCH */
312
mtr_t* mtr) /*!< in: mtr */
317
if (mode == RW_S_LATCH) {
318
undo_page = trx_undo_page_get_s_latched(space, zip_size,
321
undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
324
rec = trx_undo_page_get_first_rec(undo_page, page_no, offset);
330
return(trx_undo_get_next_rec_from_next_page(space, zip_size,
331
undo_page, page_no, offset,
335
/*============== UNDO LOG FILE COPY CREATION AND FREEING ==================*/
337
/**********************************************************************//**
338
Writes the mtr log entry of an undo log page initialization. */
341
trx_undo_page_init_log(
342
/*===================*/
343
page_t* undo_page, /*!< in: undo log page */
344
ulint type, /*!< in: undo log type */
345
mtr_t* mtr) /*!< in: mtr */
347
mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
349
mlog_catenate_ulint_compressed(mtr, type);
351
#else /* !UNIV_HOTBACKUP */
352
# define trx_undo_page_init_log(undo_page,type,mtr) ((void) 0)
353
#endif /* !UNIV_HOTBACKUP */
355
/***********************************************************//**
356
Parses the redo log entry of an undo log page initialization.
357
@return end of log record or NULL */
360
trx_undo_parse_page_init(
361
/*=====================*/
362
byte* ptr, /*!< in: buffer */
363
byte* end_ptr,/*!< in: buffer end */
364
page_t* page, /*!< in: page or NULL */
365
mtr_t* mtr) /*!< in: mtr or NULL */
369
ptr = mach_parse_compressed(ptr, end_ptr, &type);
377
trx_undo_page_init(page, type, mtr);
383
/********************************************************************//**
384
Initializes the fields in an undo log segment page. */
389
page_t* undo_page, /*!< in: undo log segment page */
390
ulint type, /*!< in: undo log segment type */
391
mtr_t* mtr) /*!< in: mtr */
393
trx_upagef_t* page_hdr;
395
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
397
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_TYPE, type);
399
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
400
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
401
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
402
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
404
fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
406
trx_undo_page_init_log(undo_page, type, mtr);
409
#ifndef UNIV_HOTBACKUP
410
/***************************************************************//**
411
Creates a new undo log segment in file.
412
@return DB_SUCCESS if page creation OK possible error codes are:
413
DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE */
418
trx_rseg_t* rseg __attribute__((unused)),/*!< in: rollback segment */
419
trx_rsegf_t* rseg_hdr,/*!< in: rollback segment header, page
421
ulint type, /*!< in: type of the segment: TRX_UNDO_INSERT or
423
ulint* id, /*!< out: slot index within rseg header */
425
/*!< out: segment header page x-latched, NULL
426
if there was an error */
427
mtr_t* mtr) /*!< in: mtr */
432
trx_upagef_t* page_hdr;
433
trx_usegf_t* seg_hdr;
436
ulint err = DB_SUCCESS;
438
ut_ad(mtr && id && rseg_hdr);
439
ut_ad(mutex_own(&(rseg->mutex)));
441
/* fputs(type == TRX_UNDO_INSERT
442
? "Creating insert undo log segment\n"
443
: "Creating update undo log segment\n", stderr); */
444
slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
446
if (slot_no == ULINT_UNDEFINED) {
447
ut_print_timestamp(stderr);
449
" InnoDB: Warning: cannot find a free slot for"
450
" an undo log. Do you have too\n"
451
"InnoDB: many active transactions"
452
" running concurrently?\n");
454
return(DB_TOO_MANY_CONCURRENT_TRXS);
457
space = page_get_space_id(page_align(rseg_hdr));
459
success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
463
return(DB_OUT_OF_FILE_SPACE);
466
/* Allocate a new file segment for the undo log */
467
block = fseg_create_general(space, 0,
469
+ TRX_UNDO_FSEG_HEADER, TRUE, mtr);
471
fil_space_release_free_extents(space, n_reserved);
476
return(DB_OUT_OF_FILE_SPACE);
479
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
481
*undo_page = buf_block_get_frame(block);
483
page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
484
seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
486
trx_undo_page_init(*undo_page, type, mtr);
488
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
489
TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
492
mlog_write_ulint(seg_hdr + TRX_UNDO_LAST_LOG, 0, MLOG_2BYTES, mtr);
494
flst_init(seg_hdr + TRX_UNDO_PAGE_LIST, mtr);
496
flst_add_last(seg_hdr + TRX_UNDO_PAGE_LIST,
497
page_hdr + TRX_UNDO_PAGE_NODE, mtr);
499
trx_rsegf_set_nth_undo(rseg_hdr, slot_no,
500
page_get_page_no(*undo_page), mtr);
506
/**********************************************************************//**
507
Writes the mtr log entry of an undo log header initialization. */
510
trx_undo_header_create_log(
511
/*=======================*/
512
const page_t* undo_page, /*!< in: undo log header page */
513
trx_id_t trx_id, /*!< in: transaction id */
514
mtr_t* mtr) /*!< in: mtr */
516
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_CREATE, mtr);
518
mlog_catenate_dulint_compressed(mtr, trx_id);
520
#else /* !UNIV_HOTBACKUP */
521
# define trx_undo_header_create_log(undo_page,trx_id,mtr) ((void) 0)
522
#endif /* !UNIV_HOTBACKUP */
524
/***************************************************************//**
525
Creates a new undo log header in file. NOTE that this function has its own
526
log record type MLOG_UNDO_HDR_CREATE. You must NOT change the operation of
528
@return header byte offset on page */
531
trx_undo_header_create(
532
/*===================*/
533
page_t* undo_page, /*!< in/out: undo log segment
534
header page, x-latched; it is
535
assumed that there is
536
TRX_UNDO_LOG_XA_HDR_SIZE bytes
538
trx_id_t trx_id, /*!< in: transaction id */
539
mtr_t* mtr) /*!< in: mtr */
541
trx_upagef_t* page_hdr;
542
trx_usegf_t* seg_hdr;
543
trx_ulogf_t* log_hdr;
544
trx_ulogf_t* prev_log_hdr;
549
ut_ad(mtr && undo_page);
551
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
552
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
554
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
556
log_hdr = undo_page + free;
558
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
560
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
562
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
564
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
566
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
568
prev_log = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
571
prev_log_hdr = undo_page + prev_log;
573
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, free);
576
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, free);
578
log_hdr = undo_page + free;
580
mach_write_to_2(log_hdr + TRX_UNDO_DEL_MARKS, TRUE);
582
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
583
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
585
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
586
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
588
mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
589
mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
591
/* Write the log record about the header creation */
592
trx_undo_header_create_log(undo_page, trx_id, mtr);
597
#ifndef UNIV_HOTBACKUP
598
/********************************************************************//**
599
Write X/Open XA Transaction Identification (XID) to undo log header */
604
trx_ulogf_t* log_hdr,/*!< in: undo log header */
605
const XID* xid, /*!< in: X/Open XA Transaction Identification */
606
mtr_t* mtr) /*!< in: mtr */
608
mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT,
609
(ulint)xid->formatID, MLOG_4BYTES, mtr);
611
mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN,
612
(ulint)xid->gtrid_length, MLOG_4BYTES, mtr);
614
mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN,
615
(ulint)xid->bqual_length, MLOG_4BYTES, mtr);
617
mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data,
621
/********************************************************************//**
622
Read X/Open XA Transaction Identification (XID) from undo log header */
627
trx_ulogf_t* log_hdr,/*!< in: undo log header */
628
XID* xid) /*!< out: X/Open XA Transaction Identification */
630
xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
633
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
635
= (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
637
memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE);
640
/***************************************************************//**
641
Adds space for the XA XID after an undo log old-style header. */
644
trx_undo_header_add_space_for_xid(
645
/*==============================*/
646
page_t* undo_page,/*!< in: undo log segment header page */
647
trx_ulogf_t* log_hdr,/*!< in: undo log header */
648
mtr_t* mtr) /*!< in: mtr */
650
trx_upagef_t* page_hdr;
654
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
656
free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
658
/* free is now the end offset of the old style undo log header */
660
ut_a(free == (ulint)(log_hdr - undo_page) + TRX_UNDO_LOG_OLD_HDR_SIZE);
662
new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
663
- TRX_UNDO_LOG_OLD_HDR_SIZE);
665
/* Add space for a XID after the header, update the free offset
666
fields on the undo log page and in the undo log header */
668
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
671
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free,
674
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
678
/**********************************************************************//**
679
Writes the mtr log entry of an undo log header reuse. */
682
trx_undo_insert_header_reuse_log(
683
/*=============================*/
684
const page_t* undo_page, /*!< in: undo log header page */
685
trx_id_t trx_id, /*!< in: transaction id */
686
mtr_t* mtr) /*!< in: mtr */
688
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr);
690
mlog_catenate_dulint_compressed(mtr, trx_id);
692
#else /* !UNIV_HOTBACKUP */
693
# define trx_undo_insert_header_reuse_log(undo_page,trx_id,mtr) ((void) 0)
694
#endif /* !UNIV_HOTBACKUP */
696
/***********************************************************//**
697
Parses the redo log entry of an undo log page header create or reuse.
698
@return end of log record or NULL */
701
trx_undo_parse_page_header(
702
/*=======================*/
703
ulint type, /*!< in: MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE */
704
byte* ptr, /*!< in: buffer */
705
byte* end_ptr,/*!< in: buffer end */
706
page_t* page, /*!< in: page or NULL */
707
mtr_t* mtr) /*!< in: mtr or NULL */
711
ptr = mach_dulint_parse_compressed(ptr, end_ptr, &trx_id);
719
if (type == MLOG_UNDO_HDR_CREATE) {
720
trx_undo_header_create(page, trx_id, mtr);
722
ut_ad(type == MLOG_UNDO_HDR_REUSE);
723
trx_undo_insert_header_reuse(page, trx_id, mtr);
730
/***************************************************************//**
731
Initializes a cached insert undo log header page for new use. NOTE that this
732
function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
733
the operation of this function!
734
@return undo log header byte offset on page */
737
trx_undo_insert_header_reuse(
738
/*=========================*/
739
page_t* undo_page, /*!< in/out: insert undo log segment
740
header page, x-latched */
741
trx_id_t trx_id, /*!< in: transaction id */
742
mtr_t* mtr) /*!< in: mtr */
744
trx_upagef_t* page_hdr;
745
trx_usegf_t* seg_hdr;
746
trx_ulogf_t* log_hdr;
750
ut_ad(mtr && undo_page);
752
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
753
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
755
free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
757
ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
759
log_hdr = undo_page + free;
761
new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
763
/* Insert undo data is not needed after commit: we may free all
764
the space on the page */
766
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
767
+ TRX_UNDO_PAGE_TYPE)
770
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
772
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
774
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
776
log_hdr = undo_page + free;
778
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
779
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
781
mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
782
mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
784
/* Write the log record MLOG_UNDO_HDR_REUSE */
785
trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
790
#ifndef UNIV_HOTBACKUP
791
/**********************************************************************//**
792
Writes the redo log entry of an update undo log header discard. */
795
trx_undo_discard_latest_log(
796
/*========================*/
797
page_t* undo_page, /*!< in: undo log header page */
798
mtr_t* mtr) /*!< in: mtr */
800
mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_DISCARD, mtr);
802
#else /* !UNIV_HOTBACKUP */
803
# define trx_undo_discard_latest_log(undo_page, mtr) ((void) 0)
804
#endif /* !UNIV_HOTBACKUP */
806
/***********************************************************//**
807
Parses the redo log entry of an undo log page header discard.
808
@return end of log record or NULL */
811
trx_undo_parse_discard_latest(
812
/*==========================*/
813
byte* ptr, /*!< in: buffer */
814
byte* end_ptr __attribute__((unused)), /*!< in: buffer end */
815
page_t* page, /*!< in: page or NULL */
816
mtr_t* mtr) /*!< in: mtr or NULL */
821
trx_undo_discard_latest_update_undo(page, mtr);
827
/**********************************************************************//**
828
If an update undo log can be discarded immediately, this function frees the
829
space, resetting the page to the proper state for caching. */
832
trx_undo_discard_latest_update_undo(
833
/*================================*/
834
page_t* undo_page, /*!< in: header page of an undo log of size 1 */
835
mtr_t* mtr) /*!< in: mtr */
837
trx_usegf_t* seg_hdr;
838
trx_upagef_t* page_hdr;
839
trx_ulogf_t* log_hdr;
840
trx_ulogf_t* prev_log_hdr;
842
ulint prev_hdr_offset;
844
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
845
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
847
free = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
848
log_hdr = undo_page + free;
850
prev_hdr_offset = mach_read_from_2(log_hdr + TRX_UNDO_PREV_LOG);
852
if (prev_hdr_offset != 0) {
853
prev_log_hdr = undo_page + prev_hdr_offset;
855
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
856
mach_read_from_2(prev_log_hdr
857
+ TRX_UNDO_LOG_START));
858
mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, 0);
861
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, free);
863
mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_CACHED);
864
mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, prev_hdr_offset);
866
trx_undo_discard_latest_log(undo_page, mtr);
869
#ifndef UNIV_HOTBACKUP
870
/********************************************************************//**
871
Tries to add a page to the undo log segment where the undo log is placed.
872
@return page number if success, else FIL_NULL */
877
trx_t* trx, /*!< in: transaction */
878
trx_undo_t* undo, /*!< in: undo log memory object */
879
mtr_t* mtr) /*!< in: mtr which does not have a latch to any
880
undo log page; the caller must have reserved
881
the rollback segment mutex */
890
ut_ad(mutex_own(&(trx->undo_mutex)));
891
ut_ad(!mutex_own(&kernel_mutex));
892
ut_ad(mutex_own(&(trx->rseg->mutex)));
896
if (rseg->curr_size == rseg->max_size) {
901
header_page = trx_undo_page_get(undo->space, undo->zip_size,
902
undo->hdr_page_no, mtr);
904
success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
911
page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
912
+ TRX_UNDO_FSEG_HEADER,
913
undo->top_page_no + 1, FSP_UP,
916
fil_space_release_free_extents(undo->space, n_reserved);
918
if (page_no == FIL_NULL) {
925
undo->last_page_no = page_no;
927
new_page = trx_undo_page_get(undo->space, undo->zip_size,
930
trx_undo_page_init(new_page, undo->type, mtr);
932
flst_add_last(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
933
new_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
940
/********************************************************************//**
941
Frees an undo log page that is not the header page.
942
@return last page number in remaining log */
947
trx_rseg_t* rseg, /*!< in: rollback segment */
948
ibool in_history, /*!< in: TRUE if the undo log is in the history
950
ulint space, /*!< in: space */
951
ulint hdr_page_no, /*!< in: header page number */
952
ulint page_no, /*!< in: page number to free: must not be the
954
mtr_t* mtr) /*!< in: mtr which does not have a latch to any
955
undo log page; the caller must have reserved
956
the rollback segment mutex */
960
fil_addr_t last_addr;
961
trx_rsegf_t* rseg_header;
965
ut_a(hdr_page_no != page_no);
966
ut_ad(!mutex_own(&kernel_mutex));
967
ut_ad(mutex_own(&(rseg->mutex)));
969
zip_size = rseg->zip_size;
971
undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
973
header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
975
flst_remove(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
976
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
978
fseg_free_page(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER,
979
space, page_no, mtr);
981
last_addr = flst_get_last(header_page + TRX_UNDO_SEG_HDR
982
+ TRX_UNDO_PAGE_LIST, mtr);
986
rseg_header = trx_rsegf_get(space, zip_size,
989
hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
991
ut_ad(hist_size > 0);
992
mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
993
hist_size - 1, MLOG_4BYTES, mtr);
996
return(last_addr.page);
999
/********************************************************************//**
1000
Frees an undo log page when there is also the memory object for the undo
1004
trx_undo_free_page_in_rollback(
1005
/*===========================*/
1006
trx_t* trx __attribute__((unused)), /*!< in: transaction */
1007
trx_undo_t* undo, /*!< in: undo log memory copy */
1008
ulint page_no,/*!< in: page number to free: must not be the
1010
mtr_t* mtr) /*!< in: mtr which does not have a latch to any
1011
undo log page; the caller must have reserved
1012
the rollback segment mutex */
1016
ut_ad(undo->hdr_page_no != page_no);
1017
ut_ad(mutex_own(&(trx->undo_mutex)));
1019
last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
1020
undo->hdr_page_no, page_no, mtr);
1022
undo->last_page_no = last_page_no;
1026
/********************************************************************//**
1027
Empties an undo log header page of undo records for that undo log. Other
1028
undo logs may still have records on that page, if it is an update undo log. */
1031
trx_undo_empty_header_page(
1032
/*=======================*/
1033
ulint space, /*!< in: space */
1034
ulint zip_size, /*!< in: compressed page size in bytes
1035
or 0 for uncompressed pages */
1036
ulint hdr_page_no, /*!< in: header page number */
1037
ulint hdr_offset, /*!< in: header offset */
1038
mtr_t* mtr) /*!< in: mtr */
1040
page_t* header_page;
1041
trx_ulogf_t* log_hdr;
1044
header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
1046
log_hdr = header_page + hdr_offset;
1048
end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
1050
mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
1053
/***********************************************************************//**
1054
Truncates an undo log from the end. This function is used during a rollback
1055
to free space from an undo log. */
1058
trx_undo_truncate_end(
1059
/*==================*/
1060
trx_t* trx, /*!< in: transaction whose undo log it is */
1061
trx_undo_t* undo, /*!< in: undo log */
1062
undo_no_t limit) /*!< in: all undo records with undo number
1063
>= this value should be truncated */
1067
trx_undo_rec_t* rec;
1068
trx_undo_rec_t* trunc_here;
1072
ut_ad(mutex_own(&(trx->undo_mutex)));
1073
ut_ad(mutex_own(&(trx->rseg->mutex)));
1082
last_page_no = undo->last_page_no;
1084
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1085
last_page_no, &mtr);
1087
rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
1091
if (last_page_no == undo->hdr_page_no) {
1096
trx_undo_free_page_in_rollback(
1097
trx, undo, last_page_no, &mtr);
1101
if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit)
1103
/* Truncate at least this record off, maybe
1110
rec = trx_undo_page_get_prev_rec(rec,
1120
mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
1121
+ TRX_UNDO_PAGE_FREE,
1122
trunc_here - undo_page, MLOG_2BYTES, &mtr);
1128
/***********************************************************************//**
1129
Truncates an undo log from the start. This function is used during a purge
1133
trx_undo_truncate_start(
1134
/*====================*/
1135
trx_rseg_t* rseg, /*!< in: rollback segment */
1136
ulint space, /*!< in: space id of the log */
1137
ulint hdr_page_no, /*!< in: header page number */
1138
ulint hdr_offset, /*!< in: header offset on the page */
1139
undo_no_t limit) /*!< in: all undo pages with
1140
undo numbers < this value
1141
should be truncated; NOTE that
1142
the function only frees whole
1143
pages; the header page is not
1144
freed, but emptied, if all the
1145
records there are < limit */
1148
trx_undo_rec_t* rec;
1149
trx_undo_rec_t* last_rec;
1153
ut_ad(mutex_own(&(rseg->mutex)));
1155
if (ut_dulint_is_zero(limit)) {
1162
rec = trx_undo_get_first_rec(space, rseg->zip_size,
1163
hdr_page_no, hdr_offset,
1173
undo_page = page_align(rec);
1175
last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no,
1177
if (ut_dulint_cmp(trx_undo_rec_get_undo_no(last_rec), limit) >= 0) {
1184
page_no = page_get_page_no(undo_page);
1186
if (page_no == hdr_page_no) {
1187
trx_undo_empty_header_page(space, rseg->zip_size,
1188
hdr_page_no, hdr_offset,
1191
trx_undo_free_page(rseg, TRUE, space, hdr_page_no,
1200
/**********************************************************************//**
1201
Frees an undo log segment which is not in the history list. */
1206
trx_undo_t* undo) /*!< in: undo log */
1209
fseg_header_t* file_seg;
1210
trx_rsegf_t* rseg_header;
1211
trx_usegf_t* seg_header;
1221
ut_ad(!mutex_own(&kernel_mutex));
1223
mutex_enter(&(rseg->mutex));
1225
seg_header = trx_undo_page_get(undo->space, undo->zip_size,
1227
&mtr) + TRX_UNDO_SEG_HDR;
1229
file_seg = seg_header + TRX_UNDO_FSEG_HEADER;
1231
finished = fseg_free_step(file_seg, &mtr);
1234
/* Update the rseg header */
1235
rseg_header = trx_rsegf_get(
1236
rseg->space, rseg->zip_size, rseg->page_no,
1238
trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL,
1242
mutex_exit(&(rseg->mutex));
1244
} while (!finished);
1247
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
1249
/********************************************************************//**
1250
Creates and initializes an undo log memory object according to the values
1251
in the header in file, when the database is started. The memory object is
1252
inserted in the appropriate list of rseg.
1253
@return own: the undo log memory object */
1256
trx_undo_mem_create_at_db_start(
1257
/*============================*/
1258
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1259
ulint id, /*!< in: slot index within rseg */
1260
ulint page_no,/*!< in: undo log segment page number */
1261
mtr_t* mtr) /*!< in: mtr */
1264
trx_upagef_t* page_header;
1265
trx_usegf_t* seg_header;
1266
trx_ulogf_t* undo_header;
1272
fil_addr_t last_addr;
1274
trx_undo_rec_t* rec;
1276
ibool xid_exists = FALSE;
1278
if (id >= TRX_RSEG_N_SLOTS) {
1280
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1284
undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
1287
page_header = undo_page + TRX_UNDO_PAGE_HDR;
1289
type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES,
1291
seg_header = undo_page + TRX_UNDO_SEG_HDR;
1293
state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
1295
offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG);
1297
undo_header = undo_page + offset;
1299
trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr);
1301
xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1304
/* Read X/Open XA transaction identification if it exists, or
1307
memset(&xid, 0, sizeof(xid));
1310
if (xid_exists == TRUE) {
1311
trx_undo_read_xid(undo_header, &xid);
1314
mutex_enter(&(rseg->mutex));
1316
undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
1318
mutex_exit(&(rseg->mutex));
1320
undo->dict_operation = mtr_read_ulint(
1321
undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr);
1323
undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr);
1324
undo->state = state;
1325
undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1327
/* If the log segment is being freed, the page list is inconsistent! */
1328
if (state == TRX_UNDO_TO_FREE) {
1333
last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
1335
undo->last_page_no = last_addr.page;
1336
undo->top_page_no = last_addr.page;
1338
last_page = trx_undo_page_get(rseg->space, rseg->zip_size,
1339
undo->last_page_no, mtr);
1341
rec = trx_undo_page_get_last_rec(last_page, page_no, offset);
1346
undo->empty = FALSE;
1347
undo->top_offset = rec - last_page;
1348
undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
1351
if (type == TRX_UNDO_INSERT) {
1352
if (state != TRX_UNDO_CACHED) {
1353
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list,
1356
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_cached,
1360
ut_ad(type == TRX_UNDO_UPDATE);
1361
if (state != TRX_UNDO_CACHED) {
1362
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_list,
1365
UT_LIST_ADD_LAST(undo_list, rseg->update_undo_cached,
1373
/********************************************************************//**
1374
Initializes the undo log lists for a rollback segment memory copy. This
1375
function is only called when the database is started or a new rollback
1377
@return the combined size of undo log segments in pages */
1380
trx_undo_lists_init(
1381
/*================*/
1382
trx_rseg_t* rseg) /*!< in: rollback segment memory object */
1387
trx_rsegf_t* rseg_header;
1391
UT_LIST_INIT(rseg->update_undo_list);
1392
UT_LIST_INIT(rseg->update_undo_cached);
1393
UT_LIST_INIT(rseg->insert_undo_list);
1394
UT_LIST_INIT(rseg->insert_undo_cached);
1398
rseg_header = trx_rsegf_get_new(rseg->space, rseg->zip_size,
1399
rseg->page_no, &mtr);
1401
for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
1402
page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr);
1404
/* In forced recovery: try to avoid operations which look
1405
at database pages; undo logs are rapidly changing data, and
1406
the probability that they are in an inconsistent state is
1409
if (page_no != FIL_NULL
1410
&& srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
1412
undo = trx_undo_mem_create_at_db_start(rseg, i,
1420
rseg_header = trx_rsegf_get(
1421
rseg->space, rseg->zip_size, rseg->page_no,
1431
/********************************************************************//**
1432
Creates and initializes an undo log memory object.
1433
@return own: the undo log memory object */
1436
trx_undo_mem_create(
1437
/*================*/
1438
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1439
ulint id, /*!< in: slot index within rseg */
1440
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
1442
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1444
const XID* xid, /*!< in: X/Open transaction identification */
1445
ulint page_no,/*!< in: undo log header page number */
1446
ulint offset) /*!< in: undo log header byte offset on page */
1450
ut_ad(mutex_own(&(rseg->mutex)));
1452
if (id >= TRX_RSEG_N_SLOTS) {
1454
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
1458
undo = mem_alloc(sizeof(trx_undo_t));
1467
undo->state = TRX_UNDO_ACTIVE;
1468
undo->del_marks = FALSE;
1469
undo->trx_id = trx_id;
1472
undo->dict_operation = FALSE;
1476
undo->space = rseg->space;
1477
undo->zip_size = rseg->zip_size;
1478
undo->hdr_page_no = page_no;
1479
undo->hdr_offset = offset;
1480
undo->last_page_no = page_no;
1484
undo->top_page_no = page_no;
1485
undo->guess_block = NULL;
1490
/********************************************************************//**
1491
Initializes a cached undo log object for new use. */
1494
trx_undo_mem_init_for_reuse(
1495
/*========================*/
1496
trx_undo_t* undo, /*!< in: undo log to init */
1497
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1499
const XID* xid, /*!< in: X/Open XA transaction identification*/
1500
ulint offset) /*!< in: undo log header byte offset on page */
1502
ut_ad(mutex_own(&((undo->rseg)->mutex)));
1504
if (UNIV_UNLIKELY(undo->id >= TRX_RSEG_N_SLOTS)) {
1505
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1508
mem_analyze_corruption(undo);
1512
undo->state = TRX_UNDO_ACTIVE;
1513
undo->del_marks = FALSE;
1514
undo->trx_id = trx_id;
1517
undo->dict_operation = FALSE;
1519
undo->hdr_offset = offset;
1523
/********************************************************************//**
1524
Frees an undo log memory copy. */
1529
trx_undo_t* undo) /*!< in: the undo object to be freed */
1531
if (undo->id >= TRX_RSEG_N_SLOTS) {
1533
"InnoDB: Error: undo->id is %lu\n", (ulong) undo->id);
1540
/**********************************************************************//**
1541
Creates a new undo log.
1542
@return DB_SUCCESS if successful in creating the new undo lob object,
1543
possible error codes are: DB_TOO_MANY_CONCURRENT_TRXS
1544
DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY */
1549
trx_t* trx, /*!< in: transaction */
1550
trx_rseg_t* rseg, /*!< in: rollback segment memory copy */
1551
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
1553
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1555
const XID* xid, /*!< in: X/Open transaction identification*/
1556
trx_undo_t** undo, /*!< out: the new undo log object, undefined
1557
* if did not succeed */
1558
mtr_t* mtr) /*!< in: mtr */
1560
trx_rsegf_t* rseg_header;
1567
ut_ad(mutex_own(&(rseg->mutex)));
1569
if (rseg->curr_size == rseg->max_size) {
1571
return(DB_OUT_OF_FILE_SPACE);
1576
rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size, rseg->page_no,
1579
err = trx_undo_seg_create(rseg, rseg_header, type, &id,
1582
if (err != DB_SUCCESS) {
1583
/* Did not succeed */
1590
page_no = page_get_page_no(undo_page);
1592
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1594
if (trx->support_xa) {
1595
trx_undo_header_add_space_for_xid(undo_page,
1596
undo_page + offset, mtr);
1599
*undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
1601
if (*undo == NULL) {
1603
err = DB_OUT_OF_MEMORY;
1609
/*================ UNDO LOG ASSIGNMENT AND CLEANUP =====================*/
1611
/********************************************************************//**
1612
Reuses a cached undo log.
1613
@return the undo log memory object, NULL if none cached */
1616
trx_undo_reuse_cached(
1617
/*==================*/
1618
trx_t* trx, /*!< in: transaction */
1619
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1620
ulint type, /*!< in: type of the log: TRX_UNDO_INSERT or
1622
trx_id_t trx_id, /*!< in: id of the trx for which the undo log
1624
const XID* xid, /*!< in: X/Open XA transaction identification */
1625
mtr_t* mtr) /*!< in: mtr */
1631
ut_ad(mutex_own(&(rseg->mutex)));
1633
if (type == TRX_UNDO_INSERT) {
1635
undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
1641
UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo);
1643
ut_ad(type == TRX_UNDO_UPDATE);
1645
undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
1651
UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo);
1654
ut_ad(undo->size == 1);
1656
if (undo->id >= TRX_RSEG_N_SLOTS) {
1657
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1659
mem_analyze_corruption(undo);
1663
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1664
undo->hdr_page_no, mtr);
1666
if (type == TRX_UNDO_INSERT) {
1667
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
1669
if (trx->support_xa) {
1670
trx_undo_header_add_space_for_xid(
1671
undo_page, undo_page + offset, mtr);
1674
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
1675
+ TRX_UNDO_PAGE_TYPE)
1676
== TRX_UNDO_UPDATE);
1678
offset = trx_undo_header_create(undo_page, trx_id, mtr);
1680
if (trx->support_xa) {
1681
trx_undo_header_add_space_for_xid(
1682
undo_page, undo_page + offset, mtr);
1686
trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
1691
/**********************************************************************//**
1692
Marks an undo log header as a header of a data dictionary operation
1696
trx_undo_mark_as_dict_operation(
1697
/*============================*/
1698
trx_t* trx, /*!< in: dict op transaction */
1699
trx_undo_t* undo, /*!< in: assigned undo log */
1700
mtr_t* mtr) /*!< in: mtr */
1704
hdr_page = trx_undo_page_get(undo->space, undo->zip_size,
1705
undo->hdr_page_no, mtr);
1707
switch (trx_get_dict_operation(trx)) {
1708
case TRX_DICT_OP_NONE:
1710
case TRX_DICT_OP_INDEX:
1711
/* Do not discard the table on recovery. */
1712
undo->table_id = ut_dulint_zero;
1714
case TRX_DICT_OP_TABLE:
1715
undo->table_id = trx->table_id;
1719
mlog_write_ulint(hdr_page + undo->hdr_offset
1720
+ TRX_UNDO_DICT_TRANS,
1721
TRUE, MLOG_1BYTE, mtr);
1723
mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
1724
undo->table_id, mtr);
1726
undo->dict_operation = TRUE;
1729
/**********************************************************************//**
1730
Assigns an undo log for a transaction. A new undo log is created or a cached
1732
@return DB_SUCCESS if undo log assign successful, possible error codes
1733
are: DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE
1737
trx_undo_assign_undo(
1738
/*=================*/
1739
trx_t* trx, /*!< in: transaction */
1740
ulint type) /*!< in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
1745
ulint err = DB_SUCCESS;
1752
ut_ad(mutex_own(&(trx->undo_mutex)));
1756
ut_ad(!mutex_own(&kernel_mutex));
1758
mutex_enter(&(rseg->mutex));
1760
undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
1763
err = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
1765
if (err != DB_SUCCESS) {
1771
if (type == TRX_UNDO_INSERT) {
1772
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_list, undo);
1773
ut_ad(trx->insert_undo == NULL);
1774
trx->insert_undo = undo;
1776
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_list, undo);
1777
ut_ad(trx->update_undo == NULL);
1778
trx->update_undo = undo;
1781
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
1782
trx_undo_mark_as_dict_operation(trx, undo, &mtr);
1786
mutex_exit(&(rseg->mutex));
1792
/******************************************************************//**
1793
Sets the state of the undo log segment at a transaction finish.
1794
@return undo log segment header page, x-latched */
1797
trx_undo_set_state_at_finish(
1798
/*=========================*/
1799
trx_rseg_t* rseg, /*!< in: rollback segment memory object */
1800
trx_t* trx __attribute__((unused)), /*!< in: transaction */
1801
trx_undo_t* undo, /*!< in: undo log memory copy */
1802
mtr_t* mtr) /*!< in: mtr */
1804
trx_usegf_t* seg_hdr;
1805
trx_upagef_t* page_hdr;
1812
ut_ad(mutex_own(&rseg->mutex));
1814
if (undo->id >= TRX_RSEG_N_SLOTS) {
1815
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1817
mem_analyze_corruption(undo);
1821
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1822
undo->hdr_page_no, mtr);
1824
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1825
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1828
&& mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE)
1829
< TRX_UNDO_PAGE_REUSE_LIMIT) {
1831
/* This is a heuristic to avoid the problem of all UNDO
1832
slots ending up in one of the UNDO lists. Previously if
1833
the server crashed with all the slots in one of the lists,
1834
transactions that required the slots of a different type
1835
would fail for lack of slots. */
1837
if (UT_LIST_GET_LEN(rseg->update_undo_list) < 500
1838
&& UT_LIST_GET_LEN(rseg->insert_undo_list) < 500) {
1840
state = TRX_UNDO_CACHED;
1842
state = TRX_UNDO_TO_FREE;
1845
} else if (undo->type == TRX_UNDO_INSERT) {
1847
state = TRX_UNDO_TO_FREE;
1849
state = TRX_UNDO_TO_PURGE;
1852
undo->state = state;
1854
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr);
1859
/******************************************************************//**
1860
Sets the state of the undo log segment at a transaction prepare.
1861
@return undo log segment header page, x-latched */
1864
trx_undo_set_state_at_prepare(
1865
/*==========================*/
1866
trx_t* trx, /*!< in: transaction */
1867
trx_undo_t* undo, /*!< in: undo log memory copy */
1868
mtr_t* mtr) /*!< in: mtr */
1870
trx_usegf_t* seg_hdr;
1871
trx_upagef_t* page_hdr;
1872
trx_ulogf_t* undo_header;
1876
ut_ad(trx && undo && mtr);
1878
if (undo->id >= TRX_RSEG_N_SLOTS) {
1879
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
1881
mem_analyze_corruption(undo);
1885
undo_page = trx_undo_page_get(undo->space, undo->zip_size,
1886
undo->hdr_page_no, mtr);
1888
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
1889
page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
1891
/*------------------------------*/
1892
undo->state = TRX_UNDO_PREPARED;
1893
undo->xid = trx->xid;
1894
/*------------------------------*/
1896
mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
1899
offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
1900
undo_header = undo_page + offset;
1902
mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS,
1903
TRUE, MLOG_1BYTE, mtr);
1905
trx_undo_write_xid(undo_header, &undo->xid, mtr);
1910
/**********************************************************************//**
1911
Adds the update undo log header as the first in the history list, and
1912
frees the memory object, or puts it to the list of cached update undo log
1916
trx_undo_update_cleanup(
1917
/*====================*/
1918
trx_t* trx, /*!< in: trx owning the update undo log */
1919
page_t* undo_page, /*!< in: update undo log header page,
1921
mtr_t* mtr) /*!< in: mtr */
1926
undo = trx->update_undo;
1929
ut_ad(mutex_own(&(rseg->mutex)));
1931
trx_purge_add_update_undo_to_history(trx, undo_page, mtr);
1933
UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo);
1935
trx->update_undo = NULL;
1937
if (undo->state == TRX_UNDO_CACHED) {
1939
UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo);
1941
ut_ad(undo->state == TRX_UNDO_TO_PURGE);
1943
trx_undo_mem_free(undo);
1947
/******************************************************************//**
1948
Frees or caches an insert undo log after a transaction commit or rollback.
1949
Knowledge of inserts is not needed after a commit or rollback, therefore
1950
the data can be discarded. */
1953
trx_undo_insert_cleanup(
1954
/*====================*/
1955
trx_t* trx) /*!< in: transaction handle */
1960
undo = trx->insert_undo;
1965
mutex_enter(&(rseg->mutex));
1967
UT_LIST_REMOVE(undo_list, rseg->insert_undo_list, undo);
1968
trx->insert_undo = NULL;
1970
if (undo->state == TRX_UNDO_CACHED) {
1972
UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_cached, undo);
1974
ut_ad(undo->state == TRX_UNDO_TO_FREE);
1976
/* Delete first the undo log segment in the file */
1978
mutex_exit(&(rseg->mutex));
1980
trx_undo_seg_free(undo);
1982
mutex_enter(&(rseg->mutex));
1984
ut_ad(rseg->curr_size > undo->size);
1986
rseg->curr_size -= undo->size;
1988
trx_undo_mem_free(undo);
1991
mutex_exit(&(rseg->mutex));
1993
#endif /* !UNIV_HOTBACKUP */