#include "row0purge.h"#include "fsp0fsp.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 "row0vers.h"#include "row0mysql.h"#include "log0log.h"Include dependency graph for row0purge.c:

Go to the source code of this file.
Functions | |
| purge_node_t * | row_purge_node_create (que_thr_t *parent, mem_heap_t *heap) |
| static ibool | row_purge_reposition_pcur (ulint mode, purge_node_t *node, mtr_t *mtr) |
| static ibool | row_purge_remove_clust_if_poss_low (purge_node_t *node, ulint mode) |
| static void | row_purge_remove_clust_if_poss (purge_node_t *node) |
| static ibool | row_purge_remove_sec_if_poss_low (purge_node_t *node, dict_index_t *index, dtuple_t *entry, ulint mode) |
| UNIV_INLINE void | row_purge_remove_sec_if_poss (purge_node_t *node, dict_index_t *index, dtuple_t *entry) |
| static void | row_purge_del_mark (purge_node_t *node) |
| static void | row_purge_upd_exist_or_extern (purge_node_t *node) |
| static ibool | row_purge_parse_undo_rec (purge_node_t *node, ibool *updated_extern, que_thr_t *thr) |
| static ulint | row_purge (purge_node_t *node, que_thr_t *thr) |
| que_thr_t * | row_purge_step (que_thr_t *thr) |
| static ulint row_purge | ( | purge_node_t * | node, | |
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 578 of file row0purge.c.
References btr_pcur_close(), DB_SUCCESS, dict_table_get_first_index(), dict_table_get_next_index(), FALSE, purge_node_struct::found_clust, purge_node_struct::heap, purge_node_struct::index, mem_heap_empty(), purge_node_struct::pcur, que_node_get_parent(), purge_node_struct::rec_type, purge_node_struct::reservation, purge_node_struct::roll_ptr, row_mysql_unfreeze_data_dictionary(), row_purge_del_mark(), row_purge_parse_undo_rec(), row_purge_upd_exist_or_extern(), que_thr_struct::run_node, purge_node_struct::table, thr_get_trx(), trx_purge_dummy_rec, trx_purge_fetch_next_rec(), trx_purge_rec_release(), TRX_UNDO_DEL_MARK_REC, TRX_UNDO_UPD_EXIST_REC, purge_node_struct::undo_rec, and ut_ad.
Referenced by row_purge_step().
00580 : DB_SUCCESS if operation successfully 00581 completed, else error code */ 00582 purge_node_t* node, /* in: row purge node */ 00583 que_thr_t* thr) /* in: query thread */ 00584 { 00585 dulint roll_ptr; 00586 ibool purge_needed; 00587 ibool updated_extern; 00588 trx_t* trx; 00589 00590 ut_ad(node && thr); 00591 00592 trx = thr_get_trx(thr); 00593 00594 node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr, 00595 &(node->reservation), 00596 node->heap); 00597 if (!node->undo_rec) { 00598 /* Purge completed for this query thread */ 00599 00600 thr->run_node = que_node_get_parent(node); 00601 00602 return(DB_SUCCESS); 00603 } 00604 00605 node->roll_ptr = roll_ptr; 00606 00607 if (node->undo_rec == &trx_purge_dummy_rec) { 00608 purge_needed = FALSE; 00609 } else { 00610 purge_needed = row_purge_parse_undo_rec(node, &updated_extern, 00611 thr); 00612 /* If purge_needed == TRUE, we must also remember to unfreeze 00613 data dictionary! */ 00614 } 00615 00616 if (purge_needed) { 00617 node->found_clust = FALSE; 00618 00619 node->index = dict_table_get_next_index( 00620 dict_table_get_first_index(node->table)); 00621 00622 if (node->rec_type == TRX_UNDO_DEL_MARK_REC) { 00623 row_purge_del_mark(node); 00624 00625 } else if (updated_extern 00626 || node->rec_type == TRX_UNDO_UPD_EXIST_REC) { 00627 00628 row_purge_upd_exist_or_extern(node); 00629 } 00630 00631 if (node->found_clust) { 00632 btr_pcur_close(&(node->pcur)); 00633 } 00634 00635 row_mysql_unfreeze_data_dictionary(trx); 00636 } 00637 00638 /* Do some cleanup */ 00639 trx_purge_rec_release(node->reservation); 00640 mem_heap_empty(node->heap); 00641 00642 thr->run_node = node; 00643 00644 return(DB_SUCCESS); 00645 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_purge_del_mark | ( | purge_node_t * | node | ) | [static] |
Definition at line 328 of file row0purge.c.
References dict_table_get_next_index(), purge_node_struct::index, index(), mem_heap_create, mem_heap_free, NULL, purge_node_struct::row, row_build_index_entry(), row_purge_remove_clust_if_poss(), row_purge_remove_sec_if_poss(), and ut_ad.
Referenced by row_purge().
00330 : row purge node */ 00331 { 00332 mem_heap_t* heap; 00333 dtuple_t* entry; 00334 dict_index_t* index; 00335 00336 ut_ad(node); 00337 00338 heap = mem_heap_create(1024); 00339 00340 while (node->index != NULL) { 00341 index = node->index; 00342 00343 /* Build the index entry */ 00344 entry = row_build_index_entry(node->row, index, heap); 00345 00346 row_purge_remove_sec_if_poss(node, index, entry); 00347 00348 node->index = dict_table_get_next_index(node->index); 00349 } 00350 00351 mem_heap_free(heap); 00352 00353 row_purge_remove_clust_if_poss(node); 00354 }
Here is the call graph for this function:

