00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "row0purge.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "row0purge.ic"
00030 #endif
00031
00032 #include "fsp0fsp.h"
00033 #include "mach0data.h"
00034 #include "trx0rseg.h"
00035 #include "trx0trx.h"
00036 #include "trx0roll.h"
00037 #include "trx0undo.h"
00038 #include "trx0purge.h"
00039 #include "trx0rec.h"
00040 #include "que0que.h"
00041 #include "row0row.h"
00042 #include "row0upd.h"
00043 #include "row0vers.h"
00044 #include "row0mysql.h"
00045 #include "log0log.h"
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00070 UNIV_INTERN
00071 purge_node_t*
00072 row_purge_node_create(
00073
00074 que_thr_t* parent,
00075 mem_heap_t* heap)
00076 {
00077 purge_node_t* node;
00078
00079 ut_ad(parent && heap);
00080
00081 node = static_cast<purge_node_t *>(mem_heap_alloc(heap, sizeof(purge_node_t)));
00082
00083 node->common.type = QUE_NODE_PURGE;
00084 node->common.parent = parent;
00085
00086 node->heap = mem_heap_create(256);
00087
00088 return(node);
00089 }
00090
00091
00095 static
00096 ibool
00097 row_purge_reposition_pcur(
00098
00099 ulint mode,
00100 purge_node_t* node,
00101 mtr_t* mtr)
00102 {
00103 ibool found;
00104
00105 if (node->found_clust) {
00106 found = btr_pcur_restore_position(mode, &(node->pcur), mtr);
00107
00108 return(found);
00109 }
00110
00111 found = row_search_on_row_ref(&(node->pcur), mode, node->table,
00112 node->ref, mtr);
00113 node->found_clust = found;
00114
00115 if (found) {
00116 btr_pcur_store_position(&(node->pcur), mtr);
00117 }
00118
00119 return(found);
00120 }
00121
00122
00126 static
00127 ibool
00128 row_purge_remove_clust_if_poss_low(
00129
00130 purge_node_t* node,
00131 ulint mode)
00132 {
00133 dict_index_t* index;
00134 btr_pcur_t* pcur;
00135 btr_cur_t* btr_cur;
00136 ibool success;
00137 ulint err;
00138 mtr_t mtr;
00139 rec_t* rec;
00140 mem_heap_t* heap = NULL;
00141 ulint offsets_[REC_OFFS_NORMAL_SIZE];
00142 rec_offs_init(offsets_);
00143
00144 index = dict_table_get_first_index(node->table);
00145
00146 pcur = &(node->pcur);
00147 btr_cur = btr_pcur_get_btr_cur(pcur);
00148
00149 log_free_check();
00150 mtr_start(&mtr);
00151
00152 success = row_purge_reposition_pcur(mode, node, &mtr);
00153
00154 if (!success) {
00155
00156
00157 btr_pcur_commit_specify_mtr(pcur, &mtr);
00158
00159 return(TRUE);
00160 }
00161
00162 rec = btr_pcur_get_rec(pcur);
00163
00164 if (node->roll_ptr != row_get_rec_roll_ptr(
00165 rec, index, rec_get_offsets(rec, index, offsets_,
00166 ULINT_UNDEFINED, &heap))) {
00167 if (UNIV_LIKELY_NULL(heap)) {
00168 mem_heap_free(heap);
00169 }
00170
00171 btr_pcur_commit_specify_mtr(pcur, &mtr);
00172
00173 return(TRUE);
00174 }
00175
00176 if (UNIV_LIKELY_NULL(heap)) {
00177 mem_heap_free(heap);
00178 }
00179
00180 if (mode == BTR_MODIFY_LEAF) {
00181 success = btr_cur_optimistic_delete(btr_cur, &mtr);
00182 } else {
00183 ut_ad(mode == BTR_MODIFY_TREE);
00184 btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
00185 RB_NONE, &mtr);
00186
00187 if (err == DB_SUCCESS) {
00188 success = TRUE;
00189 } else if (err == DB_OUT_OF_FILE_SPACE) {
00190 success = FALSE;
00191 } else {
00192 ut_error;
00193 }
00194 }
00195
00196 btr_pcur_commit_specify_mtr(pcur, &mtr);
00197
00198 return(success);
00199 }
00200
00201
00204 static
00205 void
00206 row_purge_remove_clust_if_poss(
00207
00208 purge_node_t* node)
00209 {
00210 ibool success;
00211 ulint n_tries = 0;
00212
00213
00214
00215 success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF);
00216 if (success) {
00217
00218 return;
00219 }
00220 retry:
00221 success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_TREE);
00222
00223
00224
00225
00226 if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
00227 n_tries++;
00228
00229 os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
00230
00231 goto retry;
00232 }
00233
00234 ut_a(success);
00235 }
00236
00237
00252 UNIV_INTERN
00253 ibool
00254 row_purge_poss_sec(
00255
00256 purge_node_t* node,
00257 dict_index_t* index,
00258 const dtuple_t* entry)
00259 {
00260 ibool can_delete;
00261 mtr_t mtr;
00262
00263 ut_ad(!dict_index_is_clust(index));
00264 mtr_start(&mtr);
00265
00266 can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
00267 || !row_vers_old_has_index_entry(TRUE,
00268 btr_pcur_get_rec(&node->pcur),
00269 &mtr, index, entry);
00270
00271 btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
00272
00273 return(can_delete);
00274 }
00275
00276
00277
00278
00279
00280 static
00281 ibool
00282 row_purge_remove_sec_if_poss_tree(
00283
00284 purge_node_t* node,
00285 dict_index_t* index,
00286 const dtuple_t* entry)
00287 {
00288 btr_pcur_t pcur;
00289 btr_cur_t* btr_cur;
00290 ibool success = TRUE;
00291 ulint err;
00292 mtr_t mtr;
00293 enum row_search_result search_result;
00294
00295 log_free_check();
00296 mtr_start(&mtr);
00297
00298 search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
00299 &pcur, &mtr);
00300
00301 switch (search_result) {
00302 case ROW_NOT_FOUND:
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 goto func_exit;
00316 case ROW_FOUND:
00317 break;
00318 case ROW_BUFFERED:
00319 case ROW_NOT_DELETED_REF:
00320
00321
00322
00323 ut_error;
00324 }
00325
00326 btr_cur = btr_pcur_get_btr_cur(&pcur);
00327
00328
00329
00330
00331
00332 if (row_purge_poss_sec(node, index, entry)) {
00333
00334
00335 ut_ad(REC_INFO_DELETED_FLAG
00336 & rec_get_info_bits(btr_cur_get_rec(btr_cur),
00337 dict_table_is_comp(index->table)));
00338
00339 btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
00340 RB_NONE, &mtr);
00341 switch (UNIV_EXPECT(err, DB_SUCCESS)) {
00342 case DB_SUCCESS:
00343 break;
00344 case DB_OUT_OF_FILE_SPACE:
00345 success = FALSE;
00346 break;
00347 default:
00348 ut_error;
00349 }
00350 }
00351
00352 func_exit:
00353 btr_pcur_close(&pcur);
00354 mtr_commit(&mtr);
00355
00356 return(success);
00357 }
00358
00359
00360
00361
00362
00363 static
00364 ibool
00365 row_purge_remove_sec_if_poss_leaf(
00366
00367 purge_node_t* node,
00368 dict_index_t* index,
00369 const dtuple_t* entry)
00370 {
00371 mtr_t mtr;
00372 btr_pcur_t pcur;
00373 enum row_search_result search_result;
00374
00375 log_free_check();
00376
00377 mtr_start(&mtr);
00378
00379
00380 pcur.btr_cur.purge_node = node;
00381
00382
00383 pcur.btr_cur.thr = static_cast<que_thr_t *>(que_node_get_parent(node));
00384
00385 search_result = row_search_index_entry(
00386 index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
00387
00388 switch (search_result) {
00389 ibool success;
00390 case ROW_FOUND:
00391
00392
00393 if (row_purge_poss_sec(node, index, entry)) {
00394 btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
00395
00396
00397 ut_ad(REC_INFO_DELETED_FLAG
00398 & rec_get_info_bits(
00399 btr_cur_get_rec(btr_cur),
00400 dict_table_is_comp(index->table)));
00401
00402 if (!btr_cur_optimistic_delete(btr_cur, &mtr)) {
00403
00404
00405 success = FALSE;
00406 goto func_exit;
00407 }
00408 }
00409
00410
00411 case ROW_NOT_DELETED_REF:
00412
00413 case ROW_BUFFERED:
00414
00415 case ROW_NOT_FOUND:
00416
00417 success = TRUE;
00418 func_exit:
00419 btr_pcur_close(&pcur);
00420 mtr_commit(&mtr);
00421 return(success);
00422 }
00423
00424 ut_error;
00425 return(FALSE);
00426 }
00427
00428
00430 UNIV_INLINE
00431 void
00432 row_purge_remove_sec_if_poss(
00433
00434 purge_node_t* node,
00435 dict_index_t* index,
00436 dtuple_t* entry)
00437 {
00438 ibool success;
00439 ulint n_tries = 0;
00440
00441
00442
00443 if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
00444
00445 return;
00446 }
00447 retry:
00448 success = row_purge_remove_sec_if_poss_tree(node, index, entry);
00449
00450
00451
00452
00453 if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
00454
00455 n_tries++;
00456
00457 os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
00458
00459 goto retry;
00460 }
00461
00462 ut_a(success);
00463 }
00464
00465
00467 static
00468 void
00469 row_purge_del_mark(
00470
00471 purge_node_t* node)
00472 {
00473 mem_heap_t* heap;
00474 dtuple_t* entry;
00475 dict_index_t* index;
00476
00477 ut_ad(node);
00478
00479 heap = mem_heap_create(1024);
00480
00481 while (node->index != NULL) {
00482 index = node->index;
00483
00484
00485 entry = row_build_index_entry(node->row, NULL, index, heap);
00486 ut_a(entry);
00487 row_purge_remove_sec_if_poss(node, index, entry);
00488
00489 node->index = dict_table_get_next_index(node->index);
00490 }
00491
00492 mem_heap_free(heap);
00493
00494 row_purge_remove_clust_if_poss(node);
00495 }
00496
00497
00500 static
00501 void
00502 row_purge_upd_exist_or_extern(
00503
00504 purge_node_t* node)
00505 {
00506 mem_heap_t* heap;
00507 dtuple_t* entry;
00508 dict_index_t* index;
00509 ibool is_insert;
00510 ulint rseg_id;
00511 ulint page_no;
00512 ulint offset;
00513 ulint i;
00514 mtr_t mtr;
00515
00516 ut_ad(node);
00517
00518 if (node->rec_type == TRX_UNDO_UPD_DEL_REC) {
00519
00520 goto skip_secondaries;
00521 }
00522
00523 heap = mem_heap_create(1024);
00524
00525 while (node->index != NULL) {
00526 index = node->index;
00527
00528 if (row_upd_changes_ord_field_binary(NULL, node->index,
00529 node->update)) {
00530
00531 entry = row_build_index_entry(node->row, NULL,
00532 index, heap);
00533 ut_a(entry);
00534 row_purge_remove_sec_if_poss(node, index, entry);
00535 }
00536
00537 node->index = dict_table_get_next_index(node->index);
00538 }
00539
00540 mem_heap_free(heap);
00541
00542 skip_secondaries:
00543
00544 for (i = 0; i < upd_get_n_fields(node->update); i++) {
00545
00546 const upd_field_t* ufield
00547 = upd_get_nth_field(node->update, i);
00548
00549 if (dfield_is_ext(&ufield->new_val)) {
00550 buf_block_t* block;
00551 ulint internal_offset;
00552 byte* data_field;
00553
00554
00555
00556
00557
00558
00559
00560 internal_offset
00561 = ((const byte*)
00562 dfield_get_data(&ufield->new_val))
00563 - node->undo_rec;
00564
00565 ut_a(internal_offset < UNIV_PAGE_SIZE);
00566
00567 trx_undo_decode_roll_ptr(node->roll_ptr,
00568 &is_insert, &rseg_id,
00569 &page_no, &offset);
00570 mtr_start(&mtr);
00571
00572
00573
00574
00575 index = dict_table_get_first_index(node->table);
00576
00577 mtr_x_lock(dict_index_get_lock(index), &mtr);
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 btr_root_get(index, &mtr);
00589
00590
00591
00592
00593 block = buf_page_get(0, 0, page_no, RW_X_LATCH, &mtr);
00594 buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
00595
00596 data_field = buf_block_get_frame(block)
00597 + offset + internal_offset;
00598
00599 ut_a(dfield_get_len(&ufield->new_val)
00600 >= BTR_EXTERN_FIELD_REF_SIZE);
00601 btr_free_externally_stored_field(
00602 index,
00603 data_field + dfield_get_len(&ufield->new_val)
00604 - BTR_EXTERN_FIELD_REF_SIZE,
00605 NULL, NULL, NULL, 0, RB_NONE, &mtr);
00606 mtr_commit(&mtr);
00607 }
00608 }
00609 }
00610
00611
00615 static
00616 ibool
00617 row_purge_parse_undo_rec(
00618
00619 purge_node_t* node,
00620 ibool* updated_extern,
00623 que_thr_t* thr)
00624 {
00625 dict_index_t* clust_index;
00626 byte* ptr;
00627 trx_t* trx;
00628 undo_no_t undo_no;
00629 table_id_t table_id;
00630 trx_id_t trx_id;
00631 roll_ptr_t roll_ptr;
00632 ulint info_bits;
00633 ulint type;
00634 ulint cmpl_info;
00635
00636 ut_ad(node && thr);
00637
00638 trx = thr_get_trx(thr);
00639
00640 ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
00641 updated_extern, &undo_no, &table_id);
00642 node->rec_type = type;
00643
00644 if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) {
00645
00646 return(FALSE);
00647 }
00648
00649 ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
00650 &info_bits);
00651 node->table = NULL;
00652
00653 if (type == TRX_UNDO_UPD_EXIST_REC
00654 && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) {
00655
00656
00657
00658 return(FALSE);
00659 }
00660
00661
00662
00663
00664 row_mysql_freeze_data_dictionary(trx);
00665
00666 mutex_enter(&(dict_sys->mutex));
00667
00668 node->table = dict_table_get_on_id_low(table_id);
00669
00670 mutex_exit(&(dict_sys->mutex));
00671
00672 if (node->table == NULL) {
00673
00674 err_exit:
00675 row_mysql_unfreeze_data_dictionary(trx);
00676 return(FALSE);
00677 }
00678
00679 if (node->table->ibd_file_missing) {
00680
00681
00682 node->table = NULL;
00683
00684 goto err_exit;
00685 }
00686
00687 clust_index = dict_table_get_first_index(node->table);
00688
00689 if (clust_index == NULL) {
00690
00691
00692 goto err_exit;
00693 }
00694
00695 ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
00696 node->heap);
00697
00698 ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
00699 roll_ptr, info_bits, trx,
00700 node->heap, &(node->update));
00701
00702
00703
00704 if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
00705 ptr = trx_undo_rec_get_partial_row(
00706 ptr, clust_index, &node->row,
00707 type == TRX_UNDO_UPD_DEL_REC,
00708 node->heap);
00709 }
00710
00711 return(TRUE);
00712 }
00713
00714
00719 static
00720 ulint
00721 row_purge(
00722
00723 purge_node_t* node,
00724 que_thr_t* thr)
00725 {
00726 roll_ptr_t roll_ptr;
00727 ibool purge_needed;
00728 ibool updated_extern;
00729 trx_t* trx;
00730
00731 ut_ad(node && thr);
00732
00733 trx = thr_get_trx(thr);
00734
00735 node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
00736 &(node->reservation),
00737 node->heap);
00738 if (!node->undo_rec) {
00739
00740
00741 thr->run_node = que_node_get_parent(node);
00742
00743 return(DB_SUCCESS);
00744 }
00745
00746 node->roll_ptr = roll_ptr;
00747
00748 if (node->undo_rec == &trx_purge_dummy_rec) {
00749 purge_needed = FALSE;
00750 } else {
00751 purge_needed = row_purge_parse_undo_rec(node, &updated_extern,
00752 thr);
00753
00754
00755 }
00756
00757 if (purge_needed) {
00758 node->found_clust = FALSE;
00759
00760 node->index = dict_table_get_next_index(
00761 dict_table_get_first_index(node->table));
00762
00763 if (node->rec_type == TRX_UNDO_DEL_MARK_REC) {
00764 row_purge_del_mark(node);
00765
00766 } else if (updated_extern
00767 || node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
00768
00769 row_purge_upd_exist_or_extern(node);
00770 }
00771
00772 if (node->found_clust) {
00773 btr_pcur_close(&(node->pcur));
00774 }
00775
00776 row_mysql_unfreeze_data_dictionary(trx);
00777 }
00778
00779
00780 trx_purge_rec_release(node->reservation);
00781 mem_heap_empty(node->heap);
00782
00783 thr->run_node = node;
00784
00785 return(DB_SUCCESS);
00786 }
00787
00788
00792 UNIV_INTERN
00793 que_thr_t*
00794 row_purge_step(
00795
00796 que_thr_t* thr)
00797 {
00798 purge_node_t* node;
00799 #ifdef UNIV_DEBUG
00800 ulint err;
00801 #endif
00802
00803 ut_ad(thr);
00804
00805 node = static_cast<purge_node_t *>(thr->run_node);
00806
00807 ut_ad(que_node_get_type(node) == QUE_NODE_PURGE);
00808
00809 #ifdef UNIV_DEBUG
00810 err =
00811 #endif
00812 row_purge(node, thr);
00813
00814 #ifdef UNIV_DEBUG
00815 ut_a(err == DB_SUCCESS);
00816 #endif
00817
00818 return(thr);
00819 }