#include "row0vers.h"#include "dict0dict.h"#include "dict0boot.h"#include "btr0btr.h"#include "mach0data.h"#include "trx0rseg.h"#include "trx0trx.h"#include "trx0roll.h"#include "trx0undo.h"#include "trx0purge.h"#include "trx0rec.h"#include "que0que.h"#include "row0row.h"#include "row0upd.h"#include "rem0cmp.h"#include "read0read.h"#include "lock0lock.h"Include dependency graph for row0vers.c:

Go to the source code of this file.
Functions | |
| trx_t * | row_vers_impl_x_locked_off_kernel (rec_t *rec, dict_index_t *index, const ulint *offsets) |
| ibool | row_vers_must_preserve_del_marked (dulint trx_id, mtr_t *mtr) |
| ibool | row_vers_old_has_index_entry (ibool also_curr, rec_t *rec, mtr_t *mtr, dict_index_t *index, dtuple_t *ientry) |
| ulint | row_vers_build_for_consistent_read (rec_t *rec, mtr_t *mtr, dict_index_t *index, ulint **offsets, read_view_t *view, mem_heap_t **offset_heap, mem_heap_t *in_heap, rec_t **old_vers) |
| ulint | row_vers_build_for_semi_consistent_read (rec_t *rec, mtr_t *mtr, dict_index_t *index, ulint **offsets, mem_heap_t **offset_heap, mem_heap_t *in_heap, rec_t **old_vers) |
| ulint row_vers_build_for_consistent_read | ( | rec_t * | rec, | |
| mtr_t * | mtr, | |||
| dict_index_t * | index, | |||
| ulint ** | offsets, | |||
| read_view_t * | view, | |||
| mem_heap_t ** | offset_heap, | |||
| mem_heap_t * | in_heap, | |||
| rec_t ** | old_vers | |||
| ) |
Definition at line 400 of file row0vers.c.
References buf, buf_block_align(), read_view_struct::creator_trx_id, DB_SUCCESS, DICT_CLUSTERED, err, index(), trx_purge_struct::latch, mem_heap_alloc(), mem_heap_create, mem_heap_empty(), mem_heap_free, mtr_memo_contains(), MTR_MEMO_PAGE_S_FIX, MTR_MEMO_PAGE_X_FIX, NULL, purge_sys, read_view_sees_trx_id(), rec_copy(), rec_get_offsets, rec_offs_make_valid(), rec_offs_size(), rec_offs_validate(), row_get_rec_roll_ptr(), row_get_rec_trx_id(), rw_lock_s_lock, rw_lock_s_unlock, RW_LOCK_SHARED, trx_undo_get_undo_rec_low(), trx_undo_prev_version_build(), trx_undo_rec_get_undo_no(), read_view_struct::type, read_view_struct::undo_no, ut_ad, ut_dulint_cmp(), version(), and VIEW_HIGH_GRANULARITY.
Referenced by row_sel_build_prev_vers(), and row_sel_build_prev_vers_for_mysql().
00402 : DB_SUCCESS or DB_MISSING_HISTORY */ 00403 rec_t* rec, /* in: record in a clustered index; the 00404 caller must have a latch on the page; this 00405 latch locks the top of the stack of versions 00406 of this records */ 00407 mtr_t* mtr, /* in: mtr holding the latch on rec */ 00408 dict_index_t* index, /* in: the clustered index */ 00409 ulint** offsets,/* in/out: offsets returned by 00410 rec_get_offsets(rec, index) */ 00411 read_view_t* view, /* in: the consistent read view */ 00412 mem_heap_t** offset_heap,/* in/out: memory heap from which 00413 the offsets are allocated */ 00414 mem_heap_t* in_heap,/* in: memory heap from which the memory for 00415 old_vers is allocated; memory for possible 00416 intermediate versions is allocated and freed 00417 locally within the function */ 00418 rec_t** old_vers)/* out, own: old version, or NULL if the 00419 record does not exist in the view, that is, 00420 it was freshly inserted afterwards */ 00421 { 00422 rec_t* version; 00423 rec_t* prev_version; 00424 dulint trx_id; 00425 mem_heap_t* heap = NULL; 00426 byte* buf; 00427 ulint err; 00428 00429 ut_ad(index->type & DICT_CLUSTERED); 00430 ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX) 00431 || mtr_memo_contains(mtr, buf_block_align(rec), 00432 MTR_MEMO_PAGE_S_FIX)); 00433 #ifdef UNIV_SYNC_DEBUG 00434 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); 00435 #endif /* UNIV_SYNC_DEBUG */ 00436 00437 ut_ad(rec_offs_validate(rec, index, *offsets)); 00438 00439 trx_id = row_get_rec_trx_id(rec, index, *offsets); 00440 00441 ut_ad(!read_view_sees_trx_id(view, trx_id)); 00442 00443 rw_lock_s_lock(&(purge_sys->latch)); 00444 version = rec; 00445 00446 for (;;) { 00447 mem_heap_t* heap2 = heap; 00448 trx_undo_rec_t* undo_rec; 00449 dulint roll_ptr; 00450 dulint undo_no; 00451 heap = mem_heap_create(1024); 00452 00453 /* If we have high-granularity consistent read view and 00454 creating transaction of the view is the same as trx_id in 00455 the record we see this record only in the case when 00456 undo_no of the record is < undo_no in the view. */ 00457 00458 if (view->type == VIEW_HIGH_GRANULARITY 00459 && ut_dulint_cmp(view->creator_trx_id, trx_id) == 0) { 00460 00461 roll_ptr = row_get_rec_roll_ptr(version, index, 00462 *offsets); 00463 undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap); 00464 undo_no = trx_undo_rec_get_undo_no(undo_rec); 00465 mem_heap_empty(heap); 00466 00467 if (ut_dulint_cmp(view->undo_no, undo_no) > 0) { 00468 /* The view already sees this version: we can 00469 copy it to in_heap and return */ 00470 00471 buf = mem_heap_alloc(in_heap, 00472 rec_offs_size(*offsets)); 00473 *old_vers = rec_copy(buf, version, *offsets); 00474 rec_offs_make_valid(*old_vers, index, *offsets); 00475 err = DB_SUCCESS; 00476 00477 break; 00478 } 00479 } 00480 00481 err = trx_undo_prev_version_build(rec, mtr, version, index, 00482 *offsets, heap, &prev_version); 00483 if (heap2) { 00484 mem_heap_free(heap2); /* free version */ 00485 } 00486 00487 if (err != DB_SUCCESS) { 00488 break; 00489 } 00490 00491 if (prev_version == NULL) { 00492 /* It was a freshly inserted version */ 00493 *old_vers = NULL; 00494 err = DB_SUCCESS; 00495 00496 break; 00497 } 00498 00499 *offsets = rec_get_offsets(prev_version, index, *offsets, 00500 ULINT_UNDEFINED, offset_heap); 00501 00502 trx_id = row_get_rec_trx_id(prev_version, index, *offsets); 00503 00504 if (read_view_sees_trx_id(view, trx_id)) { 00505 00506 /* The view already sees this version: we can copy 00507 it to in_heap and return */ 00508 00509 buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets)); 00510 *old_vers = rec_copy(buf, prev_version, *offsets); 00511 rec_offs_make_valid(*old_vers, index, *offsets); 00512 err = DB_SUCCESS; 00513 00514 break; 00515 } 00516 00517 version = prev_version; 00518 }/* for (;;) */ 00519 00520 mem_heap_free(heap); 00521 rw_lock_s_unlock(&(purge_sys->latch)); 00522 00523 return(err); 00524 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ulint row_vers_build_for_semi_consistent_read | ( | rec_t * | rec, | |
| mtr_t * | mtr, | |||
| dict_index_t * | index, | |||
| ulint ** | offsets, | |||
| mem_heap_t ** | offset_heap, | |||
| mem_heap_t * | in_heap, | |||
| rec_t ** | old_vers | |||
| ) |
Definition at line 531 of file row0vers.c.
References buf, buf_block_align(), DB_SUCCESS, DICT_CLUSTERED, err, index(), kernel_mutex, trx_purge_struct::latch, mem_heap_alloc(), mem_heap_create, mem_heap_free, mtr_memo_contains(), MTR_MEMO_PAGE_S_FIX, MTR_MEMO_PAGE_X_FIX, mutex_enter, mutex_exit(), NULL, purge_sys, rec_copy(), rec_get_offsets, rec_offs_make_valid(), rec_offs_size(), rec_offs_validate(), row_get_rec_trx_id(), rw_lock_s_lock, rw_lock_s_unlock, RW_LOCK_SHARED, TRX_COMMITTED_IN_MEMORY, trx_get_on_id(), TRX_NOT_STARTED, trx_undo_prev_version_build(), ut_ad, ut_dulint_cmp(), and version().
Referenced by row_sel_build_committed_vers_for_mysql().
00533 : DB_SUCCESS or DB_MISSING_HISTORY */ 00534 rec_t* rec, /* in: record in a clustered index; the 00535 caller must have a latch on the page; this 00536 latch locks the top of the stack of versions 00537 of this records */ 00538 mtr_t* mtr, /* in: mtr holding the latch on rec */ 00539 dict_index_t* index, /* in: the clustered index */ 00540 ulint** offsets,/* in/out: offsets returned by 00541 rec_get_offsets(rec, index) */ 00542 mem_heap_t** offset_heap,/* in/out: memory heap from which 00543 the offsets are allocated */ 00544 mem_heap_t* in_heap,/* in: memory heap from which the memory for 00545 old_vers is allocated; memory for possible 00546 intermediate versions is allocated and freed 00547 locally within the function */ 00548 rec_t** old_vers)/* out, own: rec, old version, or NULL if the 00549 record does not exist in the view, that is, 00550 it was freshly inserted afterwards */ 00551 { 00552 rec_t* version; 00553 mem_heap_t* heap = NULL; 00554 byte* buf; 00555 ulint err; 00556 dulint rec_trx_id; 00557 00558 ut_ad(index->type & DICT_CLUSTERED); 00559 ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX) 00560 || mtr_memo_contains(mtr, buf_block_align(rec), 00561 MTR_MEMO_PAGE_S_FIX)); 00562 #ifdef UNIV_SYNC_DEBUG 00563 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); 00564 #endif /* UNIV_SYNC_DEBUG */ 00565 00566 ut_ad(rec_offs_validate(rec, index, *offsets)); 00567 00568 rw_lock_s_lock(&(purge_sys->latch)); 00569 /* The S-latch on purge_sys prevents the purge view from 00570 changing. Thus, if we have an uncommitted transaction at 00571 this point, then purge cannot remove its undo log even if 00572 the transaction could commit now. */ 00573 00574 version = rec; 00575 00576 for (;;) { 00577 trx_t* version_trx; 00578 mem_heap_t* heap2; 00579 rec_t* prev_version; 00580 dulint version_trx_id; 00581 00582 version_trx_id = row_get_rec_trx_id( 00583 version, index, *offsets); 00584 if (rec == version) { 00585 rec_trx_id = version_trx_id; 00586 } 00587 00588 mutex_enter(&kernel_mutex); 00589 version_trx = trx_get_on_id(version_trx_id); 00590 mutex_exit(&kernel_mutex); 00591 00592 if (!version_trx 00593 || version_trx->conc_state == TRX_NOT_STARTED 00594 || version_trx->conc_state == TRX_COMMITTED_IN_MEMORY) { 00595 00596 /* We found a version that belongs to a 00597 committed transaction: return it. */ 00598 00599 if (rec == version) { 00600 *old_vers = rec; 00601 err = DB_SUCCESS; 00602 break; 00603 } 00604 00605 /* We assume that a rolled-back transaction stays in 00606 TRX_ACTIVE state until all the changes have been 00607 rolled back and the transaction is removed from 00608 the global list of transactions. */ 00609 00610 if (!ut_dulint_cmp(rec_trx_id, version_trx_id)) { 00611 /* The transaction was committed while 00612 we searched for earlier versions. 00613 Return the current version as a 00614 semi-consistent read. */ 00615 00616 version = rec; 00617 *offsets = rec_get_offsets(version, 00618 index, *offsets, 00619 ULINT_UNDEFINED, offset_heap); 00620 } 00621 00622 buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets)); 00623 *old_vers = rec_copy(buf, version, *offsets); 00624 rec_offs_make_valid(*old_vers, index, *offsets); 00625 err = DB_SUCCESS; 00626 00627 break; 00628 } 00629 00630 heap2 = heap; 00631 heap = mem_heap_create(1024); 00632 00633 err = trx_undo_prev_version_build(rec, mtr, version, index, 00634 *offsets, heap, &prev_version); 00635 if (heap2) { 00636 mem_heap_free(heap2); /* free version */ 00637 } 00638 00639 if (UNIV_UNLIKELY(err != DB_SUCCESS)) { 00640 break; 00641 } 00642 00643 if (prev_version == NULL) { 00644 /* It was a freshly inserted version */ 00645 *old_vers = NULL; 00646 err = DB_SUCCESS; 00647 00648 break; 00649 } 00650 00651 version = prev_version; 00652 *offsets = rec_get_offsets(version, index, *offsets, 00653 ULINT_UNDEFINED, offset_heap); 00654 }/* for (;;) */ 00655 00656 if (heap) { 00657 mem_heap_free(heap); 00658 } 00659 rw_lock_s_unlock(&(purge_sys->latch)); 00660 00661 return(err); 00662 }
Here is the call graph for this function:

