00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "row0vers.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "row0vers.ic"
00030 #endif
00031
00032 #include "dict0dict.h"
00033 #include "dict0boot.h"
00034 #include "btr0btr.h"
00035 #include "mach0data.h"
00036 #include "trx0rseg.h"
00037 #include "trx0trx.h"
00038 #include "trx0roll.h"
00039 #include "trx0undo.h"
00040 #include "trx0purge.h"
00041 #include "trx0rec.h"
00042 #include "que0que.h"
00043 #include "row0row.h"
00044 #include "row0upd.h"
00045 #include "rem0cmp.h"
00046 #include "read0read.h"
00047 #include "lock0lock.h"
00048
00049
00054 UNIV_INTERN
00055 trx_t*
00056 row_vers_impl_x_locked_off_kernel(
00057
00058 const rec_t* rec,
00059 dict_index_t* index,
00060 const ulint* offsets)
00061 {
00062 dict_index_t* clust_index;
00063 rec_t* clust_rec;
00064 ulint* clust_offsets;
00065 rec_t* version;
00066 trx_id_t trx_id;
00067 mem_heap_t* heap;
00068 mem_heap_t* heap2;
00069 dtuple_t* row;
00070 dtuple_t* entry = NULL;
00071
00072 trx_t* trx;
00073 ulint rec_del;
00074 #ifdef UNIV_DEBUG
00075 ulint err;
00076 #endif
00077 mtr_t mtr;
00078 ulint comp;
00079
00080 ut_ad(mutex_own(&kernel_mutex));
00081 #ifdef UNIV_SYNC_DEBUG
00082 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
00083 #endif
00084
00085 mutex_exit(&kernel_mutex);
00086
00087 mtr_start(&mtr);
00088
00089
00090
00091
00092
00093
00094
00095 clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index,
00096 &clust_index, &mtr);
00097 if (!clust_rec) {
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 mutex_enter(&kernel_mutex);
00111 mtr_commit(&mtr);
00112
00113 return(NULL);
00114 }
00115
00116 heap = mem_heap_create(1024);
00117 clust_offsets = rec_get_offsets(clust_rec, clust_index, NULL,
00118 ULINT_UNDEFINED, &heap);
00119 trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets);
00120
00121 mtr_s_lock(&(purge_sys->latch), &mtr);
00122
00123 mutex_enter(&kernel_mutex);
00124
00125 trx = NULL;
00126 if (!trx_is_active(trx_id)) {
00127
00128
00129 goto exit_func;
00130 }
00131
00132 if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index,
00133 clust_offsets, TRUE)) {
00134
00135 goto exit_func;
00136 }
00137
00138 comp = page_rec_is_comp(rec);
00139 ut_ad(index->table == clust_index->table);
00140 ut_ad(!!comp == dict_table_is_comp(index->table));
00141 ut_ad(!comp == !page_rec_is_comp(clust_rec));
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 rec_del = rec_get_deleted_flag(rec, comp);
00153 trx = NULL;
00154
00155 version = clust_rec;
00156
00157 for (;;) {
00158 rec_t* prev_version;
00159 ulint vers_del;
00160 row_ext_t* ext;
00161 trx_id_t prev_trx_id;
00162
00163 mutex_exit(&kernel_mutex);
00164
00165
00166
00167
00168
00169
00170
00171
00172 heap2 = heap;
00173 heap = mem_heap_create(1024);
00174 #ifdef UNIV_DEBUG
00175 err =
00176 #endif
00177 trx_undo_prev_version_build(clust_rec, &mtr, version,
00178 clust_index, clust_offsets,
00179 heap, &prev_version);
00180 mem_heap_free(heap2);
00181
00182 if (prev_version == NULL) {
00183 mutex_enter(&kernel_mutex);
00184
00185 if (!trx_is_active(trx_id)) {
00186
00187
00188
00189 break;
00190 }
00191
00192
00193
00194
00195 ut_ad(err == DB_SUCCESS);
00196
00197
00198
00199
00200 trx = trx_get_on_id(trx_id);
00201
00202 break;
00203 }
00204
00205 clust_offsets = rec_get_offsets(prev_version, clust_index,
00206 NULL, ULINT_UNDEFINED, &heap);
00207
00208 vers_del = rec_get_deleted_flag(prev_version, comp);
00209 prev_trx_id = row_get_rec_trx_id(prev_version, clust_index,
00210 clust_offsets);
00211
00212
00213
00214
00215
00216
00217 if (vers_del && trx_id != prev_trx_id) {
00218
00219 mutex_enter(&kernel_mutex);
00220 break;
00221 }
00222
00223
00224
00225
00226 row = row_build(ROW_COPY_POINTERS, clust_index, prev_version,
00227 clust_offsets, NULL, &ext, heap);
00228 entry = row_build_index_entry(row, ext, index, heap);
00229
00230
00231
00232
00233 ut_a(entry);
00234
00235 mutex_enter(&kernel_mutex);
00236
00237 if (!trx_is_active(trx_id)) {
00238
00239
00240 break;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 ut_ad(err == DB_SUCCESS);
00252
00253
00254
00255 if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
00256
00257
00258
00259
00260 if (rec_del != vers_del) {
00261 trx = trx_get_on_id(trx_id);
00262
00263 break;
00264 }
00265
00266
00267
00268
00269
00270
00271 dtuple_set_types_binary(entry,
00272 dtuple_get_n_fields(entry));
00273 if (0 != cmp_dtuple_rec(entry, rec, offsets)) {
00274
00275 trx = trx_get_on_id(trx_id);
00276
00277 break;
00278 }
00279 } else if (!rec_del) {
00280
00281
00282
00283 trx = trx_get_on_id(trx_id);
00284
00285 break;
00286 }
00287
00288 if (trx_id != prev_trx_id) {
00289
00290
00291
00292 break;
00293 }
00294
00295 version = prev_version;
00296 }
00297
00298 exit_func:
00299 mtr_commit(&mtr);
00300 mem_heap_free(heap);
00301
00302 return(trx);
00303 }
00304
00305
00309 UNIV_INTERN
00310 ibool
00311 row_vers_must_preserve_del_marked(
00312
00313 trx_id_t trx_id,
00314 mtr_t* mtr)
00317 {
00318 #ifdef UNIV_SYNC_DEBUG
00319 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
00320 #endif
00321
00322 mtr_s_lock(&(purge_sys->latch), mtr);
00323
00324 if (trx_purge_update_undo_must_exist(trx_id)) {
00325
00326
00327
00328
00329 return(TRUE);
00330 }
00331
00332 return(FALSE);
00333 }
00334
00335
00342 UNIV_INTERN
00343 ibool
00344 row_vers_old_has_index_entry(
00345
00346 ibool also_curr,
00349 const rec_t* rec,
00351 mtr_t* mtr,
00353 dict_index_t* index,
00354 const dtuple_t* ientry)
00355 {
00356 const rec_t* version;
00357 rec_t* prev_version;
00358 dict_index_t* clust_index;
00359 ulint* clust_offsets;
00360 mem_heap_t* heap;
00361 mem_heap_t* heap2;
00362 const dtuple_t* row;
00363 const dtuple_t* entry;
00364 ulint err;
00365 ulint comp;
00366
00367 ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
00368 || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
00369 #ifdef UNIV_SYNC_DEBUG
00370 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
00371 #endif
00372 mtr_s_lock(&(purge_sys->latch), mtr);
00373
00374 clust_index = dict_table_get_first_index(index->table);
00375
00376 comp = page_rec_is_comp(rec);
00377 ut_ad(!dict_table_is_comp(index->table) == !comp);
00378 heap = mem_heap_create(1024);
00379 clust_offsets = rec_get_offsets(rec, clust_index, NULL,
00380 ULINT_UNDEFINED, &heap);
00381
00382 if (also_curr && !rec_get_deleted_flag(rec, comp)) {
00383 row_ext_t* ext;
00384
00385
00386
00387
00388 row = row_build(ROW_COPY_POINTERS, clust_index,
00389 rec, clust_offsets, NULL, &ext, heap);
00390 entry = row_build_index_entry(row, ext, index, heap);
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 if (entry && !dtuple_coll_cmp(ientry, entry)) {
00414
00415 mem_heap_free(heap);
00416
00417 return(TRUE);
00418 }
00419 }
00420
00421 version = rec;
00422
00423 for (;;) {
00424 heap2 = heap;
00425 heap = mem_heap_create(1024);
00426 err = trx_undo_prev_version_build(rec, mtr, version,
00427 clust_index, clust_offsets,
00428 heap, &prev_version);
00429 mem_heap_free(heap2);
00430
00431 if (err != DB_SUCCESS || !prev_version) {
00432
00433
00434 mem_heap_free(heap);
00435
00436 return(FALSE);
00437 }
00438
00439 clust_offsets = rec_get_offsets(prev_version, clust_index,
00440 NULL, ULINT_UNDEFINED, &heap);
00441
00442 if (!rec_get_deleted_flag(prev_version, comp)) {
00443 row_ext_t* ext;
00444
00445
00446
00447
00448 row = row_build(ROW_COPY_POINTERS, clust_index,
00449 prev_version, clust_offsets,
00450 NULL, &ext, heap);
00451 entry = row_build_index_entry(row, ext, index, heap);
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 if (entry && !dtuple_coll_cmp(ientry, entry)) {
00466
00467 mem_heap_free(heap);
00468
00469 return(TRUE);
00470 }
00471 }
00472
00473 version = prev_version;
00474 }
00475 }
00476
00477
00482 UNIV_INTERN
00483 ulint
00484 row_vers_build_for_consistent_read(
00485
00486 const rec_t* rec,
00490 mtr_t* mtr,
00491 dict_index_t* index,
00492 ulint** offsets,
00494 read_view_t* view,
00495 mem_heap_t** offset_heap,
00497 mem_heap_t* in_heap,
00501 rec_t** old_vers)
00504 {
00505 const rec_t* version;
00506 rec_t* prev_version;
00507 trx_id_t trx_id;
00508 mem_heap_t* heap = NULL;
00509 byte* buf;
00510 ulint err;
00511
00512 ut_ad(dict_index_is_clust(index));
00513 ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
00514 || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
00515 #ifdef UNIV_SYNC_DEBUG
00516 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
00517 #endif
00518
00519 ut_ad(rec_offs_validate(rec, index, *offsets));
00520
00521 trx_id = row_get_rec_trx_id(rec, index, *offsets);
00522
00523 ut_ad(!read_view_sees_trx_id(view, trx_id));
00524
00525 rw_lock_s_lock(&(purge_sys->latch));
00526 version = rec;
00527
00528 for (;;) {
00529 mem_heap_t* heap2 = heap;
00530 trx_undo_rec_t* undo_rec;
00531 roll_ptr_t roll_ptr;
00532 undo_no_t undo_no;
00533 heap = mem_heap_create(1024);
00534
00535
00536
00537
00538
00539
00540 if (view->type == VIEW_HIGH_GRANULARITY
00541 && view->creator_trx_id == trx_id) {
00542
00543 roll_ptr = row_get_rec_roll_ptr(version, index,
00544 *offsets);
00545 undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap);
00546 undo_no = trx_undo_rec_get_undo_no(undo_rec);
00547 mem_heap_empty(heap);
00548
00549 if (view->undo_no > undo_no) {
00550
00551
00552
00553 buf = static_cast<byte *>(mem_heap_alloc(in_heap,
00554 rec_offs_size(*offsets)));
00555 *old_vers = rec_copy(buf, version, *offsets);
00556 rec_offs_make_valid(*old_vers, index,
00557 *offsets);
00558 err = DB_SUCCESS;
00559
00560 break;
00561 }
00562 }
00563
00564 err = trx_undo_prev_version_build(rec, mtr, version, index,
00565 *offsets, heap,
00566 &prev_version);
00567 if (heap2) {
00568 mem_heap_free(heap2);
00569 }
00570
00571 if (err != DB_SUCCESS) {
00572 break;
00573 }
00574
00575 if (prev_version == NULL) {
00576
00577 *old_vers = NULL;
00578 err = DB_SUCCESS;
00579
00580 break;
00581 }
00582
00583 *offsets = rec_get_offsets(prev_version, index, *offsets,
00584 ULINT_UNDEFINED, offset_heap);
00585
00586 trx_id = row_get_rec_trx_id(prev_version, index, *offsets);
00587
00588 if (read_view_sees_trx_id(view, trx_id)) {
00589
00590
00591
00592
00593 buf = static_cast<byte *>(mem_heap_alloc(in_heap, rec_offs_size(*offsets)));
00594 *old_vers = rec_copy(buf, prev_version, *offsets);
00595 rec_offs_make_valid(*old_vers, index, *offsets);
00596 err = DB_SUCCESS;
00597
00598 break;
00599 }
00600
00601 version = prev_version;
00602 }
00603
00604 mem_heap_free(heap);
00605 rw_lock_s_unlock(&(purge_sys->latch));
00606
00607 return(err);
00608 }
00609
00610
00614 UNIV_INTERN
00615 ulint
00616 row_vers_build_for_semi_consistent_read(
00617
00618 const rec_t* rec,
00622 mtr_t* mtr,
00623 dict_index_t* index,
00624 ulint** offsets,
00626 mem_heap_t** offset_heap,
00628 mem_heap_t* in_heap,
00632 const rec_t** old_vers)
00635 {
00636 const rec_t* version;
00637 mem_heap_t* heap = NULL;
00638 byte* buf;
00639 ulint err;
00640 trx_id_t rec_trx_id = 0;
00641
00642 ut_ad(dict_index_is_clust(index));
00643 ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
00644 || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
00645 #ifdef UNIV_SYNC_DEBUG
00646 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
00647 #endif
00648
00649 ut_ad(rec_offs_validate(rec, index, *offsets));
00650
00651 rw_lock_s_lock(&(purge_sys->latch));
00652
00653
00654
00655
00656
00657 version = rec;
00658
00659 for (;;) {
00660 trx_t* version_trx;
00661 mem_heap_t* heap2;
00662 rec_t* prev_version;
00663 trx_id_t version_trx_id;
00664
00665 version_trx_id = row_get_rec_trx_id(version, index, *offsets);
00666 if (rec == version) {
00667 rec_trx_id = version_trx_id;
00668 }
00669
00670 mutex_enter(&kernel_mutex);
00671 version_trx = trx_get_on_id(version_trx_id);
00672 mutex_exit(&kernel_mutex);
00673
00674 if (!version_trx
00675 || version_trx->conc_state == TRX_NOT_STARTED
00676 || version_trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
00677
00678
00679
00680
00681 if (rec == version) {
00682 *old_vers = rec;
00683 err = DB_SUCCESS;
00684 break;
00685 }
00686
00687
00688
00689
00690
00691
00692 if (rec_trx_id == version_trx_id) {
00693
00694
00695
00696
00697
00698 version = rec;
00699 *offsets = rec_get_offsets(version,
00700 index, *offsets,
00701 ULINT_UNDEFINED,
00702 offset_heap);
00703 }
00704
00705 buf = static_cast<byte *>(mem_heap_alloc(in_heap, rec_offs_size(*offsets)));
00706 *old_vers = rec_copy(buf, version, *offsets);
00707 rec_offs_make_valid(*old_vers, index, *offsets);
00708 err = DB_SUCCESS;
00709
00710 break;
00711 }
00712
00713 heap2 = heap;
00714 heap = mem_heap_create(1024);
00715
00716 err = trx_undo_prev_version_build(rec, mtr, version, index,
00717 *offsets, heap,
00718 &prev_version);
00719 if (heap2) {
00720 mem_heap_free(heap2);
00721 }
00722
00723 if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
00724 break;
00725 }
00726
00727 if (prev_version == NULL) {
00728
00729 *old_vers = NULL;
00730 err = DB_SUCCESS;
00731
00732 break;
00733 }
00734
00735 version = prev_version;
00736 *offsets = rec_get_offsets(version, index, *offsets,
00737 ULINT_UNDEFINED, offset_heap);
00738 }
00739
00740 if (heap) {
00741 mem_heap_free(heap);
00742 }
00743 rw_lock_s_unlock(&(purge_sys->latch));
00744
00745 return(err);
00746 }