00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "trx0undo.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "trx0undo.ic"
00030 #endif
00031
00032 #include "fsp0fsp.h"
00033 #ifndef UNIV_HOTBACKUP
00034 #include "mach0data.h"
00035 #include "mtr0log.h"
00036 #include "trx0rseg.h"
00037 #include "trx0trx.h"
00038 #include "srv0srv.h"
00039 #include "trx0rec.h"
00040 #include "trx0purge.h"
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 #endif
00097
00098
00100 static
00101 void
00102 trx_undo_page_init(
00103
00104 page_t* undo_page,
00105 ulint type,
00106 mtr_t* mtr);
00108 #ifndef UNIV_HOTBACKUP
00109
00112 static
00113 trx_undo_t*
00114 trx_undo_mem_create(
00115
00116 trx_rseg_t* rseg,
00117 ulint id,
00118 ulint type,
00120 trx_id_t trx_id,
00122 const XID* xid,
00123 ulint page_no,
00124 ulint offset);
00125 #endif
00126
00131 static
00132 ulint
00133 trx_undo_insert_header_reuse(
00134
00135 page_t* undo_page,
00137 trx_id_t trx_id,
00138 mtr_t* mtr);
00139
00142 static
00143 void
00144 trx_undo_discard_latest_update_undo(
00145
00146 page_t* undo_page,
00147 mtr_t* mtr);
00149 #ifndef UNIV_HOTBACKUP
00150
00153 static
00154 trx_undo_rec_t*
00155 trx_undo_get_prev_rec_from_prev_page(
00156
00157 trx_undo_rec_t* rec,
00158 ulint page_no,
00159 ulint offset,
00160 mtr_t* mtr)
00161 {
00162 ulint space;
00163 ulint zip_size;
00164 ulint prev_page_no;
00165 page_t* prev_page;
00166 page_t* undo_page;
00167
00168 undo_page = page_align(rec);
00169
00170 prev_page_no = flst_get_prev_addr(undo_page + TRX_UNDO_PAGE_HDR
00171 + TRX_UNDO_PAGE_NODE, mtr)
00172 .page;
00173
00174 if (prev_page_no == FIL_NULL) {
00175
00176 return(NULL);
00177 }
00178
00179 space = page_get_space_id(undo_page);
00180 zip_size = fil_space_get_zip_size(space);
00181
00182 prev_page = trx_undo_page_get_s_latched(space, zip_size,
00183 prev_page_no, mtr);
00184
00185 return(trx_undo_page_get_last_rec(prev_page, page_no, offset));
00186 }
00187
00188
00191 UNIV_INTERN
00192 trx_undo_rec_t*
00193 trx_undo_get_prev_rec(
00194
00195 trx_undo_rec_t* rec,
00196 ulint page_no,
00197 ulint offset,
00198 mtr_t* mtr)
00199 {
00200 trx_undo_rec_t* prev_rec;
00201
00202 prev_rec = trx_undo_page_get_prev_rec(rec, page_no, offset);
00203
00204 if (prev_rec) {
00205
00206 return(prev_rec);
00207 }
00208
00209
00210
00211
00212 return(trx_undo_get_prev_rec_from_prev_page(rec, page_no, offset,
00213 mtr));
00214 }
00215
00216
00219 static
00220 trx_undo_rec_t*
00221 trx_undo_get_next_rec_from_next_page(
00222
00223 ulint space,
00224 ulint zip_size,
00226 page_t* undo_page,
00227 ulint page_no,
00228 ulint offset,
00229 ulint mode,
00230 mtr_t* mtr)
00231 {
00232 trx_ulogf_t* log_hdr;
00233 ulint next_page_no;
00234 page_t* next_page;
00235 ulint next;
00236
00237 if (page_no == page_get_page_no(undo_page)) {
00238
00239 log_hdr = undo_page + offset;
00240 next = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
00241
00242 if (next != 0) {
00243
00244 return(NULL);
00245 }
00246 }
00247
00248 next_page_no = flst_get_next_addr(undo_page + TRX_UNDO_PAGE_HDR
00249 + TRX_UNDO_PAGE_NODE, mtr)
00250 .page;
00251 if (next_page_no == FIL_NULL) {
00252
00253 return(NULL);
00254 }
00255
00256 if (mode == RW_S_LATCH) {
00257 next_page = trx_undo_page_get_s_latched(space, zip_size,
00258 next_page_no, mtr);
00259 } else {
00260 ut_ad(mode == RW_X_LATCH);
00261 next_page = trx_undo_page_get(space, zip_size,
00262 next_page_no, mtr);
00263 }
00264
00265 return(trx_undo_page_get_first_rec(next_page, page_no, offset));
00266 }
00267
00268
00271 UNIV_INTERN
00272 trx_undo_rec_t*
00273 trx_undo_get_next_rec(
00274
00275 trx_undo_rec_t* rec,
00276 ulint page_no,
00277 ulint offset,
00278 mtr_t* mtr)
00279 {
00280 ulint space;
00281 ulint zip_size;
00282 trx_undo_rec_t* next_rec;
00283
00284 next_rec = trx_undo_page_get_next_rec(rec, page_no, offset);
00285
00286 if (next_rec) {
00287 return(next_rec);
00288 }
00289
00290 space = page_get_space_id(page_align(rec));
00291 zip_size = fil_space_get_zip_size(space);
00292
00293 return(trx_undo_get_next_rec_from_next_page(space, zip_size,
00294 page_align(rec),
00295 page_no, offset,
00296 RW_S_LATCH, mtr));
00297 }
00298
00299
00302 UNIV_INTERN
00303 trx_undo_rec_t*
00304 trx_undo_get_first_rec(
00305
00306 ulint space,
00307 ulint zip_size,
00309 ulint page_no,
00310 ulint offset,
00311 ulint mode,
00312 mtr_t* mtr)
00313 {
00314 page_t* undo_page;
00315 trx_undo_rec_t* rec;
00316
00317 if (mode == RW_S_LATCH) {
00318 undo_page = trx_undo_page_get_s_latched(space, zip_size,
00319 page_no, mtr);
00320 } else {
00321 undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
00322 }
00323
00324 rec = trx_undo_page_get_first_rec(undo_page, page_no, offset);
00325
00326 if (rec) {
00327 return(rec);
00328 }
00329
00330 return(trx_undo_get_next_rec_from_next_page(space, zip_size,
00331 undo_page, page_no, offset,
00332 mode, mtr));
00333 }
00334
00335
00336
00337
00339 UNIV_INLINE
00340 void
00341 trx_undo_page_init_log(
00342
00343 page_t* undo_page,
00344 ulint type,
00345 mtr_t* mtr)
00346 {
00347 mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
00348
00349 mlog_catenate_ulint_compressed(mtr, type);
00350 }
00351 #else
00352 # define trx_undo_page_init_log(undo_page,type,mtr) ((void) 0)
00353 #endif
00354
00355
00358 UNIV_INTERN
00359 byte*
00360 trx_undo_parse_page_init(
00361
00362 byte* ptr,
00363 byte* end_ptr,
00364 page_t* page,
00365 mtr_t* mtr)
00366 {
00367 ulint type;
00368
00369 ptr = mach_parse_compressed(ptr, end_ptr, &type);
00370
00371 if (ptr == NULL) {
00372
00373 return(NULL);
00374 }
00375
00376 if (page) {
00377 trx_undo_page_init(page, type, mtr);
00378 }
00379
00380 return(ptr);
00381 }
00382
00383
00385 static
00386 void
00387 trx_undo_page_init(
00388
00389 page_t* undo_page,
00390 ulint type,
00391 mtr_t* mtr)
00392 {
00393 trx_upagef_t* page_hdr;
00394
00395 page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
00396
00397 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_TYPE, type);
00398
00399 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
00400 TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
00401 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
00402 TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
00403
00404 fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
00405
00406 trx_undo_page_init_log(undo_page, type, mtr);
00407 }
00408
00409 #ifndef UNIV_HOTBACKUP
00410
00414 static
00415 ulint
00416 trx_undo_seg_create(
00417
00418 trx_rseg_t* ,
00419 trx_rsegf_t* rseg_hdr,
00421 ulint type,
00423 ulint* id,
00424 page_t** undo_page,
00427 mtr_t* mtr)
00428 {
00429 ulint slot_no;
00430 ulint space;
00431 buf_block_t* block;
00432 trx_upagef_t* page_hdr;
00433 trx_usegf_t* seg_hdr;
00434 ulint n_reserved;
00435 ibool success;
00436 ulint err = DB_SUCCESS;
00437
00438 ut_ad(mtr && id && rseg_hdr);
00439 ut_ad(mutex_own(&(rseg->mutex)));
00440
00441
00442
00443
00444 slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
00445
00446 if (slot_no == ULINT_UNDEFINED) {
00447 ut_print_timestamp(stderr);
00448 fprintf(stderr,
00449 " InnoDB: Warning: cannot find a free slot for"
00450 " an undo log. Do you have too\n"
00451 "InnoDB: many active transactions"
00452 " running concurrently?\n");
00453
00454 return(DB_TOO_MANY_CONCURRENT_TRXS);
00455 }
00456
00457 space = page_get_space_id(page_align(rseg_hdr));
00458
00459 success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
00460 mtr);
00461 if (!success) {
00462
00463 return(DB_OUT_OF_FILE_SPACE);
00464 }
00465
00466
00467 block = fseg_create_general(space, 0,
00468 TRX_UNDO_SEG_HDR
00469 + TRX_UNDO_FSEG_HEADER, TRUE, mtr);
00470
00471 fil_space_release_free_extents(space, n_reserved);
00472
00473 if (block == NULL) {
00474
00475
00476 return(DB_OUT_OF_FILE_SPACE);
00477 }
00478
00479 buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
00480
00481 *undo_page = buf_block_get_frame(block);
00482
00483 page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
00484 seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
00485
00486 trx_undo_page_init(*undo_page, type, mtr);
00487
00488 mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
00489 TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
00490 MLOG_2BYTES, mtr);
00491
00492 mlog_write_ulint(seg_hdr + TRX_UNDO_LAST_LOG, 0, MLOG_2BYTES, mtr);
00493
00494 flst_init(seg_hdr + TRX_UNDO_PAGE_LIST, mtr);
00495
00496 flst_add_last(seg_hdr + TRX_UNDO_PAGE_LIST,
00497 page_hdr + TRX_UNDO_PAGE_NODE, mtr);
00498
00499 trx_rsegf_set_nth_undo(rseg_hdr, slot_no,
00500 page_get_page_no(*undo_page), mtr);
00501 *id = slot_no;
00502
00503 return(err);
00504 }
00505
00506
00508 UNIV_INLINE
00509 void
00510 trx_undo_header_create_log(
00511
00512 const page_t* undo_page,
00513 trx_id_t trx_id,
00514 mtr_t* mtr)
00515 {
00516 mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_CREATE, mtr);
00517
00518 mlog_catenate_ull_compressed(mtr, trx_id);
00519 }
00520 #else
00521 # define trx_undo_header_create_log(undo_page,trx_id,mtr) ((void) 0)
00522 #endif
00523
00524
00529 static
00530 ulint
00531 trx_undo_header_create(
00532
00533 page_t* undo_page,
00538 trx_id_t trx_id,
00539 mtr_t* mtr)
00540 {
00541 trx_upagef_t* page_hdr;
00542 trx_usegf_t* seg_hdr;
00543 trx_ulogf_t* log_hdr;
00544 trx_ulogf_t* prev_log_hdr;
00545 ulint prev_log;
00546 ulint free;
00547 ulint new_free;
00548
00549 ut_ad(mtr && undo_page);
00550
00551 page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
00552 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
00553
00554 free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
00555
00556 log_hdr = undo_page + free;
00557
00558 new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
00559
00560 ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
00561
00562 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
00563
00564 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
00565
00566 mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
00567
00568 prev_log = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
00569
00570 if (prev_log != 0) {
00571 prev_log_hdr = undo_page + prev_log;
00572
00573 mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, free);
00574 }
00575
00576 mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, free);
00577
00578 log_hdr = undo_page + free;
00579
00580 mach_write_to_2(log_hdr + TRX_UNDO_DEL_MARKS, TRUE);
00581
00582 mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
00583 mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
00584
00585 mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
00586 mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
00587
00588 mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
00589 mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
00590
00591
00592 trx_undo_header_create_log(undo_page, trx_id, mtr);
00593
00594 return(free);
00595 }
00596
00597 #ifndef UNIV_HOTBACKUP
00598
00600 static
00601 void
00602 trx_undo_write_xid(
00603
00604 trx_ulogf_t* log_hdr,
00605 const XID* xid,
00606 mtr_t* mtr)
00607 {
00608 mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT,
00609 (ulint)xid->formatID, MLOG_4BYTES, mtr);
00610
00611 mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN,
00612 (ulint)xid->gtrid_length, MLOG_4BYTES, mtr);
00613
00614 mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN,
00615 (ulint)xid->bqual_length, MLOG_4BYTES, mtr);
00616
00617 mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data,
00618 XIDDATASIZE, mtr);
00619 }
00620
00621
00623 static
00624 void
00625 trx_undo_read_xid(
00626
00627 trx_ulogf_t* log_hdr,
00628 XID* xid)
00629 {
00630 xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
00631
00632 xid->gtrid_length
00633 = (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
00634 xid->bqual_length
00635 = (long) mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
00636
00637 memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE);
00638 }
00639
00640
00642 static
00643 void
00644 trx_undo_header_add_space_for_xid(
00645
00646 page_t* undo_page,
00647 trx_ulogf_t* log_hdr,
00648 mtr_t* mtr)
00649 {
00650 trx_upagef_t* page_hdr;
00651 ulint free;
00652 ulint new_free;
00653
00654 page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
00655
00656 free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
00657
00658
00659
00660 ut_a(free == (ulint)(log_hdr - undo_page) + TRX_UNDO_LOG_OLD_HDR_SIZE);
00661
00662 new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
00663 - TRX_UNDO_LOG_OLD_HDR_SIZE);
00664
00665
00666
00667
00668 mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
00669 MLOG_2BYTES, mtr);
00670
00671 mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free,
00672 MLOG_2BYTES, mtr);
00673
00674 mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
00675 MLOG_2BYTES, mtr);
00676 }
00677
00678
00680 UNIV_INLINE
00681 void
00682 trx_undo_insert_header_reuse_log(
00683
00684 const page_t* undo_page,
00685 trx_id_t trx_id,
00686 mtr_t* mtr)
00687 {
00688 mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr);
00689
00690 mlog_catenate_ull_compressed(mtr, trx_id);
00691 }
00692 #else
00693 # define trx_undo_insert_header_reuse_log(undo_page,trx_id,mtr) ((void) 0)
00694 #endif
00695
00696
00699 UNIV_INTERN
00700 byte*
00701 trx_undo_parse_page_header(
00702
00703 ulint type,
00704 byte* ptr,
00705 byte* end_ptr,
00706 page_t* page,
00707 mtr_t* mtr)
00708 {
00709 trx_id_t trx_id;
00710
00711
00712 ut_d(trx_id = 0);
00713
00714
00715 UNIV_MEM_INVALID(&trx_id, sizeof trx_id);
00716
00717 ptr = mach_ull_parse_compressed(ptr, end_ptr, &trx_id);
00718
00719 if (ptr == NULL) {
00720
00721 return(NULL);
00722 }
00723
00724 if (page) {
00725 if (type == MLOG_UNDO_HDR_CREATE) {
00726 trx_undo_header_create(page, trx_id, mtr);
00727 } else {
00728 ut_ad(type == MLOG_UNDO_HDR_REUSE);
00729 trx_undo_insert_header_reuse(page, trx_id, mtr);
00730 }
00731 }
00732
00733 return(ptr);
00734 }
00735
00736
00741 static
00742 ulint
00743 trx_undo_insert_header_reuse(
00744
00745 page_t* undo_page,
00747 trx_id_t trx_id,
00748 mtr_t* mtr)
00749 {
00750 trx_upagef_t* page_hdr;
00751 trx_usegf_t* seg_hdr;
00752 trx_ulogf_t* log_hdr;
00753 ulint free;
00754 ulint new_free;
00755
00756 ut_ad(mtr && undo_page);
00757
00758 page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
00759 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
00760
00761 free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
00762
00763 ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
00764
00765 log_hdr = undo_page + free;
00766
00767 new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
00768
00769
00770
00771
00772 ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
00773 + TRX_UNDO_PAGE_TYPE)
00774 == TRX_UNDO_INSERT);
00775
00776 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
00777
00778 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
00779
00780 mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
00781
00782 log_hdr = undo_page + free;
00783
00784 mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
00785 mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
00786
00787 mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
00788 mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
00789
00790
00791 trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
00792
00793 return(free);
00794 }
00795
00796 #ifndef UNIV_HOTBACKUP
00797
00799 UNIV_INLINE
00800 void
00801 trx_undo_discard_latest_log(
00802
00803 page_t* undo_page,
00804 mtr_t* mtr)
00805 {
00806 mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_DISCARD, mtr);
00807 }
00808 #else
00809 # define trx_undo_discard_latest_log(undo_page, mtr) ((void) 0)
00810 #endif
00811
00812
00815 UNIV_INTERN
00816 byte*
00817 trx_undo_parse_discard_latest(
00818
00819 byte* ptr,
00820 byte* ,
00821 page_t* page,
00822 mtr_t* mtr)
00823 {
00824 ut_ad(end_ptr);
00825
00826 if (page) {
00827 trx_undo_discard_latest_update_undo(page, mtr);
00828 }
00829
00830 return(ptr);
00831 }
00832
00833
00836 static
00837 void
00838 trx_undo_discard_latest_update_undo(
00839
00840 page_t* undo_page,
00841 mtr_t* mtr)
00842 {
00843 trx_usegf_t* seg_hdr;
00844 trx_upagef_t* page_hdr;
00845 trx_ulogf_t* log_hdr;
00846 trx_ulogf_t* prev_log_hdr;
00847 ulint free;
00848 ulint prev_hdr_offset;
00849
00850 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
00851 page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
00852
00853 free = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
00854 log_hdr = undo_page + free;
00855
00856 prev_hdr_offset = mach_read_from_2(log_hdr + TRX_UNDO_PREV_LOG);
00857
00858 if (prev_hdr_offset != 0) {
00859 prev_log_hdr = undo_page + prev_hdr_offset;
00860
00861 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
00862 mach_read_from_2(prev_log_hdr
00863 + TRX_UNDO_LOG_START));
00864 mach_write_to_2(prev_log_hdr + TRX_UNDO_NEXT_LOG, 0);
00865 }
00866
00867 mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, free);
00868
00869 mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_CACHED);
00870 mach_write_to_2(seg_hdr + TRX_UNDO_LAST_LOG, prev_hdr_offset);
00871
00872 trx_undo_discard_latest_log(undo_page, mtr);
00873 }
00874
00875 #ifndef UNIV_HOTBACKUP
00876
00879 UNIV_INTERN
00880 ulint
00881 trx_undo_add_page(
00882
00883 trx_t* trx,
00884 trx_undo_t* undo,
00885 mtr_t* mtr)
00888 {
00889 page_t* header_page;
00890 page_t* new_page;
00891 trx_rseg_t* rseg;
00892 ulint page_no;
00893 ulint n_reserved;
00894 ibool success;
00895
00896 ut_ad(mutex_own(&(trx->undo_mutex)));
00897 ut_ad(!mutex_own(&kernel_mutex));
00898 ut_ad(mutex_own(&(trx->rseg->mutex)));
00899
00900 rseg = trx->rseg;
00901
00902 if (rseg->curr_size == rseg->max_size) {
00903
00904 return(FIL_NULL);
00905 }
00906
00907 header_page = trx_undo_page_get(undo->space, undo->zip_size,
00908 undo->hdr_page_no, mtr);
00909
00910 success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
00911 FSP_UNDO, mtr);
00912 if (!success) {
00913
00914 return(FIL_NULL);
00915 }
00916
00917 page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
00918 + TRX_UNDO_FSEG_HEADER,
00919 undo->top_page_no + 1, FSP_UP,
00920 TRUE, mtr);
00921
00922 fil_space_release_free_extents(undo->space, n_reserved);
00923
00924 if (page_no == FIL_NULL) {
00925
00926
00927
00928 return(FIL_NULL);
00929 }
00930
00931 undo->last_page_no = page_no;
00932
00933 new_page = trx_undo_page_get(undo->space, undo->zip_size,
00934 page_no, mtr);
00935
00936 trx_undo_page_init(new_page, undo->type, mtr);
00937
00938 flst_add_last(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
00939 new_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
00940 undo->size++;
00941 rseg->curr_size++;
00942
00943 return(page_no);
00944 }
00945
00946
00949 static
00950 ulint
00951 trx_undo_free_page(
00952
00953 trx_rseg_t* rseg,
00954 ibool in_history,
00956 ulint space,
00957 ulint hdr_page_no,
00958 ulint page_no,
00960 mtr_t* mtr)
00963 {
00964 page_t* header_page;
00965 page_t* undo_page;
00966 fil_addr_t last_addr;
00967 trx_rsegf_t* rseg_header;
00968 ulint hist_size;
00969 ulint zip_size;
00970
00971 ut_a(hdr_page_no != page_no);
00972 ut_ad(!mutex_own(&kernel_mutex));
00973 ut_ad(mutex_own(&(rseg->mutex)));
00974
00975 zip_size = rseg->zip_size;
00976
00977 undo_page = trx_undo_page_get(space, zip_size, page_no, mtr);
00978
00979 header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
00980
00981 flst_remove(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
00982 undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
00983
00984 fseg_free_page(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER,
00985 space, page_no, mtr);
00986
00987 last_addr = flst_get_last(header_page + TRX_UNDO_SEG_HDR
00988 + TRX_UNDO_PAGE_LIST, mtr);
00989 rseg->curr_size--;
00990
00991 if (in_history) {
00992 rseg_header = trx_rsegf_get(space, zip_size,
00993 rseg->page_no, mtr);
00994
00995 hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
00996 MLOG_4BYTES, mtr);
00997 ut_ad(hist_size > 0);
00998 mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
00999 hist_size - 1, MLOG_4BYTES, mtr);
01000 }
01001
01002 return(last_addr.page);
01003 }
01004
01005
01008 static
01009 void
01010 trx_undo_free_page_in_rollback(
01011
01012 trx_t* ,
01013 trx_undo_t* undo,
01014 ulint page_no,
01016 mtr_t* mtr)
01019 {
01020 ulint last_page_no;
01021
01022 ut_ad(undo->hdr_page_no != page_no);
01023 ut_ad(mutex_own(&(trx->undo_mutex)));
01024
01025 last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
01026 undo->hdr_page_no, page_no, mtr);
01027
01028 undo->last_page_no = last_page_no;
01029 undo->size--;
01030 }
01031
01032
01035 static
01036 void
01037 trx_undo_empty_header_page(
01038
01039 ulint space,
01040 ulint zip_size,
01042 ulint hdr_page_no,
01043 ulint hdr_offset,
01044 mtr_t* mtr)
01045 {
01046 page_t* header_page;
01047 trx_ulogf_t* log_hdr;
01048 ulint end;
01049
01050 header_page = trx_undo_page_get(space, zip_size, hdr_page_no, mtr);
01051
01052 log_hdr = header_page + hdr_offset;
01053
01054 end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
01055
01056 mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
01057 }
01058
01059
01062 UNIV_INTERN
01063 void
01064 trx_undo_truncate_end(
01065
01066 trx_t* trx,
01067 trx_undo_t* undo,
01068 undo_no_t limit)
01070 {
01071 page_t* undo_page;
01072 ulint last_page_no;
01073 trx_undo_rec_t* rec;
01074 trx_undo_rec_t* trunc_here;
01075 mtr_t mtr;
01076
01077 ut_ad(mutex_own(&(trx->undo_mutex)));
01078 ut_ad(mutex_own(&(trx->rseg->mutex)));
01079
01080 for (;;) {
01081 mtr_start(&mtr);
01082
01083 trunc_here = NULL;
01084
01085 last_page_no = undo->last_page_no;
01086
01087 undo_page = trx_undo_page_get(undo->space, undo->zip_size,
01088 last_page_no, &mtr);
01089
01090 rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
01091 undo->hdr_offset);
01092 for (;;) {
01093 if (rec == NULL) {
01094 if (last_page_no == undo->hdr_page_no) {
01095
01096 goto function_exit;
01097 }
01098
01099 trx_undo_free_page_in_rollback(
01100 trx, undo, last_page_no, &mtr);
01101 break;
01102 }
01103
01104 if (trx_undo_rec_get_undo_no(rec) >= limit) {
01105
01106
01107 trunc_here = rec;
01108 } else {
01109 goto function_exit;
01110 }
01111
01112 rec = trx_undo_page_get_prev_rec(rec,
01113 undo->hdr_page_no,
01114 undo->hdr_offset);
01115 }
01116
01117 mtr_commit(&mtr);
01118 }
01119
01120 function_exit:
01121 if (trunc_here) {
01122 mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
01123 + TRX_UNDO_PAGE_FREE,
01124 trunc_here - undo_page, MLOG_2BYTES, &mtr);
01125 }
01126
01127 mtr_commit(&mtr);
01128 }
01129
01130
01133 UNIV_INTERN
01134 void
01135 trx_undo_truncate_start(
01136
01137 trx_rseg_t* rseg,
01138 ulint space,
01139 ulint hdr_page_no,
01140 ulint hdr_offset,
01141 undo_no_t limit)
01148 {
01149 page_t* undo_page;
01150 trx_undo_rec_t* rec;
01151 trx_undo_rec_t* last_rec;
01152 ulint page_no;
01153 mtr_t mtr;
01154
01155 ut_ad(mutex_own(&(rseg->mutex)));
01156
01157 if (!limit) {
01158
01159 return;
01160 }
01161 loop:
01162 mtr_start(&mtr);
01163
01164 rec = trx_undo_get_first_rec(space, rseg->zip_size,
01165 hdr_page_no, hdr_offset,
01166 RW_X_LATCH, &mtr);
01167 if (rec == NULL) {
01168
01169
01170 mtr_commit(&mtr);
01171
01172 return;
01173 }
01174
01175 undo_page = page_align(rec);
01176
01177 last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no,
01178 hdr_offset);
01179 if (trx_undo_rec_get_undo_no(last_rec) >= limit) {
01180
01181 mtr_commit(&mtr);
01182
01183 return;
01184 }
01185
01186 page_no = page_get_page_no(undo_page);
01187
01188 if (page_no == hdr_page_no) {
01189 trx_undo_empty_header_page(space, rseg->zip_size,
01190 hdr_page_no, hdr_offset,
01191 &mtr);
01192 } else {
01193 trx_undo_free_page(rseg, TRUE, space, hdr_page_no,
01194 page_no, &mtr);
01195 }
01196
01197 mtr_commit(&mtr);
01198
01199 goto loop;
01200 }
01201
01202
01204 static
01205 void
01206 trx_undo_seg_free(
01207
01208 trx_undo_t* undo)
01209 {
01210 trx_rseg_t* rseg;
01211 fseg_header_t* file_seg;
01212 trx_rsegf_t* rseg_header;
01213 trx_usegf_t* seg_header;
01214 ibool finished;
01215 mtr_t mtr;
01216
01217 rseg = undo->rseg;
01218
01219 do {
01220
01221 mtr_start(&mtr);
01222
01223 ut_ad(!mutex_own(&kernel_mutex));
01224
01225 mutex_enter(&(rseg->mutex));
01226
01227 seg_header = trx_undo_page_get(undo->space, undo->zip_size,
01228 undo->hdr_page_no,
01229 &mtr) + TRX_UNDO_SEG_HDR;
01230
01231 file_seg = seg_header + TRX_UNDO_FSEG_HEADER;
01232
01233 finished = fseg_free_step(file_seg, &mtr);
01234
01235 if (finished) {
01236
01237 rseg_header = trx_rsegf_get(
01238 rseg->space, rseg->zip_size, rseg->page_no,
01239 &mtr);
01240 trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL,
01241 &mtr);
01242 }
01243
01244 mutex_exit(&(rseg->mutex));
01245 mtr_commit(&mtr);
01246 } while (!finished);
01247 }
01248
01249
01250
01251
01256 static
01257 trx_undo_t*
01258 trx_undo_mem_create_at_db_start(
01259
01260 trx_rseg_t* rseg,
01261 ulint id,
01262 ulint page_no,
01263 mtr_t* mtr)
01264 {
01265 page_t* undo_page;
01266 trx_upagef_t* page_header;
01267 trx_usegf_t* seg_header;
01268 trx_ulogf_t* undo_header;
01269 trx_undo_t* undo;
01270 ulint type;
01271 ulint state;
01272 trx_id_t trx_id;
01273 ulint offset;
01274 fil_addr_t last_addr;
01275 page_t* last_page;
01276 trx_undo_rec_t* rec;
01277 XID xid;
01278 ibool xid_exists = FALSE;
01279
01280 if (id >= TRX_RSEG_N_SLOTS) {
01281 fprintf(stderr,
01282 "InnoDB: Error: undo->id is %lu\n", (ulong) id);
01283 ut_error;
01284 }
01285
01286 undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
01287 page_no, mtr);
01288
01289 page_header = undo_page + TRX_UNDO_PAGE_HDR;
01290
01291 type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES,
01292 mtr);
01293 seg_header = undo_page + TRX_UNDO_SEG_HDR;
01294
01295 state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
01296
01297 offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG);
01298
01299 undo_header = undo_page + offset;
01300
01301 trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
01302
01303 xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS,
01304 MLOG_1BYTE, mtr);
01305
01306
01307
01308
01309 memset(&xid, 0, sizeof(xid));
01310 xid.formatID = -1;
01311
01312 if (xid_exists == TRUE) {
01313 trx_undo_read_xid(undo_header, &xid);
01314 }
01315
01316 mutex_enter(&(rseg->mutex));
01317
01318 undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
01319 page_no, offset);
01320 mutex_exit(&(rseg->mutex));
01321
01322 undo->dict_operation = mtr_read_ulint(
01323 undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr);
01324
01325 undo->table_id = mach_read_from_8(undo_header + TRX_UNDO_TABLE_ID);
01326 undo->state = state;
01327 undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
01328
01329
01330 if (state == TRX_UNDO_TO_FREE) {
01331
01332 goto add_to_list;
01333 }
01334
01335 last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
01336
01337 undo->last_page_no = last_addr.page;
01338 undo->top_page_no = last_addr.page;
01339
01340 last_page = trx_undo_page_get(rseg->space, rseg->zip_size,
01341 undo->last_page_no, mtr);
01342
01343 rec = trx_undo_page_get_last_rec(last_page, page_no, offset);
01344
01345 if (rec == NULL) {
01346 undo->empty = TRUE;
01347 } else {
01348 undo->empty = FALSE;
01349 undo->top_offset = rec - last_page;
01350 undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
01351 }
01352 add_to_list:
01353 if (type == TRX_UNDO_INSERT) {
01354 if (state != TRX_UNDO_CACHED) {
01355 UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list,
01356 undo);
01357 } else {
01358 UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_cached,
01359 undo);
01360 }
01361 } else {
01362 ut_ad(type == TRX_UNDO_UPDATE);
01363 if (state != TRX_UNDO_CACHED) {
01364 UT_LIST_ADD_LAST(undo_list, rseg->update_undo_list,
01365 undo);
01366 } else {
01367 UT_LIST_ADD_LAST(undo_list, rseg->update_undo_cached,
01368 undo);
01369 }
01370 }
01371
01372 return(undo);
01373 }
01374
01375
01380 UNIV_INTERN
01381 ulint
01382 trx_undo_lists_init(
01383
01384 trx_rseg_t* rseg)
01385 {
01386 ulint page_no;
01387 trx_undo_t* undo;
01388 ulint size = 0;
01389 trx_rsegf_t* rseg_header;
01390 ulint i;
01391 mtr_t mtr;
01392
01393 UT_LIST_INIT(rseg->update_undo_list);
01394 UT_LIST_INIT(rseg->update_undo_cached);
01395 UT_LIST_INIT(rseg->insert_undo_list);
01396 UT_LIST_INIT(rseg->insert_undo_cached);
01397
01398 mtr_start(&mtr);
01399
01400 rseg_header = trx_rsegf_get_new(rseg->space, rseg->zip_size,
01401 rseg->page_no, &mtr);
01402
01403 for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
01404 page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr);
01405
01406
01407
01408
01409
01410
01411 if (page_no != FIL_NULL
01412 && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
01413
01414 undo = trx_undo_mem_create_at_db_start(rseg, i,
01415 page_no, &mtr);
01416 size += undo->size;
01417
01418 mtr_commit(&mtr);
01419
01420 mtr_start(&mtr);
01421
01422 rseg_header = trx_rsegf_get(
01423 rseg->space, rseg->zip_size, rseg->page_no,
01424 &mtr);
01425 }
01426 }
01427
01428 mtr_commit(&mtr);
01429
01430 return(size);
01431 }
01432
01433
01436 static
01437 trx_undo_t*
01438 trx_undo_mem_create(
01439
01440 trx_rseg_t* rseg,
01441 ulint id,
01442 ulint type,
01444 trx_id_t trx_id,
01446 const XID* xid,
01447 ulint page_no,
01448 ulint offset)
01449 {
01450 trx_undo_t* undo;
01451
01452 ut_ad(mutex_own(&(rseg->mutex)));
01453
01454 if (id >= TRX_RSEG_N_SLOTS) {
01455 fprintf(stderr,
01456 "InnoDB: Error: undo->id is %lu\n", (ulong) id);
01457 ut_error;
01458 }
01459
01460 undo = static_cast<trx_undo_t *>(mem_alloc(sizeof(trx_undo_t)));
01461
01462 if (undo == NULL) {
01463
01464 return NULL;
01465 }
01466
01467 undo->id = id;
01468 undo->type = type;
01469 undo->state = TRX_UNDO_ACTIVE;
01470 undo->del_marks = FALSE;
01471 undo->trx_id = trx_id;
01472 undo->xid = *xid;
01473
01474 undo->dict_operation = FALSE;
01475
01476 undo->rseg = rseg;
01477
01478 undo->space = rseg->space;
01479 undo->zip_size = rseg->zip_size;
01480 undo->hdr_page_no = page_no;
01481 undo->hdr_offset = offset;
01482 undo->last_page_no = page_no;
01483 undo->size = 1;
01484
01485 undo->empty = TRUE;
01486 undo->top_page_no = page_no;
01487 undo->guess_block = NULL;
01488
01489 return(undo);
01490 }
01491
01492
01494 static
01495 void
01496 trx_undo_mem_init_for_reuse(
01497
01498 trx_undo_t* undo,
01499 trx_id_t trx_id,
01501 const XID* xid,
01502 ulint offset)
01503 {
01504 ut_ad(mutex_own(&((undo->rseg)->mutex)));
01505
01506 if (UNIV_UNLIKELY(undo->id >= TRX_RSEG_N_SLOTS)) {
01507 fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
01508 (ulong) undo->id);
01509
01510 mem_analyze_corruption(undo);
01511 ut_error;
01512 }
01513
01514 undo->state = TRX_UNDO_ACTIVE;
01515 undo->del_marks = FALSE;
01516 undo->trx_id = trx_id;
01517 undo->xid = *xid;
01518
01519 undo->dict_operation = FALSE;
01520
01521 undo->hdr_offset = offset;
01522 undo->empty = TRUE;
01523 }
01524
01525
01527 UNIV_INTERN
01528 void
01529 trx_undo_mem_free(
01530
01531 trx_undo_t* undo)
01532 {
01533 if (undo->id >= TRX_RSEG_N_SLOTS) {
01534 fprintf(stderr,
01535 "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id);
01536 ut_error;
01537 }
01538
01539 mem_free(undo);
01540 }
01541
01542
01547 static
01548 ulint
01549 trx_undo_create(
01550
01551 trx_t* trx,
01552 trx_rseg_t* rseg,
01553 ulint type,
01555 trx_id_t trx_id,
01557 const XID* xid,
01558 trx_undo_t** undo,
01560 mtr_t* mtr)
01561 {
01562 trx_rsegf_t* rseg_header;
01563 ulint page_no;
01564 ulint offset;
01565 ulint id;
01566 page_t* undo_page;
01567 ulint err;
01568
01569 ut_ad(mutex_own(&(rseg->mutex)));
01570
01571 if (rseg->curr_size == rseg->max_size) {
01572
01573 return(DB_OUT_OF_FILE_SPACE);
01574 }
01575
01576 rseg->curr_size++;
01577
01578 rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size, rseg->page_no,
01579 mtr);
01580
01581 err = trx_undo_seg_create(rseg, rseg_header, type, &id,
01582 &undo_page, mtr);
01583
01584 if (err != DB_SUCCESS) {
01585
01586
01587 rseg->curr_size--;
01588
01589 return(err);
01590 }
01591
01592 page_no = page_get_page_no(undo_page);
01593
01594 offset = trx_undo_header_create(undo_page, trx_id, mtr);
01595
01596 if (trx->support_xa) {
01597 trx_undo_header_add_space_for_xid(undo_page,
01598 undo_page + offset, mtr);
01599 }
01600
01601 *undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
01602 page_no, offset);
01603 if (*undo == NULL) {
01604
01605 err = DB_OUT_OF_MEMORY;
01606 }
01607
01608 return(err);
01609 }
01610
01611
01612
01613
01616 static
01617 trx_undo_t*
01618 trx_undo_reuse_cached(
01619
01620 trx_t* trx,
01621 trx_rseg_t* rseg,
01622 ulint type,
01624 trx_id_t trx_id,
01626 const XID* xid,
01627 mtr_t* mtr)
01628 {
01629 trx_undo_t* undo;
01630 page_t* undo_page;
01631 ulint offset;
01632
01633 ut_ad(mutex_own(&(rseg->mutex)));
01634
01635 if (type == TRX_UNDO_INSERT) {
01636
01637 undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
01638 if (undo == NULL) {
01639
01640 return(NULL);
01641 }
01642
01643 UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo);
01644 } else {
01645 ut_ad(type == TRX_UNDO_UPDATE);
01646
01647 undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
01648 if (undo == NULL) {
01649
01650 return(NULL);
01651 }
01652
01653 UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo);
01654 }
01655
01656 ut_ad(undo->size == 1);
01657
01658 if (undo->id >= TRX_RSEG_N_SLOTS) {
01659 fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
01660 (ulong) undo->id);
01661 mem_analyze_corruption(undo);
01662 ut_error;
01663 }
01664
01665 undo_page = trx_undo_page_get(undo->space, undo->zip_size,
01666 undo->hdr_page_no, mtr);
01667
01668 if (type == TRX_UNDO_INSERT) {
01669 offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
01670
01671 if (trx->support_xa) {
01672 trx_undo_header_add_space_for_xid(
01673 undo_page, undo_page + offset, mtr);
01674 }
01675 } else {
01676 ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
01677 + TRX_UNDO_PAGE_TYPE)
01678 == TRX_UNDO_UPDATE);
01679
01680 offset = trx_undo_header_create(undo_page, trx_id, mtr);
01681
01682 if (trx->support_xa) {
01683 trx_undo_header_add_space_for_xid(
01684 undo_page, undo_page + offset, mtr);
01685 }
01686 }
01687
01688 trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
01689
01690 return(undo);
01691 }
01692
01693
01696 static
01697 void
01698 trx_undo_mark_as_dict_operation(
01699
01700 trx_t* trx,
01701 trx_undo_t* undo,
01702 mtr_t* mtr)
01703 {
01704 page_t* hdr_page;
01705
01706 hdr_page = trx_undo_page_get(undo->space, undo->zip_size,
01707 undo->hdr_page_no, mtr);
01708
01709 switch (trx_get_dict_operation(trx)) {
01710 case TRX_DICT_OP_NONE:
01711 ut_error;
01712 case TRX_DICT_OP_INDEX:
01713
01714 undo->table_id = 0;
01715 break;
01716 case TRX_DICT_OP_TABLE:
01717 undo->table_id = trx->table_id;
01718 break;
01719 }
01720
01721 mlog_write_ulint(hdr_page + undo->hdr_offset
01722 + TRX_UNDO_DICT_TRANS,
01723 TRUE, MLOG_1BYTE, mtr);
01724
01725 mlog_write_ull(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
01726 undo->table_id, mtr);
01727
01728 undo->dict_operation = TRUE;
01729 }
01730
01731
01737 UNIV_INTERN
01738 ulint
01739 trx_undo_assign_undo(
01740
01741 trx_t* trx,
01742 ulint type)
01743 {
01744 trx_rseg_t* rseg;
01745 trx_undo_t* undo;
01746 mtr_t mtr;
01747 ulint err = DB_SUCCESS;
01748
01749 ut_ad(trx);
01750 ut_ad(trx->rseg);
01751
01752 rseg = trx->rseg;
01753
01754 ut_ad(mutex_own(&(trx->undo_mutex)));
01755
01756 mtr_start(&mtr);
01757
01758 ut_ad(!mutex_own(&kernel_mutex));
01759
01760 mutex_enter(&(rseg->mutex));
01761
01762 undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
01763 &mtr);
01764 if (undo == NULL) {
01765 err = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
01766 &undo, &mtr);
01767 if (err != DB_SUCCESS) {
01768
01769 goto func_exit;
01770 }
01771 }
01772
01773 if (type == TRX_UNDO_INSERT) {
01774 UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_list, undo);
01775 ut_ad(trx->insert_undo == NULL);
01776 trx->insert_undo = undo;
01777 } else {
01778 UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_list, undo);
01779 ut_ad(trx->update_undo == NULL);
01780 trx->update_undo = undo;
01781 }
01782
01783 if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
01784 trx_undo_mark_as_dict_operation(trx, undo, &mtr);
01785 }
01786
01787 func_exit:
01788 mutex_exit(&(rseg->mutex));
01789 mtr_commit(&mtr);
01790
01791 return err;
01792 }
01793
01794
01797 UNIV_INTERN
01798 page_t*
01799 trx_undo_set_state_at_finish(
01800
01801 trx_undo_t* undo,
01802 mtr_t* mtr)
01803 {
01804 trx_usegf_t* seg_hdr;
01805 trx_upagef_t* page_hdr;
01806 page_t* undo_page;
01807 ulint state;
01808
01809 ut_ad(undo);
01810 ut_ad(mtr);
01811
01812 if (undo->id >= TRX_RSEG_N_SLOTS) {
01813 fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
01814 (ulong) undo->id);
01815 mem_analyze_corruption(undo);
01816 ut_error;
01817 }
01818
01819 undo_page = trx_undo_page_get(undo->space, undo->zip_size,
01820 undo->hdr_page_no, mtr);
01821
01822 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
01823 page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
01824
01825 if (undo->size == 1
01826 && mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE)
01827 < TRX_UNDO_PAGE_REUSE_LIMIT) {
01828
01829 state = TRX_UNDO_CACHED;
01830
01831 } else if (undo->type == TRX_UNDO_INSERT) {
01832
01833 state = TRX_UNDO_TO_FREE;
01834 } else {
01835 state = TRX_UNDO_TO_PURGE;
01836 }
01837
01838 undo->state = state;
01839
01840 mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr);
01841
01842 return(undo_page);
01843 }
01844
01845
01848 UNIV_INTERN
01849 page_t*
01850 trx_undo_set_state_at_prepare(
01851
01852 trx_t* trx,
01853 trx_undo_t* undo,
01854 mtr_t* mtr)
01855 {
01856 trx_usegf_t* seg_hdr;
01857 trx_ulogf_t* undo_header;
01858 page_t* undo_page;
01859 ulint offset;
01860
01861 ut_ad(trx && undo && mtr);
01862
01863 if (undo->id >= TRX_RSEG_N_SLOTS) {
01864 fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
01865 (ulong) undo->id);
01866 mem_analyze_corruption(undo);
01867 ut_error;
01868 }
01869
01870 undo_page = trx_undo_page_get(undo->space, undo->zip_size,
01871 undo->hdr_page_no, mtr);
01872
01873 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
01874
01875
01876 undo->state = TRX_UNDO_PREPARED;
01877 undo->xid = trx->xid;
01878
01879
01880 mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
01881 MLOG_2BYTES, mtr);
01882
01883 offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
01884 undo_header = undo_page + offset;
01885
01886 mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS,
01887 TRUE, MLOG_1BYTE, mtr);
01888
01889 trx_undo_write_xid(undo_header, &undo->xid, mtr);
01890
01891 return(undo_page);
01892 }
01893
01894
01898 UNIV_INTERN
01899 void
01900 trx_undo_update_cleanup(
01901
01902 trx_t* trx,
01903 page_t* undo_page,
01905 mtr_t* mtr)
01906 {
01907 trx_rseg_t* rseg;
01908 trx_undo_t* undo;
01909
01910 undo = trx->update_undo;
01911 rseg = trx->rseg;
01912
01913 ut_ad(mutex_own(&(rseg->mutex)));
01914
01915 trx_purge_add_update_undo_to_history(trx, undo_page, mtr);
01916
01917 UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo);
01918
01919 trx->update_undo = NULL;
01920
01921 if (undo->state == TRX_UNDO_CACHED) {
01922
01923 UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo);
01924 } else {
01925 ut_ad(undo->state == TRX_UNDO_TO_PURGE
01926 || undo->state == TRX_UNDO_TO_FREE);
01927
01928 trx_undo_mem_free(undo);
01929 }
01930 }
01931
01932
01936 UNIV_INTERN
01937 void
01938 trx_undo_insert_cleanup(
01939
01940 trx_t* trx)
01941 {
01942 trx_undo_t* undo;
01943 trx_rseg_t* rseg;
01944
01945 undo = trx->insert_undo;
01946 ut_ad(undo);
01947
01948 rseg = trx->rseg;
01949
01950 mutex_enter(&(rseg->mutex));
01951
01952 UT_LIST_REMOVE(undo_list, rseg->insert_undo_list, undo);
01953 trx->insert_undo = NULL;
01954
01955 if (undo->state == TRX_UNDO_CACHED) {
01956
01957 UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_cached, undo);
01958 } else {
01959 ut_ad(undo->state == TRX_UNDO_TO_FREE);
01960
01961
01962
01963 mutex_exit(&(rseg->mutex));
01964
01965 trx_undo_seg_free(undo);
01966
01967 mutex_enter(&(rseg->mutex));
01968
01969 ut_ad(rseg->curr_size > undo->size);
01970
01971 rseg->curr_size -= undo->size;
01972
01973 trx_undo_mem_free(undo);
01974 }
01975
01976 mutex_exit(&(rseg->mutex));
01977 }
01978 #endif