00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "trx0rec.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "trx0rec.ic"
00030 #endif
00031
00032 #include "fsp0fsp.h"
00033 #include "mach0data.h"
00034 #include "trx0undo.h"
00035 #include "mtr0log.h"
00036 #ifndef UNIV_HOTBACKUP
00037 #include "dict0dict.h"
00038 #include "ut0mem.h"
00039 #include "row0ext.h"
00040 #include "row0upd.h"
00041 #include "que0que.h"
00042 #include "trx0purge.h"
00043 #include "trx0rseg.h"
00044 #include "row0row.h"
00045
00046
00047
00048
00051 UNIV_INLINE
00052 void
00053 trx_undof_page_add_undo_rec_log(
00054
00055 page_t* undo_page,
00056 ulint old_free,
00057 ulint new_free,
00058 mtr_t* mtr)
00059 {
00060 byte* log_ptr;
00061 const byte* log_end;
00062 ulint len;
00063
00064 log_ptr = mlog_open(mtr, 11 + 13 + MLOG_BUF_MARGIN);
00065
00066 if (log_ptr == NULL) {
00067
00068 return;
00069 }
00070
00071 log_end = &log_ptr[11 + 13 + MLOG_BUF_MARGIN];
00072 log_ptr = mlog_write_initial_log_record_fast(
00073 undo_page, MLOG_UNDO_INSERT, log_ptr, mtr);
00074 len = new_free - old_free - 4;
00075
00076 mach_write_to_2(log_ptr, len);
00077 log_ptr += 2;
00078
00079 if (log_ptr + len <= log_end) {
00080 memcpy(log_ptr, undo_page + old_free + 2, len);
00081 mlog_close(mtr, log_ptr + len);
00082 } else {
00083 mlog_close(mtr, log_ptr);
00084 mlog_catenate_string(mtr, undo_page + old_free + 2, len);
00085 }
00086 }
00087 #endif
00088
00089
00092 UNIV_INTERN
00093 byte*
00094 trx_undo_parse_add_undo_rec(
00095
00096 byte* ptr,
00097 byte* end_ptr,
00098 page_t* page)
00099 {
00100 ulint len;
00101 byte* rec;
00102 ulint first_free;
00103
00104 if (end_ptr < ptr + 2) {
00105
00106 return(NULL);
00107 }
00108
00109 len = mach_read_from_2(ptr);
00110 ptr += 2;
00111
00112 if (end_ptr < ptr + len) {
00113
00114 return(NULL);
00115 }
00116
00117 if (page == NULL) {
00118
00119 return(ptr + len);
00120 }
00121
00122 first_free = mach_read_from_2(page + TRX_UNDO_PAGE_HDR
00123 + TRX_UNDO_PAGE_FREE);
00124 rec = page + first_free;
00125
00126 mach_write_to_2(rec, first_free + 4 + len);
00127 mach_write_to_2(rec + 2 + len, first_free);
00128
00129 mach_write_to_2(page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE,
00130 first_free + 4 + len);
00131 ut_memcpy(rec + 2, ptr, len);
00132
00133 return(ptr + len);
00134 }
00135
00136 #ifndef UNIV_HOTBACKUP
00137
00140 UNIV_INLINE
00141 ulint
00142 trx_undo_left(
00143
00144 const page_t* page,
00145 const byte* ptr)
00146 {
00147
00148
00149
00150 return(UNIV_PAGE_SIZE - (ptr - page) - 10 - FIL_PAGE_DATA_END);
00151 }
00152
00153
00158 static
00159 ulint
00160 trx_undo_page_set_next_prev_and_add(
00161
00162 page_t* undo_page,
00163 byte* ptr,
00165 mtr_t* mtr)
00166 {
00167 ulint first_free;
00168 ulint end_of_rec;
00169 byte* ptr_to_first_free;
00170
00171
00172
00173
00174 ut_ad(ptr > undo_page);
00175 ut_ad(ptr < undo_page + UNIV_PAGE_SIZE);
00176
00177 if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < 2)) {
00178
00179 return(0);
00180 }
00181
00182 ptr_to_first_free = undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE;
00183
00184 first_free = mach_read_from_2(ptr_to_first_free);
00185
00186
00187 mach_write_to_2(ptr, first_free);
00188 ptr += 2;
00189
00190 end_of_rec = ptr - undo_page;
00191
00192
00193 mach_write_to_2(undo_page + first_free, end_of_rec);
00194
00195
00196 mach_write_to_2(ptr_to_first_free, end_of_rec);
00197
00198
00199 trx_undof_page_add_undo_rec_log(undo_page, first_free,
00200 end_of_rec, mtr);
00201
00202 return(first_free);
00203 }
00204
00205
00208 static
00209 ulint
00210 trx_undo_page_report_insert(
00211
00212 page_t* undo_page,
00213 trx_t* trx,
00214 dict_index_t* index,
00215 const dtuple_t* clust_entry,
00217 mtr_t* mtr)
00218 {
00219 ulint first_free;
00220 byte* ptr;
00221 ulint i;
00222
00223 ut_ad(dict_index_is_clust(index));
00224 ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
00225 + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
00226
00227 first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
00228 + TRX_UNDO_PAGE_FREE);
00229 ptr = undo_page + first_free;
00230
00231 ut_ad(first_free <= UNIV_PAGE_SIZE);
00232
00233 if (trx_undo_left(undo_page, ptr) < 2 + 1 + 11 + 11) {
00234
00235
00236
00237 return(0);
00238 }
00239
00240
00241 ptr += 2;
00242
00243
00244 *ptr++ = TRX_UNDO_INSERT_REC;
00245 ptr += mach_ull_write_much_compressed(ptr, trx->undo_no);
00246 ptr += mach_ull_write_much_compressed(ptr, index->table->id);
00247
00248
00249
00250
00251 for (i = 0; i < dict_index_get_n_unique(index); i++) {
00252
00253 const dfield_t* field = dtuple_get_nth_field(clust_entry, i);
00254 ulint flen = dfield_get_len(field);
00255
00256 if (trx_undo_left(undo_page, ptr) < 5) {
00257
00258 return(0);
00259 }
00260
00261 ptr += mach_write_compressed(ptr, flen);
00262
00263 if (flen != UNIV_SQL_NULL) {
00264 if (trx_undo_left(undo_page, ptr) < flen) {
00265
00266 return(0);
00267 }
00268
00269 ut_memcpy(ptr, dfield_get_data(field), flen);
00270 ptr += flen;
00271 }
00272 }
00273
00274 return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
00275 }
00276
00277
00280 UNIV_INTERN
00281 byte*
00282 trx_undo_rec_get_pars(
00283
00284 trx_undo_rec_t* undo_rec,
00285 ulint* type,
00287 ulint* cmpl_info,
00289 ibool* updated_extern,
00291 undo_no_t* undo_no,
00292 table_id_t* table_id)
00293 {
00294 byte* ptr;
00295 ulint type_cmpl;
00296
00297 ptr = undo_rec + 2;
00298
00299 type_cmpl = mach_read_from_1(ptr);
00300 ptr++;
00301
00302 if (type_cmpl & TRX_UNDO_UPD_EXTERN) {
00303 *updated_extern = TRUE;
00304 type_cmpl -= TRX_UNDO_UPD_EXTERN;
00305 } else {
00306 *updated_extern = FALSE;
00307 }
00308
00309 *type = type_cmpl & (TRX_UNDO_CMPL_INFO_MULT - 1);
00310 *cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
00311
00312 *undo_no = mach_ull_read_much_compressed(ptr);
00313 ptr += mach_ull_get_much_compressed_size(*undo_no);
00314
00315 *table_id = mach_ull_read_much_compressed(ptr);
00316 ptr += mach_ull_get_much_compressed_size(*table_id);
00317
00318 return(ptr);
00319 }
00320
00321
00324 static
00325 byte*
00326 trx_undo_rec_get_col_val(
00327
00328 byte* ptr,
00329 byte** field,
00330 ulint* len,
00331 ulint* orig_len)
00333 {
00334 *len = mach_read_compressed(ptr);
00335 ptr += mach_get_compressed_size(*len);
00336
00337 *orig_len = 0;
00338
00339 switch (*len) {
00340 case UNIV_SQL_NULL:
00341 *field = NULL;
00342 break;
00343 case UNIV_EXTERN_STORAGE_FIELD:
00344 *orig_len = mach_read_compressed(ptr);
00345 ptr += mach_get_compressed_size(*orig_len);
00346 *len = mach_read_compressed(ptr);
00347 ptr += mach_get_compressed_size(*len);
00348 *field = ptr;
00349 ptr += *len;
00350
00351 ut_ad(*orig_len >= BTR_EXTERN_FIELD_REF_SIZE);
00352 ut_ad(*len > *orig_len);
00353
00354 ut_ad(*len >= BTR_EXTERN_FIELD_REF_SIZE * 2);
00355
00356
00357
00358
00359
00360
00361 *len += UNIV_EXTERN_STORAGE_FIELD;
00362 break;
00363 default:
00364 *field = ptr;
00365 if (*len >= UNIV_EXTERN_STORAGE_FIELD) {
00366 ptr += *len - UNIV_EXTERN_STORAGE_FIELD;
00367 } else {
00368 ptr += *len;
00369 }
00370 }
00371
00372 return(ptr);
00373 }
00374
00375
00378 UNIV_INTERN
00379 byte*
00380 trx_undo_rec_get_row_ref(
00381
00382 byte* ptr,
00388 dict_index_t* index,
00389 dtuple_t** ref,
00390 mem_heap_t* heap)
00392 {
00393 ulint ref_len;
00394 ulint i;
00395
00396 ut_ad(index && ptr && ref && heap);
00397 ut_a(dict_index_is_clust(index));
00398
00399 ref_len = dict_index_get_n_unique(index);
00400
00401 *ref = dtuple_create(heap, ref_len);
00402
00403 dict_index_copy_types(*ref, index, ref_len);
00404
00405 for (i = 0; i < ref_len; i++) {
00406 dfield_t* dfield;
00407 byte* field;
00408 ulint len;
00409 ulint orig_len;
00410
00411 dfield = dtuple_get_nth_field(*ref, i);
00412
00413 ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
00414
00415 dfield_set_data(dfield, field, len);
00416 }
00417
00418 return(ptr);
00419 }
00420
00421
00424 UNIV_INTERN
00425 byte*
00426 trx_undo_rec_skip_row_ref(
00427
00428 byte* ptr,
00430 dict_index_t* index)
00431 {
00432 ulint ref_len;
00433 ulint i;
00434
00435 ut_ad(index && ptr);
00436 ut_a(dict_index_is_clust(index));
00437
00438 ref_len = dict_index_get_n_unique(index);
00439
00440 for (i = 0; i < ref_len; i++) {
00441 byte* field;
00442 ulint len;
00443 ulint orig_len;
00444
00445 ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
00446 }
00447
00448 return(ptr);
00449 }
00450
00451
00455 static
00456 byte*
00457 trx_undo_page_fetch_ext(
00458
00459 byte* ext_buf,
00462 ulint zip_size,
00464 const byte* field,
00465 ulint* len)
00467 {
00468
00469 ulint ext_len = btr_copy_externally_stored_field_prefix(
00470 ext_buf, REC_MAX_INDEX_COL_LEN, zip_size, field, *len);
00471
00472 ut_a(ext_len);
00473
00474 memcpy(ext_buf + ext_len,
00475 field + *len - BTR_EXTERN_FIELD_REF_SIZE,
00476 BTR_EXTERN_FIELD_REF_SIZE);
00477 *len = ext_len + BTR_EXTERN_FIELD_REF_SIZE;
00478 return(ext_buf);
00479 }
00480
00481
00484 static
00485 byte*
00486 trx_undo_page_report_modify_ext(
00487
00488 byte* ptr,
00490 byte* ext_buf,
00495 ulint zip_size,
00497 const byte** field,
00499 ulint* len)
00500 {
00501 if (ext_buf) {
00502
00503
00504
00505
00506 ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD);
00507
00508 ptr += mach_write_compressed(ptr, *len);
00509
00510 *field = trx_undo_page_fetch_ext(ext_buf, zip_size,
00511 *field, len);
00512
00513 ptr += mach_write_compressed(ptr, *len);
00514 } else {
00515 ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD
00516 + *len);
00517 }
00518
00519 return(ptr);
00520 }
00521
00522
00527 static
00528 ulint
00529 trx_undo_page_report_modify(
00530
00531 page_t* undo_page,
00532 trx_t* trx,
00533 dict_index_t* index,
00535 const rec_t* rec,
00537 const ulint* offsets,
00538 const upd_t* update,
00541 ulint cmpl_info,
00543 mtr_t* mtr)
00544 {
00545 dict_table_t* table;
00546 ulint first_free;
00547 byte* ptr;
00548 const byte* field;
00549 ulint flen;
00550 ulint col_no;
00551 ulint type_cmpl;
00552 byte* type_cmpl_ptr;
00553 ulint i;
00554 trx_id_t trx_id;
00555 ibool ignore_prefix = FALSE;
00556 byte ext_buf[REC_MAX_INDEX_COL_LEN
00557 + BTR_EXTERN_FIELD_REF_SIZE];
00558
00559 ut_a(dict_index_is_clust(index));
00560 ut_ad(rec_offs_validate(rec, index, offsets));
00561 ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
00562 + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE);
00563 table = index->table;
00564
00565 first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
00566 + TRX_UNDO_PAGE_FREE);
00567 ptr = undo_page + first_free;
00568
00569 ut_ad(first_free <= UNIV_PAGE_SIZE);
00570
00571 if (trx_undo_left(undo_page, ptr) < 50) {
00572
00573
00574
00575
00576 return(0);
00577 }
00578
00579
00580 ptr += 2;
00581
00582
00583
00584 if (!update) {
00585 type_cmpl = TRX_UNDO_DEL_MARK_REC;
00586 } else if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) {
00587 type_cmpl = TRX_UNDO_UPD_DEL_REC;
00588
00589
00590
00591
00592 ignore_prefix = TRUE;
00593 } else {
00594 type_cmpl = TRX_UNDO_UPD_EXIST_REC;
00595 }
00596
00597 type_cmpl |= cmpl_info * TRX_UNDO_CMPL_INFO_MULT;
00598 type_cmpl_ptr = ptr;
00599
00600 *ptr++ = (byte) type_cmpl;
00601 ptr += mach_ull_write_much_compressed(ptr, trx->undo_no);
00602
00603 ptr += mach_ull_write_much_compressed(ptr, table->id);
00604
00605
00606
00607
00608 *ptr++ = (byte) rec_get_info_bits(rec, dict_table_is_comp(table));
00609
00610
00611 field = rec_get_nth_field(rec, offsets,
00612 dict_index_get_sys_col_pos(
00613 index, DATA_TRX_ID), &flen);
00614 ut_ad(flen == DATA_TRX_ID_LEN);
00615
00616 trx_id = trx_read_trx_id(field);
00617
00618
00619
00620
00621
00622 if (ignore_prefix) {
00623 ignore_prefix = (trx_id != trx->id);
00624 }
00625 ptr += mach_ull_write_compressed(ptr, trx_id);
00626
00627 field = rec_get_nth_field(rec, offsets,
00628 dict_index_get_sys_col_pos(
00629 index, DATA_ROLL_PTR), &flen);
00630 ut_ad(flen == DATA_ROLL_PTR_LEN);
00631
00632 ptr += mach_ull_write_compressed(ptr, trx_read_roll_ptr(field));
00633
00634
00635
00636
00637
00638 for (i = 0; i < dict_index_get_n_unique(index); i++) {
00639
00640 field = rec_get_nth_field(rec, offsets, i, &flen);
00641
00642
00643 ut_ad(!rec_offs_nth_extern(offsets, i));
00644 ut_ad(dict_index_get_nth_col(index, i)->ord_part);
00645
00646 if (trx_undo_left(undo_page, ptr) < 5) {
00647
00648 return(0);
00649 }
00650
00651 ptr += mach_write_compressed(ptr, flen);
00652
00653 if (flen != UNIV_SQL_NULL) {
00654 if (trx_undo_left(undo_page, ptr) < flen) {
00655
00656 return(0);
00657 }
00658
00659 ut_memcpy(ptr, field, flen);
00660 ptr += flen;
00661 }
00662 }
00663
00664
00665
00666
00667 if (update) {
00668 if (trx_undo_left(undo_page, ptr) < 5) {
00669
00670 return(0);
00671 }
00672
00673 ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
00674
00675 for (i = 0; i < upd_get_n_fields(update); i++) {
00676
00677 ulint pos = upd_get_nth_field(update, i)->field_no;
00678
00679
00680 if (trx_undo_left(undo_page, ptr) < 5) {
00681
00682 return(0);
00683 }
00684
00685 ptr += mach_write_compressed(ptr, pos);
00686
00687
00688 field = rec_get_nth_field(rec, offsets, pos, &flen);
00689
00690 if (trx_undo_left(undo_page, ptr) < 15) {
00691
00692 return(0);
00693 }
00694
00695 if (rec_offs_nth_extern(offsets, pos)) {
00696 ptr = trx_undo_page_report_modify_ext(
00697 ptr,
00698 dict_index_get_nth_col(index, pos)
00699 ->ord_part
00700 && !ignore_prefix
00701 && flen < REC_MAX_INDEX_COL_LEN
00702 ? ext_buf : NULL,
00703 dict_table_zip_size(table),
00704 &field, &flen);
00705
00706
00707
00708
00709 trx->update_undo->del_marks = TRUE;
00710
00711 *type_cmpl_ptr |= TRX_UNDO_UPD_EXTERN;
00712 } else {
00713 ptr += mach_write_compressed(ptr, flen);
00714 }
00715
00716 if (flen != UNIV_SQL_NULL) {
00717 if (trx_undo_left(undo_page, ptr) < flen) {
00718
00719 return(0);
00720 }
00721
00722 ut_memcpy(ptr, field, flen);
00723 ptr += flen;
00724 }
00725 }
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 if (!update || !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
00743 byte* old_ptr = ptr;
00744
00745 trx->update_undo->del_marks = TRUE;
00746
00747 if (trx_undo_left(undo_page, ptr) < 5) {
00748
00749 return(0);
00750 }
00751
00752
00753
00754
00755 ptr += 2;
00756
00757 for (col_no = 0; col_no < dict_table_get_n_cols(table);
00758 col_no++) {
00759
00760 const dict_col_t* col
00761 = dict_table_get_nth_col(table, col_no);
00762
00763 if (col->ord_part) {
00764 ulint pos;
00765
00766
00767 if (trx_undo_left(undo_page, ptr) < 5 + 15) {
00768
00769 return(0);
00770 }
00771
00772 pos = dict_index_get_nth_col_pos(index,
00773 col_no);
00774 ptr += mach_write_compressed(ptr, pos);
00775
00776
00777 field = rec_get_nth_field(rec, offsets, pos,
00778 &flen);
00779
00780 if (rec_offs_nth_extern(offsets, pos)) {
00781 ptr = trx_undo_page_report_modify_ext(
00782 ptr,
00783 flen < REC_MAX_INDEX_COL_LEN
00784 && !ignore_prefix
00785 ? ext_buf : NULL,
00786 dict_table_zip_size(table),
00787 &field, &flen);
00788 } else {
00789 ptr += mach_write_compressed(
00790 ptr, flen);
00791 }
00792
00793 if (flen != UNIV_SQL_NULL) {
00794 if (trx_undo_left(undo_page, ptr)
00795 < flen) {
00796
00797 return(0);
00798 }
00799
00800 ut_memcpy(ptr, field, flen);
00801 ptr += flen;
00802 }
00803 }
00804 }
00805
00806 mach_write_to_2(old_ptr, ptr - old_ptr);
00807 }
00808
00809
00810
00811 if (trx_undo_left(undo_page, ptr) < 2) {
00812
00813 return(0);
00814 }
00815
00816 mach_write_to_2(ptr, first_free);
00817 ptr += 2;
00818 mach_write_to_2(undo_page + first_free, ptr - undo_page);
00819
00820 mach_write_to_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE,
00821 ptr - undo_page);
00822
00823
00824
00825 trx_undof_page_add_undo_rec_log(undo_page, first_free,
00826 ptr - undo_page, mtr);
00827 return(first_free);
00828 }
00829
00830
00834 UNIV_INTERN
00835 byte*
00836 trx_undo_update_rec_get_sys_cols(
00837
00838 byte* ptr,
00841 trx_id_t* trx_id,
00842 roll_ptr_t* roll_ptr,
00843 ulint* info_bits)
00844 {
00845
00846 *info_bits = mach_read_from_1(ptr);
00847 ptr += 1;
00848
00849
00850
00851 *trx_id = mach_ull_read_compressed(ptr);
00852 ptr += mach_ull_get_compressed_size(*trx_id);
00853
00854 *roll_ptr = mach_ull_read_compressed(ptr);
00855 ptr += mach_ull_get_compressed_size(*roll_ptr);
00856
00857 return(ptr);
00858 }
00859
00860
00863 UNIV_INLINE
00864 byte*
00865 trx_undo_update_rec_get_n_upd_fields(
00866
00867 byte* ptr,
00868 ulint* n)
00869 {
00870 *n = mach_read_compressed(ptr);
00871 ptr += mach_get_compressed_size(*n);
00872
00873 return(ptr);
00874 }
00875
00876
00879 UNIV_INLINE
00880 byte*
00881 trx_undo_update_rec_get_field_no(
00882
00883 byte* ptr,
00884 ulint* field_no)
00885 {
00886 *field_no = mach_read_compressed(ptr);
00887 ptr += mach_get_compressed_size(*field_no);
00888
00889 return(ptr);
00890 }
00891
00892
00896 UNIV_INTERN
00897 byte*
00898 trx_undo_update_rec_get_update(
00899
00900 byte* ptr,
00906 dict_index_t* index,
00907 ulint type,
00912 trx_id_t trx_id,
00913 roll_ptr_t roll_ptr,
00914 ulint info_bits,
00915 trx_t* trx,
00916 mem_heap_t* heap,
00918 upd_t** upd)
00919 {
00920 upd_field_t* upd_field;
00921 upd_t* update;
00922 ulint n_fields;
00923 byte* buf;
00924 ulint i;
00925
00926 ut_a(dict_index_is_clust(index));
00927
00928 if (type != TRX_UNDO_DEL_MARK_REC) {
00929 ptr = trx_undo_update_rec_get_n_upd_fields(ptr, &n_fields);
00930 } else {
00931 n_fields = 0;
00932 }
00933
00934 update = upd_create(n_fields + 2, heap);
00935
00936 update->info_bits = info_bits;
00937
00938
00939
00940 upd_field = upd_get_nth_field(update, n_fields);
00941 buf = static_cast<byte *>(mem_heap_alloc(heap, DATA_TRX_ID_LEN));
00942 trx_write_trx_id(buf, trx_id);
00943
00944 upd_field_set_field_no(upd_field,
00945 dict_index_get_sys_col_pos(index, DATA_TRX_ID),
00946 index, trx);
00947 dfield_set_data(&(upd_field->new_val), buf, DATA_TRX_ID_LEN);
00948
00949 upd_field = upd_get_nth_field(update, n_fields + 1);
00950 buf = static_cast<byte *>(mem_heap_alloc(heap, DATA_ROLL_PTR_LEN));
00951 trx_write_roll_ptr(buf, roll_ptr);
00952
00953 upd_field_set_field_no(
00954 upd_field, dict_index_get_sys_col_pos(index, DATA_ROLL_PTR),
00955 index, trx);
00956 dfield_set_data(&(upd_field->new_val), buf, DATA_ROLL_PTR_LEN);
00957
00958
00959
00960 for (i = 0; i < n_fields; i++) {
00961
00962 byte* field;
00963 ulint len;
00964 ulint field_no;
00965 ulint orig_len;
00966
00967 ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
00968
00969 if (field_no >= dict_index_get_n_fields(index)) {
00970 fprintf(stderr,
00971 "InnoDB: Error: trying to access"
00972 " update undo rec field %lu in ",
00973 (ulong) field_no);
00974 dict_index_name_print(stderr, trx, index);
00975 fprintf(stderr, "\n"
00976 "InnoDB: but index has only %lu fields\n"
00977 "InnoDB: Submit a detailed bug report"
00978 " to http://bugs.mysql.com\n"
00979 "InnoDB: Run also CHECK TABLE ",
00980 (ulong) dict_index_get_n_fields(index));
00981 ut_print_name(stderr, trx, TRUE, index->table_name);
00982 fprintf(stderr, "\n"
00983 "InnoDB: n_fields = %lu, i = %lu, ptr %p\n",
00984 (ulong) n_fields, (ulong) i, ptr);
00985 *upd = NULL;
00986 return(NULL);
00987 }
00988
00989 upd_field = upd_get_nth_field(update, i);
00990
00991 upd_field_set_field_no(upd_field, field_no, index, trx);
00992
00993 ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
00994
00995 upd_field->orig_len = orig_len;
00996
00997 if (len == UNIV_SQL_NULL) {
00998 dfield_set_null(&upd_field->new_val);
00999 } else if (len < UNIV_EXTERN_STORAGE_FIELD) {
01000 dfield_set_data(&upd_field->new_val, field, len);
01001 } else {
01002 len -= UNIV_EXTERN_STORAGE_FIELD;
01003
01004 dfield_set_data(&upd_field->new_val, field, len);
01005 dfield_set_ext(&upd_field->new_val);
01006 }
01007 }
01008
01009 *upd = update;
01010
01011 return(ptr);
01012 }
01013
01014
01018 UNIV_INTERN
01019 byte*
01020 trx_undo_rec_get_partial_row(
01021
01022 byte* ptr,
01029 dict_index_t* index,
01030 dtuple_t** row,
01031 ibool ignore_prefix,
01034 mem_heap_t* heap)
01036 {
01037 const byte* end_ptr;
01038 ulint row_len;
01039
01040 ut_ad(index);
01041 ut_ad(ptr);
01042 ut_ad(row);
01043 ut_ad(heap);
01044 ut_ad(dict_index_is_clust(index));
01045
01046 row_len = dict_table_get_n_cols(index->table);
01047
01048 *row = dtuple_create(heap, row_len);
01049
01050 dict_table_copy_types(*row, index->table);
01051
01052 end_ptr = ptr + mach_read_from_2(ptr);
01053 ptr += 2;
01054
01055 while (ptr != end_ptr) {
01056 dfield_t* dfield;
01057 byte* field;
01058 ulint field_no;
01059 const dict_col_t* col;
01060 ulint col_no;
01061 ulint len;
01062 ulint orig_len;
01063
01064 ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
01065
01066 col = dict_index_get_nth_col(index, field_no);
01067 col_no = dict_col_get_no(col);
01068
01069 ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
01070
01071 dfield = dtuple_get_nth_field(*row, col_no);
01072
01073 dfield_set_data(dfield, field, len);
01074
01075 if (len != UNIV_SQL_NULL
01076 && len >= UNIV_EXTERN_STORAGE_FIELD) {
01077 dfield_set_len(dfield,
01078 len - UNIV_EXTERN_STORAGE_FIELD);
01079 dfield_set_ext(dfield);
01080
01081
01082
01083 if (!ignore_prefix && col->ord_part) {
01084 ut_a(dfield_get_len(dfield)
01085 >= 2 * BTR_EXTERN_FIELD_REF_SIZE);
01086 ut_a(dict_table_get_format(index->table)
01087 >= DICT_TF_FORMAT_ZIP
01088 || dfield_get_len(dfield)
01089 >= REC_MAX_INDEX_COL_LEN
01090 + BTR_EXTERN_FIELD_REF_SIZE);
01091 }
01092 }
01093 }
01094
01095 return(ptr);
01096 }
01097 #endif
01098
01099
01101 static
01102 void
01103 trx_undo_erase_page_end(
01104
01105 page_t* undo_page,
01106 mtr_t* mtr)
01107 {
01108 ulint first_free;
01109
01110 first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
01111 + TRX_UNDO_PAGE_FREE);
01112 memset(undo_page + first_free, 0xff,
01113 (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free);
01114
01115 mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr);
01116 }
01117
01118
01121 UNIV_INTERN
01122 byte*
01123 trx_undo_parse_erase_page_end(
01124
01125 byte* ptr,
01126 byte* ,
01127 page_t* page,
01128 mtr_t* mtr)
01129 {
01130 ut_ad(ptr && end_ptr);
01131
01132 if (page == NULL) {
01133
01134 return(ptr);
01135 }
01136
01137 trx_undo_erase_page_end(page, mtr);
01138
01139 return(ptr);
01140 }
01141
01142 #ifndef UNIV_HOTBACKUP
01143
01149 UNIV_INTERN
01150 ulint
01151 trx_undo_report_row_operation(
01152
01153 ulint flags,
01155 ulint op_type,
01157 que_thr_t* thr,
01158 dict_index_t* index,
01159 const dtuple_t* clust_entry,
01162 const upd_t* update,
01164 ulint cmpl_info,
01166 const rec_t* rec,
01169 roll_ptr_t* roll_ptr)
01173 {
01174 trx_t* trx;
01175 trx_undo_t* undo;
01176 ulint page_no;
01177 trx_rseg_t* rseg;
01178 mtr_t mtr;
01179 ulint err = DB_SUCCESS;
01180 mem_heap_t* heap = NULL;
01181 ulint offsets_[REC_OFFS_NORMAL_SIZE];
01182 ulint* offsets = offsets_;
01183 rec_offs_init(offsets_);
01184
01185 ut_a(dict_index_is_clust(index));
01186
01187 if (flags & BTR_NO_UNDO_LOG_FLAG) {
01188
01189 *roll_ptr = 0;
01190
01191 return(DB_SUCCESS);
01192 }
01193
01194 ut_ad(thr);
01195 ut_ad((op_type != TRX_UNDO_INSERT_OP)
01196 || (clust_entry && !update && !rec));
01197
01198 trx = thr_get_trx(thr);
01199 rseg = trx->rseg;
01200
01201 mutex_enter(&(trx->undo_mutex));
01202
01203
01204
01205 if (op_type == TRX_UNDO_INSERT_OP) {
01206
01207 if (trx->insert_undo == NULL) {
01208
01209 err = trx_undo_assign_undo(trx, TRX_UNDO_INSERT);
01210 }
01211
01212 undo = trx->insert_undo;
01213
01214 if (UNIV_UNLIKELY(!undo)) {
01215
01216 mutex_exit(&(trx->undo_mutex));
01217
01218 return(err);
01219 }
01220 } else {
01221 ut_ad(op_type == TRX_UNDO_MODIFY_OP);
01222
01223 if (trx->update_undo == NULL) {
01224
01225 err = trx_undo_assign_undo(trx, TRX_UNDO_UPDATE);
01226
01227 }
01228
01229 undo = trx->update_undo;
01230
01231 if (UNIV_UNLIKELY(!undo)) {
01232
01233 mutex_exit(&(trx->undo_mutex));
01234 return(err);
01235 }
01236
01237 offsets = rec_get_offsets(rec, index, offsets,
01238 ULINT_UNDEFINED, &heap);
01239 }
01240
01241 page_no = undo->last_page_no;
01242
01243 mtr_start(&mtr);
01244
01245 for (;;) {
01246 buf_block_t* undo_block;
01247 page_t* undo_page;
01248 ulint offset;
01249
01250 undo_block = buf_page_get_gen(undo->space, undo->zip_size,
01251 page_no, RW_X_LATCH,
01252 undo->guess_block, BUF_GET,
01253 __FILE__, __LINE__, &mtr);
01254 buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
01255
01256 undo_page = buf_block_get_frame(undo_block);
01257
01258 if (op_type == TRX_UNDO_INSERT_OP) {
01259 offset = trx_undo_page_report_insert(
01260 undo_page, trx, index, clust_entry, &mtr);
01261 } else {
01262 offset = trx_undo_page_report_modify(
01263 undo_page, trx, index, rec, offsets, update,
01264 cmpl_info, &mtr);
01265 }
01266
01267 if (UNIV_UNLIKELY(offset == 0)) {
01268
01269
01270
01271
01272
01273
01274 trx_undo_erase_page_end(undo_page, &mtr);
01275 mtr_commit(&mtr);
01276 } else {
01277
01278
01279 mtr_commit(&mtr);
01280
01281 undo->empty = FALSE;
01282 undo->top_page_no = page_no;
01283 undo->top_offset = offset;
01284 undo->top_undo_no = trx->undo_no;
01285 undo->guess_block = undo_block;
01286
01287 trx->undo_no++;
01288
01289 mutex_exit(&trx->undo_mutex);
01290
01291 *roll_ptr = trx_undo_build_roll_ptr(
01292 op_type == TRX_UNDO_INSERT_OP,
01293 rseg->id, page_no, offset);
01294 if (UNIV_LIKELY_NULL(heap)) {
01295 mem_heap_free(heap);
01296 }
01297 return(DB_SUCCESS);
01298 }
01299
01300 ut_ad(page_no == undo->last_page_no);
01301
01302
01303
01304 mtr_start(&mtr);
01305
01306
01307
01308
01309
01310 mutex_enter(&(rseg->mutex));
01311
01312 page_no = trx_undo_add_page(trx, undo, &mtr);
01313
01314 mutex_exit(&(rseg->mutex));
01315
01316 if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
01317
01318
01319 mutex_exit(&(trx->undo_mutex));
01320 mtr_commit(&mtr);
01321 if (UNIV_LIKELY_NULL(heap)) {
01322 mem_heap_free(heap);
01323 }
01324 return(DB_OUT_OF_FILE_SPACE);
01325 }
01326 }
01327 }
01328
01329
01330
01331
01335 UNIV_INTERN
01336 trx_undo_rec_t*
01337 trx_undo_get_undo_rec_low(
01338
01339 roll_ptr_t roll_ptr,
01340 mem_heap_t* heap)
01341 {
01342 trx_undo_rec_t* undo_rec;
01343 ulint rseg_id;
01344 ulint page_no;
01345 ulint offset;
01346 const page_t* undo_page;
01347 trx_rseg_t* rseg;
01348 ibool is_insert;
01349 mtr_t mtr;
01350
01351 trx_undo_decode_roll_ptr(roll_ptr, &is_insert, &rseg_id, &page_no,
01352 &offset);
01353 rseg = trx_rseg_get_on_id(rseg_id);
01354
01355 mtr_start(&mtr);
01356
01357 undo_page = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
01358 page_no, &mtr);
01359
01360 undo_rec = trx_undo_rec_copy(undo_page + offset, heap);
01361
01362 mtr_commit(&mtr);
01363
01364 return(undo_rec);
01365 }
01366
01367
01375 UNIV_INTERN
01376 ulint
01377 trx_undo_get_undo_rec(
01378
01379 roll_ptr_t roll_ptr,
01380 trx_id_t trx_id,
01383 trx_undo_rec_t** undo_rec,
01384 mem_heap_t* heap)
01385 {
01386 #ifdef UNIV_SYNC_DEBUG
01387 ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
01388 #endif
01389
01390 if (!trx_purge_update_undo_must_exist(trx_id)) {
01391
01392
01393
01394
01395 return(DB_MISSING_HISTORY);
01396 }
01397
01398 *undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap);
01399
01400 return(DB_SUCCESS);
01401 }
01402
01403
01411 UNIV_INTERN
01412 ulint
01413 trx_undo_prev_version_build(
01414
01415 const rec_t* index_rec,
01417 mtr_t* ,
01420 const rec_t* rec,
01421 dict_index_t* index,
01422 ulint* offsets,
01423 mem_heap_t* heap,
01425 rec_t** old_vers)
01430 {
01431 trx_undo_rec_t* undo_rec = NULL;
01432 dtuple_t* entry;
01433 trx_id_t rec_trx_id;
01434 ulint type;
01435 undo_no_t undo_no;
01436 table_id_t table_id;
01437 trx_id_t trx_id;
01438 roll_ptr_t roll_ptr;
01439 roll_ptr_t old_roll_ptr;
01440 upd_t* update= NULL;
01441 byte* ptr;
01442 ulint info_bits;
01443 ulint cmpl_info;
01444 ibool dummy_extern;
01445 byte* buf;
01446 ulint err;
01447 #ifdef UNIV_SYNC_DEBUG
01448 ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
01449 #endif
01450 ut_ad(mtr_memo_contains_page(index_mtr, index_rec, MTR_MEMO_PAGE_S_FIX)
01451 || mtr_memo_contains_page(index_mtr, index_rec,
01452 MTR_MEMO_PAGE_X_FIX));
01453 ut_ad(rec_offs_validate(rec, index, offsets));
01454
01455 if (!dict_index_is_clust(index)) {
01456 fprintf(stderr, "InnoDB: Error: trying to access"
01457 " update undo rec for non-clustered index %s\n"
01458 "InnoDB: Submit a detailed bug report to"
01459 " http://bugs.mysql.com\n"
01460 "InnoDB: index record ", index->name);
01461 rec_print(stderr, index_rec, index);
01462 fputs("\n"
01463 "InnoDB: record version ", stderr);
01464 rec_print_new(stderr, rec, offsets);
01465 putc('\n', stderr);
01466 return(DB_ERROR);
01467 }
01468
01469 roll_ptr = row_get_rec_roll_ptr(rec, index, offsets);
01470 old_roll_ptr = roll_ptr;
01471
01472 *old_vers = NULL;
01473
01474 if (trx_undo_roll_ptr_is_insert(roll_ptr)) {
01475
01476
01477
01478 return(DB_SUCCESS);
01479 }
01480
01481 rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
01482
01483 err = trx_undo_get_undo_rec(roll_ptr, rec_trx_id, &undo_rec, heap);
01484
01485 if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
01486
01487
01488
01489 return(err);
01490 }
01491
01492 ptr = trx_undo_rec_get_pars(undo_rec, &type, &cmpl_info,
01493 &dummy_extern, &undo_no, &table_id);
01494
01495 ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
01496 &info_bits);
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 ptr = trx_undo_rec_skip_row_ref(ptr, index);
01521
01522 ptr = trx_undo_update_rec_get_update(ptr, index, type, trx_id,
01523 roll_ptr, info_bits,
01524 NULL, heap, &update);
01525
01526 if (UNIV_UNLIKELY(table_id != index->table->id)) {
01527 ptr = NULL;
01528
01529 fprintf(stderr,
01530 "InnoDB: Error: trying to access update undo rec"
01531 " for table %s\n"
01532 "InnoDB: but the table id in the"
01533 " undo record is wrong\n"
01534 "InnoDB: Submit a detailed bug report"
01535 " to http://bugs.mysql.com\n"
01536 "InnoDB: Run also CHECK TABLE %s\n",
01537 index->table_name, index->table_name);
01538 }
01539
01540 if (ptr == NULL) {
01541
01542
01543
01544 fprintf(stderr,
01545 "InnoDB: table %s, index %s, n_uniq %lu\n"
01546 "InnoDB: undo rec address %p, type %lu cmpl_info %lu\n"
01547 "InnoDB: undo rec table id %llu,"
01548 " index table id %llu\n"
01549 "InnoDB: dump of 150 bytes in undo rec: ",
01550 index->table_name, index->name,
01551 (ulong) dict_index_get_n_unique(index),
01552 undo_rec, (ulong) type, (ulong) cmpl_info,
01553 (ullint) table_id,
01554 (ullint) index->table->id);
01555 ut_print_buf(stderr, undo_rec, 150);
01556 fputs("\n"
01557 "InnoDB: index record ", stderr);
01558 rec_print(stderr, index_rec, index);
01559 fputs("\n"
01560 "InnoDB: record version ", stderr);
01561 rec_print_new(stderr, rec, offsets);
01562 fprintf(stderr, "\n"
01563 "InnoDB: Record trx id " TRX_ID_FMT
01564 ", update rec trx id " TRX_ID_FMT "\n"
01565 "InnoDB: Roll ptr in rec " TRX_ID_FMT
01566 ", in update rec" TRX_ID_FMT "\n",
01567 rec_trx_id, trx_id,
01568 old_roll_ptr, roll_ptr);
01569
01570 trx_purge_sys_print();
01571 return(DB_ERROR);
01572 }
01573
01574 if (row_upd_changes_field_size_or_external(index, offsets, update)) {
01575 ulint n_ext;
01576
01577
01578
01579
01580
01581
01582
01583 entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index,
01584 offsets, &n_ext, heap);
01585 n_ext += btr_push_update_extern_fields(entry, update, heap);
01586
01587
01588
01589 row_upd_index_replace_new_col_vals(entry, index, update, heap);
01590
01591 buf = static_cast<byte *>(mem_heap_alloc(heap, rec_get_converted_size(index, entry,
01592 n_ext)));
01593
01594 *old_vers = rec_convert_dtuple_to_rec(buf, index,
01595 entry, n_ext);
01596 } else {
01597 buf = static_cast<byte *>(mem_heap_alloc(heap, rec_offs_size(offsets)));
01598 *old_vers = rec_copy(buf, rec, offsets);
01599 rec_offs_make_valid(*old_vers, index, offsets);
01600 row_upd_rec_in_place(*old_vers, index, offsets, update, NULL);
01601 }
01602
01603 return(DB_SUCCESS);
01604 }
01605 #endif