Here is the caller graph for this function:

| trx_t* row_vers_impl_x_locked_off_kernel | ( | rec_t * | rec, | |
| dict_index_t * | index, | |||
| const ulint * | offsets | |||
| ) |
Definition at line 38 of file row0vers.c.
References BTR_SEARCH_LEAF, cmp_dtuple_rec(), DB_SUCCESS, dict_table_is_comp(), dtuple_get_n_fields(), dtuple_set_types_binary(), err, index(), kernel_mutex, trx_purge_struct::latch, lock_check_trx_id_sanity(), mem_heap_create, mem_heap_free, mtr_commit(), mtr_s_lock, mtr_start(), mutex_enter, mutex_exit(), NULL, page_rec_is_comp(), purge_sys, rec_get_deleted_flag(), rec_get_offsets, row_build(), row_build_index_entry(), ROW_COPY_POINTERS, row_get_clust_rec(), row_get_rec_trx_id(), RW_LOCK_SHARED, dict_index_struct::table, TRUE, trx_get_on_id(), trx_is_active(), trx_undo_prev_version_build(), ut_ad, ut_dulint_cmp(), and version().
Referenced by lock_sec_rec_some_has_impl_off_kernel().
00040 : NULL if committed, else the active 00041 transaction; NOTE that the kernel mutex is 00042 temporarily released! */ 00043 rec_t* rec, /* in: record in a secondary index */ 00044 dict_index_t* index, /* in: the secondary index */ 00045 const ulint* offsets)/* in: rec_get_offsets(rec, index) */ 00046 { 00047 dict_index_t* clust_index; 00048 rec_t* clust_rec; 00049 ulint* clust_offsets; 00050 rec_t* version; 00051 rec_t* prev_version; 00052 dulint trx_id; 00053 dulint prev_trx_id; 00054 mem_heap_t* heap; 00055 mem_heap_t* heap2; 00056 dtuple_t* row; 00057 dtuple_t* entry = NULL; /* assignment to eliminate compiler 00058 warning */ 00059 trx_t* trx; 00060 ulint vers_del; 00061 ulint rec_del; 00062 ulint err; 00063 mtr_t mtr; 00064 ulint comp; 00065 00066 #ifdef UNIV_SYNC_DEBUG 00067 ut_ad(mutex_own(&kernel_mutex)); 00068 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); 00069 #endif /* UNIV_SYNC_DEBUG */ 00070 00071 mutex_exit(&kernel_mutex); 00072 00073 mtr_start(&mtr); 00074 00075 /* Search for the clustered index record: this is a time-consuming 00076 operation: therefore we release the kernel mutex; also, the release 00077 is required by the latching order convention. The latch on the 00078 clustered index locks the top of the stack of versions. We also 00079 reserve purge_latch to lock the bottom of the version stack. */ 00080 00081 clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, 00082 &clust_index, &mtr); 00083 if (!clust_rec) { 00084 /* In a rare case it is possible that no clust rec is found 00085 for a secondary index record: if in row0umod.c 00086 row_undo_mod_remove_clust_low() we have already removed the 00087 clust rec, while purge is still cleaning and removing 00088 secondary index records associated with earlier versions of 00089 the clustered index record. In that case there cannot be 00090 any implicit lock on the secondary index record, because 00091 an active transaction which has modified the secondary index 00092 record has also modified the clustered index record. And in 00093 a rollback we always undo the modifications to secondary index 00094 records before the clustered index record. */ 00095 00096 mutex_enter(&kernel_mutex); 00097 mtr_commit(&mtr); 00098 00099 return(NULL); 00100 } 00101 00102 heap = mem_heap_create(1024); 00103 clust_offsets = rec_get_offsets(clust_rec, clust_index, NULL, 00104 ULINT_UNDEFINED, &heap); 00105 trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets); 00106 00107 mtr_s_lock(&(purge_sys->latch), &mtr); 00108 00109 mutex_enter(&kernel_mutex); 00110 00111 trx = NULL; 00112 if (!trx_is_active(trx_id)) { 00113 /* The transaction that modified or inserted clust_rec is no 00114 longer active: no implicit lock on rec */ 00115 goto exit_func; 00116 } 00117 00118 if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index, 00119 clust_offsets, TRUE)) { 00120 /* Corruption noticed: try to avoid a crash by returning */ 00121 goto exit_func; 00122 } 00123 00124 comp = page_rec_is_comp(rec); 00125 ut_ad(index->table == clust_index->table); 00126 ut_ad(!!comp == dict_table_is_comp(index->table)); 00127 ut_ad(!comp == !page_rec_is_comp(clust_rec)); 00128 00129 /* We look up if some earlier version, which was modified by the trx_id 00130 transaction, of the clustered index record would require rec to be in 00131 a different state (delete marked or unmarked, or have different field 00132 values, or not existing). If there is such a version, then rec was 00133 modified by the trx_id transaction, and it has an implicit x-lock on 00134 rec. Note that if clust_rec itself would require rec to be in a 00135 different state, then the trx_id transaction has not yet had time to 00136 modify rec, and does not necessarily have an implicit x-lock on rec. */ 00137 00138 rec_del = rec_get_deleted_flag(rec, comp); 00139 trx = NULL; 00140 00141 version = clust_rec; 00142 00143 for (;;) { 00144 mutex_exit(&kernel_mutex); 00145 00146 /* While we retrieve an earlier version of clust_rec, we 00147 release the kernel mutex, because it may take time to access 00148 the disk. After the release, we have to check if the trx_id 00149 transaction is still active. We keep the semaphore in mtr on 00150 the clust_rec page, so that no other transaction can update 00151 it and get an implicit x-lock on rec. */ 00152 00153 heap2 = heap; 00154 heap = mem_heap_create(1024); 00155 err = trx_undo_prev_version_build(clust_rec, &mtr, version, 00156 clust_index, clust_offsets, heap, 00157 &prev_version); 00158 mem_heap_free(heap2); /* free version and clust_offsets */ 00159 00160 if (prev_version) { 00161 clust_offsets = rec_get_offsets(prev_version, 00162 clust_index, NULL, 00163 ULINT_UNDEFINED, &heap); 00164 row = row_build(ROW_COPY_POINTERS, clust_index, 00165 prev_version, clust_offsets, heap); 00166 entry = row_build_index_entry(row, index, heap); 00167 } 00168 00169 mutex_enter(&kernel_mutex); 00170 00171 if (!trx_is_active(trx_id)) { 00172 /* Transaction no longer active: no implicit x-lock */ 00173 00174 break; 00175 } 00176 00177 /* If the transaction is still active, the previous version 00178 of clust_rec must be accessible if not a fresh insert; we 00179 may assert the following: */ 00180 00181 ut_ad(err == DB_SUCCESS); 00182 00183 if (prev_version == NULL) { 00184 /* It was a freshly inserted version: there is an 00185 implicit x-lock on rec */ 00186 00187 trx = trx_get_on_id(trx_id); 00188 00189 break; 00190 } 00191 00192 /* If we get here, we know that the trx_id transaction is 00193 still active and it has modified prev_version. Let us check 00194 if prev_version would require rec to be in a different 00195 state. */ 00196 00197 vers_del = rec_get_deleted_flag(prev_version, comp); 00198 00199 /* We check if entry and rec are identified in the alphabetical 00200 ordering */ 00201 if (0 == cmp_dtuple_rec(entry, rec, offsets)) { 00202 /* The delete marks of rec and prev_version should be 00203 equal for rec to be in the state required by 00204 prev_version */ 00205 00206 if (rec_del != vers_del) { 00207 trx = trx_get_on_id(trx_id); 00208 00209 break; 00210 } 00211 00212 /* It is possible that the row was updated so that the 00213 secondary index record remained the same in 00214 alphabetical ordering, but the field values changed 00215 still. For example, 'abc' -> 'ABC'. Check also that. */ 00216 00217 dtuple_set_types_binary(entry, 00218 dtuple_get_n_fields(entry)); 00219 if (0 != cmp_dtuple_rec(entry, rec, offsets)) { 00220 00221 trx = trx_get_on_id(trx_id); 00222 00223 break; 00224 } 00225 } else if (!rec_del) { 00226 /* The delete mark should be set in rec for it to be 00227 in the state required by prev_version */ 00228 00229 trx = trx_get_on_id(trx_id); 00230 00231 break; 00232 } 00233 00234 prev_trx_id = row_get_rec_trx_id(prev_version, clust_index, 00235 clust_offsets); 00236 00237 if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) { 00238 /* The versions modified by the trx_id transaction end 00239 to prev_version: no implicit x-lock */ 00240 00241 break; 00242 } 00243 00244 version = prev_version; 00245 }/* for (;;) */ 00246 00247 exit_func: 00248 mtr_commit(&mtr); 00249 mem_heap_free(heap); 00250 00251 return(trx); 00252 }
Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 259 of file row0vers.c.
References FALSE, trx_purge_struct::latch, mtr_s_lock, purge_sys, RW_LOCK_SHARED, TRUE, trx_purge_update_undo_must_exist(), and ut_ad.
Referenced by row_undo_mod_remove_clust_low().
00261 : TRUE if earlier version should be preserved */ 00262 dulint trx_id, /* in: transaction id in the version */ 00263 mtr_t* mtr) /* in: mtr holding the latch on the clustered index 00264 record; it will also hold the latch on purge_view */ 00265 { 00266 #ifdef UNIV_SYNC_DEBUG 00267 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); 00268 #endif /* UNIV_SYNC_DEBUG */ 00269 00270 mtr_s_lock(&(purge_sys->latch), mtr); 00271 00272 if (trx_purge_update_undo_must_exist(trx_id)) { 00273 00274 /* A purge operation is not yet allowed to remove this 00275 delete marked record */ 00276 00277 return(TRUE); 00278 } 00279 00280 return(FALSE); 00281 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ibool row_vers_old_has_index_entry | ( | ibool | also_curr, | |
| rec_t * | rec, | |||
| mtr_t * | mtr, | |||
| dict_index_t * | index, | |||
| dtuple_t * | ientry | |||
| ) |
Definition at line 291 of file row0vers.c.
References buf_block_align(), DB_SUCCESS, dict_table_get_first_index(), dict_table_is_comp(), dtuple_datas_are_ordering_equal(), err, FALSE, index(), trx_purge_struct::latch, mem_heap_create, mem_heap_free, mtr_memo_contains(), MTR_MEMO_PAGE_S_FIX, MTR_MEMO_PAGE_X_FIX, mtr_s_lock, NULL, page_rec_is_comp(), purge_sys, rec_get_deleted_flag(), rec_get_offsets, row_build(), row_build_index_entry(), ROW_COPY_POINTERS, RW_LOCK_SHARED, TRUE, trx_undo_prev_version_build(), ut_ad, and version().
Referenced by row_purge_remove_sec_if_poss_low(), and row_undo_mod_del_mark_or_remove_sec_low().
00293 : TRUE if earlier version should have */ 00294 ibool also_curr,/* in: TRUE if also rec is included in the 00295 versions to search; otherwise only versions 00296 prior to it are searched */ 00297 rec_t* rec, /* in: record in the clustered index; the 00298 caller must have a latch on the page */ 00299 mtr_t* mtr, /* in: mtr holding the latch on rec; it will 00300 also hold the latch on purge_view */ 00301 dict_index_t* index, /* in: the secondary index */ 00302 dtuple_t* ientry) /* in: the secondary index entry */ 00303 { 00304 rec_t* version; 00305 rec_t* prev_version; 00306 dict_index_t* clust_index; 00307 ulint* clust_offsets; 00308 mem_heap_t* heap; 00309 mem_heap_t* heap2; 00310 dtuple_t* row; 00311 dtuple_t* entry; 00312 ulint err; 00313 ulint comp; 00314 00315 ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX) 00316 || mtr_memo_contains(mtr, buf_block_align(rec), 00317 MTR_MEMO_PAGE_S_FIX)); 00318 #ifdef UNIV_SYNC_DEBUG 00319 ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); 00320 #endif /* UNIV_SYNC_DEBUG */ 00321 mtr_s_lock(&(purge_sys->latch), mtr); 00322 00323 clust_index = dict_table_get_first_index(index->table); 00324 00325 comp = page_rec_is_comp(rec); 00326 ut_ad(!dict_table_is_comp(index->table) == !comp); 00327 heap = mem_heap_create(1024); 00328 clust_offsets = rec_get_offsets(rec, clust_index, NULL, 00329 ULINT_UNDEFINED, &heap); 00330 00331 if (also_curr && !rec_get_deleted_flag(rec, comp)) { 00332 row = row_build(ROW_COPY_POINTERS, clust_index, 00333 rec, clust_offsets, heap); 00334 entry = row_build_index_entry(row, index, heap); 00335 00336 /* NOTE that we cannot do the comparison as binary 00337 fields because the row is maybe being modified so that 00338 the clustered index record has already been updated 00339 to a different binary value in a char field, but the 00340 collation identifies the old and new value anyway! */ 00341 00342 if (dtuple_datas_are_ordering_equal(ientry, entry)) { 00343 00344 mem_heap_free(heap); 00345 00346 return(TRUE); 00347 } 00348 } 00349 00350 version = rec; 00351 00352 for (;;) { 00353 heap2 = heap; 00354 heap = mem_heap_create(1024); 00355 err = trx_undo_prev_version_build(rec, mtr, version, 00356 clust_index, clust_offsets, heap, 00357 &prev_version); 00358 mem_heap_free(heap2); /* free version and clust_offsets */ 00359 00360 if (err != DB_SUCCESS || !prev_version) { 00361 /* Versions end here */ 00362 00363 mem_heap_free(heap); 00364 00365 return(FALSE); 00366 } 00367 00368 clust_offsets = rec_get_offsets(prev_version, clust_index, 00369 NULL, ULINT_UNDEFINED, &heap); 00370 00371 if (!rec_get_deleted_flag(prev_version, comp)) { 00372 row = row_build(ROW_COPY_POINTERS, clust_index, 00373 prev_version, clust_offsets, heap); 00374 entry = row_build_index_entry(row, index, heap); 00375 00376 /* NOTE that we cannot do the comparison as binary 00377 fields because maybe the secondary index record has 00378 already been updated to a different binary value in 00379 a char field, but the collation identifies the old 00380 and new value anyway! */ 00381 00382 if (dtuple_datas_are_ordering_equal(ientry, entry)) { 00383 00384 mem_heap_free(heap); 00385 00386 return(TRUE); 00387 } 00388 } 00389 00390 version = prev_version; 00391 } 00392 }
Here is the call graph for this function:

Here is the caller graph for this function:

1.4.7