Here is the caller graph for this function:

| purge_node_t* row_purge_node_create | ( | que_thr_t * | parent, | |
| mem_heap_t * | heap | |||
| ) |
Definition at line 34 of file row0purge.c.
References purge_node_struct::common, purge_node_struct::heap, mem_heap_alloc(), mem_heap_create, que_common_struct::parent, QUE_NODE_PURGE, que_common_struct::type, and ut_ad.
Referenced by trx_purge_graph_build().
00036 : purge node */ 00037 que_thr_t* parent, /* in: parent node, i.e., a thr node */ 00038 mem_heap_t* heap) /* in: memory heap where created */ 00039 { 00040 purge_node_t* node; 00041 00042 ut_ad(parent && heap); 00043 00044 node = mem_heap_alloc(heap, sizeof(purge_node_t)); 00045 00046 node->common.type = QUE_NODE_PURGE; 00047 node->common.parent = parent; 00048 00049 node->heap = mem_heap_create(256); 00050 00051 return(node); 00052 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ibool row_purge_parse_undo_rec | ( | purge_node_t * | node, | |
| ibool * | updated_extern, | |||
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 469 of file row0purge.c.
References dict_sys, dict_table_get_first_index(), dict_table_get_on_id_low(), FALSE, purge_node_struct::heap, dict_table_struct::ibd_file_missing, dict_sys_struct::mutex, mutex_enter, mutex_exit(), NULL, purge_node_struct::rec_type, purge_node_struct::ref, purge_node_struct::row, row_mysql_freeze_data_dictionary(), row_mysql_unfreeze_data_dictionary(), purge_node_struct::table, thr_get_trx(), TRUE, trx_undo_rec_get_pars(), trx_undo_rec_get_partial_row(), trx_undo_rec_get_row_ref(), TRX_UNDO_UPD_DEL_REC, TRX_UNDO_UPD_EXIST_REC, trx_undo_update_rec_get_sys_cols(), trx_undo_update_rec_get_update(), purge_node_struct::undo_rec, UPD_NODE_NO_ORD_CHANGE, purge_node_struct::update, and ut_ad.
Referenced by row_purge().
00471 : TRUE if purge operation required: 00472 NOTE that then the CALLER must unfreeze 00473 data dictionary! */ 00474 purge_node_t* node, /* in: row undo node */ 00475 ibool* updated_extern, 00476 /* out: TRUE if an externally stored field 00477 was updated */ 00478 que_thr_t* thr) /* in: query thread */ 00479 { 00480 dict_index_t* clust_index; 00481 byte* ptr; 00482 trx_t* trx; 00483 dulint undo_no; 00484 dulint table_id; 00485 dulint trx_id; 00486 dulint roll_ptr; 00487 ulint info_bits; 00488 ulint type; 00489 ulint cmpl_info; 00490 00491 ut_ad(node && thr); 00492 00493 trx = thr_get_trx(thr); 00494 00495 ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, 00496 updated_extern, &undo_no, &table_id); 00497 node->rec_type = type; 00498 00499 if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) { 00500 00501 return(FALSE); 00502 } 00503 00504 ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr, 00505 &info_bits); 00506 node->table = NULL; 00507 00508 if (type == TRX_UNDO_UPD_EXIST_REC 00509 && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { 00510 00511 /* Purge requires no changes to indexes: we may return */ 00512 00513 return(FALSE); 00514 } 00515 00516 /* Prevent DROP TABLE etc. from running when we are doing the purge 00517 for this row */ 00518 00519 row_mysql_freeze_data_dictionary(trx); 00520 00521 mutex_enter(&(dict_sys->mutex)); 00522 00523 node->table = dict_table_get_on_id_low(table_id); 00524 00525 mutex_exit(&(dict_sys->mutex)); 00526 00527 if (node->table == NULL) { 00528 /* The table has been dropped: no need to do purge */ 00529 00530 row_mysql_unfreeze_data_dictionary(trx); 00531 00532 return(FALSE); 00533 } 00534 00535 if (node->table->ibd_file_missing) { 00536 /* We skip purge of missing .ibd files */ 00537 00538 node->table = NULL; 00539 00540 row_mysql_unfreeze_data_dictionary(trx); 00541 00542 return(FALSE); 00543 } 00544 00545 clust_index = dict_table_get_first_index(node->table); 00546 00547 if (clust_index == NULL) { 00548 /* The table was corrupt in the data dictionary */ 00549 00550 row_mysql_unfreeze_data_dictionary(trx); 00551 00552 return(FALSE); 00553 } 00554 00555 ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref), 00556 node->heap); 00557 00558 ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id, 00559 roll_ptr, info_bits, trx, 00560 node->heap, &(node->update)); 00561 00562 /* Read to the partial row the fields that occur in indexes */ 00563 00564 if (!cmpl_info & UPD_NODE_NO_ORD_CHANGE) { 00565 ptr = trx_undo_rec_get_partial_row(ptr, clust_index, 00566 &(node->row), node->heap); 00567 } 00568 00569 return(TRUE); 00570 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_purge_remove_clust_if_poss | ( | purge_node_t * | node | ) | [static] |
Definition at line 167 of file row0purge.c.
References BTR_CUR_RETRY_DELETE_N_TIMES, BTR_CUR_RETRY_SLEEP_TIME, BTR_MODIFY_LEAF, BTR_MODIFY_TREE, os_thread_sleep(), row_purge_remove_clust_if_poss_low(), and ut_a.
Referenced by row_purge_del_mark().
00169 : row purge node */ 00170 { 00171 ibool success; 00172 ulint n_tries = 0; 00173 00174 /* fputs("Purge: Removing clustered record\n", stderr); */ 00175 00176 success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF); 00177 if (success) { 00178 00179 return; 00180 } 00181 retry: 00182 success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_TREE); 00183 /* The delete operation may fail if we have little 00184 file space left: TODO: easiest to crash the database 00185 and restart with more file space */ 00186 00187 if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) { 00188 n_tries++; 00189 00190 os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME); 00191 00192 goto retry; 00193 } 00194 00195 ut_a(success); 00196 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ibool row_purge_remove_clust_if_poss_low | ( | purge_node_t * | node, | |
| ulint | mode | |||
| ) | [static] |
Definition at line 89 of file row0purge.c.
References btr_cur_optimistic_delete(), btr_cur_pessimistic_delete(), BTR_MODIFY_LEAF, BTR_MODIFY_TREE, btr_pcur_commit_specify_mtr(), btr_pcur_get_btr_cur(), btr_pcur_get_rec(), DB_OUT_OF_FILE_SPACE, DB_SUCCESS, dict_table_get_first_index(), err, FALSE, index(), mem_heap_free, mtr_start(), NULL, purge_node_struct::pcur, rec_get_offsets, REC_OFFS_NORMAL_SIZE, purge_node_struct::roll_ptr, row_get_rec_roll_ptr(), row_purge_reposition_pcur(), purge_node_struct::table, TRUE, ut_ad, ut_dulint_cmp(), and ut_error.
Referenced by row_purge_remove_clust_if_poss().
00091 : TRUE if success, or if not found, or 00092 if modified after the delete marking */ 00093 purge_node_t* node, /* in: row purge node */ 00094 ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ 00095 { 00096 dict_index_t* index; 00097 btr_pcur_t* pcur; 00098 btr_cur_t* btr_cur; 00099 ibool success; 00100 ulint err; 00101 mtr_t mtr; 00102 rec_t* rec; 00103 mem_heap_t* heap = NULL; 00104 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 00105 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 00106 00107 index = dict_table_get_first_index(node->table); 00108 00109 pcur = &(node->pcur); 00110 btr_cur = btr_pcur_get_btr_cur(pcur); 00111 00112 mtr_start(&mtr); 00113 00114 success = row_purge_reposition_pcur(mode, node, &mtr); 00115 00116 if (!success) { 00117 /* The record is already removed */ 00118 00119 btr_pcur_commit_specify_mtr(pcur, &mtr); 00120 00121 return(TRUE); 00122 } 00123 00124 rec = btr_pcur_get_rec(pcur); 00125 00126 if (0 != ut_dulint_cmp(node->roll_ptr, 00127 row_get_rec_roll_ptr(rec, index, rec_get_offsets( 00128 rec, index, offsets_, ULINT_UNDEFINED, &heap)))) { 00129 if (UNIV_LIKELY_NULL(heap)) { 00130 mem_heap_free(heap); 00131 } 00132 /* Someone else has modified the record later: do not remove */ 00133 btr_pcur_commit_specify_mtr(pcur, &mtr); 00134 00135 return(TRUE); 00136 } 00137 00138 if (UNIV_LIKELY_NULL(heap)) { 00139 mem_heap_free(heap); 00140 } 00141 00142 if (mode == BTR_MODIFY_LEAF) { 00143 success = btr_cur_optimistic_delete(btr_cur, &mtr); 00144 } else { 00145 ut_ad(mode == BTR_MODIFY_TREE); 00146 btr_cur_pessimistic_delete(&err, FALSE, btr_cur, FALSE, &mtr); 00147 00148 if (err == DB_SUCCESS) { 00149 success = TRUE; 00150 } else if (err == DB_OUT_OF_FILE_SPACE) { 00151 success = FALSE; 00152 } else { 00153 ut_error; 00154 } 00155 } 00156 00157 btr_pcur_commit_specify_mtr(pcur, &mtr); 00158 00159 return(success); 00160 }
Here is the call graph for this function:

Here is the caller graph for this function:

| UNIV_INLINE void row_purge_remove_sec_if_poss | ( | purge_node_t * | node, | |
| dict_index_t * | index, | |||
| dtuple_t * | entry | |||
| ) |
Definition at line 288 of file row0purge.c.
References BTR_CUR_RETRY_DELETE_N_TIMES, BTR_CUR_RETRY_SLEEP_TIME, BTR_MODIFY_LEAF, BTR_MODIFY_TREE, index(), os_thread_sleep(), row_purge_remove_sec_if_poss_low(), and ut_a.
Referenced by row_purge_del_mark(), and row_purge_upd_exist_or_extern().
00290 : row purge node */ 00291 dict_index_t* index, /* in: index */ 00292 dtuple_t* entry) /* in: index entry */ 00293 { 00294 ibool success; 00295 ulint n_tries = 0; 00296 00297 /* fputs("Purge: Removing secondary record\n", stderr); */ 00298 00299 success = row_purge_remove_sec_if_poss_low(node, index, entry, 00300 BTR_MODIFY_LEAF); 00301 if (success) { 00302 00303 return; 00304 } 00305 retry: 00306 success = row_purge_remove_sec_if_poss_low(node, index, entry, 00307 BTR_MODIFY_TREE); 00308 /* The delete operation may fail if we have little 00309 file space left: TODO: easiest to crash the database 00310 and restart with more file space */ 00311 00312 if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) { 00313 00314 n_tries++; 00315 00316 os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME); 00317 00318 goto retry; 00319 } 00320 00321 ut_a(success); 00322 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ibool row_purge_remove_sec_if_poss_low | ( | purge_node_t * | node, | |
| dict_index_t * | index, | |||
| dtuple_t * | entry, | |||
| ulint | mode | |||
| ) | [static] |
Definition at line 202 of file row0purge.c.
References btr_cur_optimistic_delete(), btr_cur_pessimistic_delete(), BTR_MODIFY_LEAF, BTR_MODIFY_TREE, btr_pcur_close(), btr_pcur_commit_specify_mtr(), btr_pcur_get_btr_cur(), btr_pcur_get_rec(), BTR_SEARCH_LEAF, DB_OUT_OF_FILE_SPACE, DB_SUCCESS, err, FALSE, index(), log_free_check(), mem_alloc, mem_free, mtr_commit(), mtr_start(), purge_node_struct::pcur, row_purge_reposition_pcur(), row_search_index_entry(), row_vers_old_has_index_entry(), TRUE, ut_ad, and ut_error.
Referenced by row_purge_remove_sec_if_poss().
00204 : TRUE if success or if not found */ 00205 purge_node_t* node, /* in: row purge node */ 00206 dict_index_t* index, /* in: index */ 00207 dtuple_t* entry, /* in: index entry */ 00208 ulint mode) /* in: latch mode BTR_MODIFY_LEAF or 00209 BTR_MODIFY_TREE */ 00210 { 00211 btr_pcur_t pcur; 00212 btr_cur_t* btr_cur; 00213 ibool success; 00214 ibool old_has = 0; /* remove warning */ 00215 ibool found; 00216 ulint err; 00217 mtr_t mtr; 00218 mtr_t* mtr_vers; 00219 00220 log_free_check(); 00221 mtr_start(&mtr); 00222 00223 found = row_search_index_entry(index, entry, mode, &pcur, &mtr); 00224 00225 if (!found) { 00226 /* Not found */ 00227 00228 /* fputs("PURGE:........sec entry not found\n", stderr); */ 00229 /* dtuple_print(entry); */ 00230 00231 btr_pcur_close(&pcur); 00232 mtr_commit(&mtr); 00233 00234 return(TRUE); 00235 } 00236 00237 btr_cur = btr_pcur_get_btr_cur(&pcur); 00238 00239 /* We should remove the index record if no later version of the row, 00240 which cannot be purged yet, requires its existence. If some requires, 00241 we should do nothing. */ 00242 00243 mtr_vers = mem_alloc(sizeof(mtr_t)); 00244 00245 mtr_start(mtr_vers); 00246 00247 success = row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, mtr_vers); 00248 00249 if (success) { 00250 old_has = row_vers_old_has_index_entry(TRUE, 00251 btr_pcur_get_rec(&(node->pcur)), 00252 mtr_vers, index, entry); 00253 } 00254 00255 btr_pcur_commit_specify_mtr(&(node->pcur), mtr_vers); 00256 00257 mem_free(mtr_vers); 00258 00259 if (!success || !old_has) { 00260 /* Remove the index record */ 00261 00262 if (mode == BTR_MODIFY_LEAF) { 00263 success = btr_cur_optimistic_delete(btr_cur, &mtr); 00264 } else { 00265 ut_ad(mode == BTR_MODIFY_TREE); 00266 btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 00267 FALSE, &mtr); 00268 if (err == DB_SUCCESS) { 00269 success = TRUE; 00270 } else if (err == DB_OUT_OF_FILE_SPACE) { 00271 success = FALSE; 00272 } else { 00273 ut_error; 00274 } 00275 } 00276 } 00277 00278 btr_pcur_close(&pcur); 00279 mtr_commit(&mtr); 00280 00281 return(success); 00282 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ibool row_purge_reposition_pcur | ( | ulint | mode, | |
| purge_node_t * | node, | |||
| mtr_t * | mtr | |||
| ) | [static] |
Definition at line 59 of file row0purge.c.
References btr_pcur_restore_position(), btr_pcur_store_position(), purge_node_struct::found_clust, purge_node_struct::pcur, purge_node_struct::ref, row_search_on_row_ref(), and purge_node_struct::table.
Referenced by row_purge_remove_clust_if_poss_low(), and row_purge_remove_sec_if_poss_low().
00061 : TRUE if the record was found */ 00062 ulint mode, /* in: latching mode */ 00063 purge_node_t* node, /* in: row purge node */ 00064 mtr_t* mtr) /* in: mtr */ 00065 { 00066 ibool found; 00067 00068 if (node->found_clust) { 00069 found = btr_pcur_restore_position(mode, &(node->pcur), mtr); 00070 00071 return(found); 00072 } 00073 00074 found = row_search_on_row_ref(&(node->pcur), mode, node->table, 00075 node->ref, mtr); 00076 node->found_clust = found; 00077 00078 if (found) { 00079 btr_pcur_store_position(&(node->pcur), mtr); 00080 } 00081 00082 return(found); 00083 }
Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 652 of file row0purge.c.
References DB_SUCCESS, err, que_node_get_type(), QUE_NODE_PURGE, row_purge(), que_thr_struct::run_node, and ut_ad.
Referenced by que_thr_step().
00654 : query thread to run next or NULL */ 00655 que_thr_t* thr) /* in: query thread */ 00656 { 00657 purge_node_t* node; 00658 ulint err; 00659 00660 ut_ad(thr); 00661 00662 node = thr->run_node; 00663 00664 ut_ad(que_node_get_type(node) == QUE_NODE_PURGE); 00665 00666 err = row_purge(node, thr); 00667 00668 ut_ad(err == DB_SUCCESS); 00669 00670 return(thr); 00671 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_purge_upd_exist_or_extern | ( | purge_node_t * | node | ) | [static] |
Definition at line 361 of file row0purge.c.
References btr_free_externally_stored_field(), btr_root_get(), buf_frame_align(), buf_page_get, dfield_struct::data, dict_table_get_first_index(), dict_table_get_next_index(), dict_tree_get_lock(), upd_field_struct::extern_storage, FALSE, purge_node_struct::index, index(), dfield_struct::len, mem_heap_create, mem_heap_free, mtr_commit(), mtr_start(), mtr_x_lock, upd_field_struct::new_val, NULL, offset, purge_node_struct::rec_type, purge_node_struct::roll_ptr, purge_node_struct::row, row_build_index_entry(), row_purge_remove_sec_if_poss(), row_upd_changes_ord_field_binary(), RW_X_LATCH, SYNC_TRX_UNDO_PAGE, purge_node_struct::table, trx_undo_decode_roll_ptr(), TRX_UNDO_UPD_DEL_REC, purge_node_struct::undo_rec, UNIV_PAGE_SIZE, upd_get_n_fields(), upd_get_nth_field(), purge_node_struct::update, ut_a, and ut_ad.
Referenced by row_purge().
00363 : row purge node */ 00364 { 00365 mem_heap_t* heap; 00366 dtuple_t* entry; 00367 dict_index_t* index; 00368 upd_field_t* ufield; 00369 ibool is_insert; 00370 ulint rseg_id; 00371 ulint page_no; 00372 ulint offset; 00373 ulint internal_offset; 00374 byte* data_field; 00375 ulint data_field_len; 00376 ulint i; 00377 mtr_t mtr; 00378 00379 ut_ad(node); 00380 00381 if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { 00382 00383 goto skip_secondaries; 00384 } 00385 00386 heap = mem_heap_create(1024); 00387 00388 while (node->index != NULL) { 00389 index = node->index; 00390 00391 if (row_upd_changes_ord_field_binary(NULL, node->index, 00392 node->update)) { 00393 /* Build the older version of the index entry */ 00394 entry = row_build_index_entry(node->row, index, heap); 00395 00396 row_purge_remove_sec_if_poss(node, index, entry); 00397 } 00398 00399 node->index = dict_table_get_next_index(node->index); 00400 } 00401 00402 mem_heap_free(heap); 00403 00404 skip_secondaries: 00405 /* Free possible externally stored fields */ 00406 for (i = 0; i < upd_get_n_fields(node->update); i++) { 00407 00408 ufield = upd_get_nth_field(node->update, i); 00409 00410 if (ufield->extern_storage) { 00411 /* We use the fact that new_val points to 00412 node->undo_rec and get thus the offset of 00413 dfield data inside the unod record. Then we 00414 can calculate from node->roll_ptr the file 00415 address of the new_val data */ 00416 00417 internal_offset = ((byte*)ufield->new_val.data) 00418 - node->undo_rec; 00419 00420 ut_a(internal_offset < UNIV_PAGE_SIZE); 00421 00422 trx_undo_decode_roll_ptr(node->roll_ptr, 00423 &is_insert, &rseg_id, 00424 &page_no, &offset); 00425 mtr_start(&mtr); 00426 00427 /* We have to acquire an X-latch to the clustered 00428 index tree */ 00429 00430 index = dict_table_get_first_index(node->table); 00431 00432 mtr_x_lock(dict_tree_get_lock(index->tree), &mtr); 00433 00434 /* NOTE: we must also acquire an X-latch to the 00435 root page of the tree. We will need it when we 00436 free pages from the tree. If the tree is of height 1, 00437 the tree X-latch does NOT protect the root page, 00438 because it is also a leaf page. Since we will have a 00439 latch on an undo log page, we would break the 00440 latching order if we would only later latch the 00441 root page of such a tree! */ 00442 00443 btr_root_get(index->tree, &mtr); 00444 00445 /* We assume in purge of externally stored fields 00446 that the space id of the undo log record is 0! */ 00447 00448 data_field = buf_page_get(0, page_no, RW_X_LATCH, &mtr) 00449 + offset + internal_offset; 00450 00451 #ifdef UNIV_SYNC_DEBUG 00452 buf_page_dbg_add_level(buf_frame_align(data_field), 00453 SYNC_TRX_UNDO_PAGE); 00454 #endif /* UNIV_SYNC_DEBUG */ 00455 00456 data_field_len = ufield->new_val.len; 00457 00458 btr_free_externally_stored_field(index, data_field, 00459 data_field_len, FALSE, &mtr); 00460 mtr_commit(&mtr); 00461 } 00462 } 00463 }
Here is the call graph for this function:

Here is the caller graph for this function:

1.4.7

