00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "trx0purge.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "trx0purge.ic"
00030 #endif
00031
00032 #include "fsp0fsp.h"
00033 #include "mach0data.h"
00034 #include "mtr0log.h"
00035 #include "trx0rseg.h"
00036 #include "trx0trx.h"
00037 #include "trx0roll.h"
00038 #include "read0read.h"
00039 #include "fut0fut.h"
00040 #include "que0que.h"
00041 #include "row0purge.h"
00042 #include "row0upd.h"
00043 #include "trx0rec.h"
00044 #include "srv0srv.h"
00045 #include "os0thread.h"
00046
00048 UNIV_INTERN trx_purge_t* purge_sys = NULL;
00049
00052 UNIV_INTERN trx_undo_rec_t trx_purge_dummy_rec;
00053
00054 #ifdef UNIV_PFS_RWLOCK
00055
00056 UNIV_INTERN mysql_pfs_key_t trx_purge_latch_key;
00057 #endif
00058
00059 #ifdef UNIV_PFS_MUTEX
00060
00061 UNIV_INTERN mysql_pfs_key_t purge_sys_mutex_key;
00062 #endif
00063
00064
00070 UNIV_INTERN
00071 ibool
00072 trx_purge_update_undo_must_exist(
00073
00074 trx_id_t trx_id)
00075 {
00076 #ifdef UNIV_SYNC_DEBUG
00077 ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
00078 #endif
00079
00080 if (!read_view_sees_trx_id(purge_sys->view, trx_id)) {
00081
00082 return(TRUE);
00083 }
00084
00085 return(FALSE);
00086 }
00087
00088
00089
00090
00093 static
00094 trx_undo_inf_t*
00095 trx_purge_arr_store_info(
00096
00097 trx_id_t trx_no,
00098 undo_no_t undo_no)
00099 {
00100 trx_undo_inf_t* cell;
00101 trx_undo_arr_t* arr;
00102 ulint i;
00103
00104 arr = purge_sys->arr;
00105
00106 for (i = 0;; i++) {
00107 cell = trx_undo_arr_get_nth_info(arr, i);
00108
00109 if (!(cell->in_use)) {
00110
00111 cell->undo_no = undo_no;
00112 cell->trx_no = trx_no;
00113 cell->in_use = TRUE;
00114
00115 arr->n_used++;
00116
00117 return(cell);
00118 }
00119 }
00120 }
00121
00122
00124 UNIV_INLINE
00125 void
00126 trx_purge_arr_remove_info(
00127
00128 trx_undo_inf_t* cell)
00129 {
00130 trx_undo_arr_t* arr;
00131
00132 arr = purge_sys->arr;
00133
00134 cell->in_use = FALSE;
00135
00136 ut_ad(arr->n_used > 0);
00137
00138 arr->n_used--;
00139 }
00140
00141
00143 static
00144 void
00145 trx_purge_arr_get_biggest(
00146
00147 trx_undo_arr_t* arr,
00148 trx_id_t* trx_no,
00150 undo_no_t* undo_no)
00151 {
00152 trx_undo_inf_t* cell;
00153 trx_id_t pair_trx_no;
00154 undo_no_t pair_undo_no;
00155 ulint i;
00156 ulint n;
00157
00158 n = arr->n_used;
00159 pair_trx_no = 0;
00160 pair_undo_no = 0;
00161
00162 if (n) {
00163 for (i = 0;; i++) {
00164 cell = trx_undo_arr_get_nth_info(arr, i);
00165
00166 if (!cell->in_use) {
00167 continue;
00168 }
00169
00170 if ((cell->trx_no > pair_trx_no)
00171 || ((cell->trx_no == pair_trx_no)
00172 && cell->undo_no >= pair_undo_no)) {
00173
00174 pair_trx_no = cell->trx_no;
00175 pair_undo_no = cell->undo_no;
00176 }
00177
00178 if (!--n) {
00179 break;
00180 }
00181 }
00182 }
00183
00184 *trx_no = pair_trx_no;
00185 *undo_no = pair_undo_no;
00186 }
00187
00188
00192 static
00193 que_t*
00194 trx_purge_graph_build(void)
00195
00196 {
00197 mem_heap_t* heap;
00198 que_fork_t* fork;
00199 que_thr_t* thr;
00200
00201
00202 heap = mem_heap_create(512);
00203 fork = que_fork_create(NULL, NULL, QUE_FORK_PURGE, heap);
00204 fork->trx = purge_sys->trx;
00205
00206 thr = que_thr_create(fork, heap);
00207
00208 thr->child = row_purge_node_create(thr, heap);
00209
00210
00211
00212
00213
00214 return(fork);
00215 }
00216
00217
00220 UNIV_INTERN
00221 void
00222 trx_purge_sys_create(void)
00223
00224 {
00225 ut_ad(mutex_own(&kernel_mutex));
00226
00227 purge_sys = static_cast<trx_purge_t *>(mem_alloc(sizeof(trx_purge_t)));
00228
00229 purge_sys->state = TRX_STOP_PURGE;
00230
00231 purge_sys->n_pages_handled = 0;
00232
00233 purge_sys->purge_trx_no = 0;
00234 purge_sys->purge_undo_no = 0;
00235 purge_sys->next_stored = FALSE;
00236
00237 rw_lock_create(trx_purge_latch_key,
00238 &purge_sys->latch, SYNC_PURGE_LATCH);
00239
00240 mutex_create(purge_sys_mutex_key,
00241 &purge_sys->mutex, SYNC_PURGE_SYS);
00242
00243 purge_sys->heap = mem_heap_create(256);
00244
00245 purge_sys->arr = trx_undo_arr_create();
00246
00247 purge_sys->sess = sess_open();
00248
00249 purge_sys->trx = purge_sys->sess->trx;
00250
00251 purge_sys->trx->is_purge = 1;
00252
00253 ut_a(trx_start_low(purge_sys->trx, ULINT_UNDEFINED));
00254
00255 purge_sys->query = trx_purge_graph_build();
00256
00257 purge_sys->view = read_view_oldest_copy_or_open_new(0,
00258 purge_sys->heap);
00259 }
00260
00261
00262
00263 UNIV_INTERN
00264 void
00265 trx_purge_sys_close(void)
00266
00267 {
00268 ut_ad(!mutex_own(&kernel_mutex));
00269
00270 que_graph_free(purge_sys->query);
00271
00272 ut_a(purge_sys->sess->trx->is_purge);
00273 purge_sys->sess->trx->conc_state = TRX_NOT_STARTED;
00274 sess_close(purge_sys->sess);
00275 purge_sys->sess = NULL;
00276
00277 if (purge_sys->view != NULL) {
00278
00279
00280 mutex_enter(&kernel_mutex);
00281
00282 read_view_close(purge_sys->view);
00283 purge_sys->view = NULL;
00284
00285 mutex_exit(&kernel_mutex);
00286 }
00287
00288 trx_undo_arr_free(purge_sys->arr);
00289
00290 rw_lock_free(&purge_sys->latch);
00291 mutex_free(&purge_sys->mutex);
00292
00293 mem_heap_free(purge_sys->heap);
00294 mem_free(purge_sys);
00295
00296 purge_sys = NULL;
00297 }
00298
00299
00300
00301
00304 UNIV_INTERN
00305 void
00306 trx_purge_add_update_undo_to_history(
00307
00308 trx_t* trx,
00309 page_t* undo_page,
00311 mtr_t* mtr)
00312 {
00313 trx_undo_t* undo;
00314 trx_rseg_t* rseg;
00315 trx_rsegf_t* rseg_header;
00316 #ifdef UNIV_DEBUG
00317 trx_usegf_t* seg_header;
00318 #endif
00319 trx_ulogf_t* undo_header;
00320 ulint hist_size;
00321
00322 undo = trx->update_undo;
00323
00324 ut_ad(undo);
00325
00326 rseg = undo->rseg;
00327
00328 ut_ad(mutex_own(&(rseg->mutex)));
00329
00330 rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size,
00331 rseg->page_no, mtr);
00332
00333 undo_header = undo_page + undo->hdr_offset;
00334 #ifdef UNIV_DEBUG
00335 seg_header = undo_page + TRX_UNDO_SEG_HDR;
00336 #endif
00337
00338 if (undo->state != TRX_UNDO_CACHED) {
00339
00340
00341 if (undo->id >= TRX_RSEG_N_SLOTS) {
00342 fprintf(stderr,
00343 "InnoDB: Error: undo->id is %lu\n",
00344 (ulong) undo->id);
00345 ut_error;
00346 }
00347
00348 trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, mtr);
00349
00350 hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
00351 MLOG_4BYTES, mtr);
00352 ut_ad(undo->size == flst_get_len(
00353 seg_header + TRX_UNDO_PAGE_LIST, mtr));
00354
00355 mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
00356 hist_size + undo->size, MLOG_4BYTES, mtr);
00357 }
00358
00359
00360 flst_add_first(rseg_header + TRX_RSEG_HISTORY,
00361 undo_header + TRX_UNDO_HISTORY_NODE, mtr);
00362 mutex_enter(&kernel_mutex);
00363 trx_sys->rseg_history_len++;
00364 mutex_exit(&kernel_mutex);
00365
00366 if (!(trx_sys->rseg_history_len % srv_purge_batch_size)) {
00367
00368 srv_wake_purge_thread_if_not_active();
00369 }
00370
00371
00372 mlog_write_ull(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr);
00373
00374
00375 if (!undo->del_marks) {
00376 mlog_write_ulint(undo_header + TRX_UNDO_DEL_MARKS, FALSE,
00377 MLOG_2BYTES, mtr);
00378 }
00379
00380 if (rseg->last_page_no == FIL_NULL) {
00381
00382 rseg->last_page_no = undo->hdr_page_no;
00383 rseg->last_offset = undo->hdr_offset;
00384 rseg->last_trx_no = trx->no;
00385 rseg->last_del_marks = undo->del_marks;
00386 }
00387 }
00388
00389
00392 static
00393 void
00394 trx_purge_free_segment(
00395
00396 trx_rseg_t* rseg,
00397 fil_addr_t hdr_addr,
00398 ulint n_removed_logs)
00401 {
00402 page_t* undo_page;
00403 trx_rsegf_t* rseg_hdr;
00404 trx_ulogf_t* log_hdr;
00405 trx_usegf_t* seg_hdr;
00406 ibool freed;
00407 ulint seg_size;
00408 ulint hist_size;
00409 ibool marked = FALSE;
00410 mtr_t mtr;
00411
00412
00413
00414 ut_ad(mutex_own(&(purge_sys->mutex)));
00415 loop:
00416 mtr_start(&mtr);
00417 mutex_enter(&(rseg->mutex));
00418
00419 rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
00420 rseg->page_no, &mtr);
00421
00422 undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
00423 hdr_addr.page, &mtr);
00424 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
00425 log_hdr = undo_page + hdr_addr.boffset;
00426
00427
00428
00429
00430
00431
00432
00433 if (!marked) {
00434 mlog_write_ulint(log_hdr + TRX_UNDO_DEL_MARKS, FALSE,
00435 MLOG_2BYTES, &mtr);
00436 marked = TRUE;
00437 }
00438
00439 freed = fseg_free_step_not_header(seg_hdr + TRX_UNDO_FSEG_HEADER,
00440 &mtr);
00441 if (!freed) {
00442 mutex_exit(&(rseg->mutex));
00443 mtr_commit(&mtr);
00444
00445 goto loop;
00446 }
00447
00448
00449
00450
00451
00452 seg_size = flst_get_len(seg_hdr + TRX_UNDO_PAGE_LIST, &mtr);
00453
00454
00455
00456
00457
00458
00459 flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY,
00460 log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr);
00461
00462 mutex_enter(&kernel_mutex);
00463 ut_ad(trx_sys->rseg_history_len >= n_removed_logs);
00464 trx_sys->rseg_history_len -= n_removed_logs;
00465 mutex_exit(&kernel_mutex);
00466
00467 freed = FALSE;
00468
00469 while (!freed) {
00470
00471
00472
00473
00474
00475 freed = fseg_free_step(seg_hdr + TRX_UNDO_FSEG_HEADER,
00476 &mtr);
00477 }
00478
00479 hist_size = mtr_read_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
00480 MLOG_4BYTES, &mtr);
00481 ut_ad(hist_size >= seg_size);
00482
00483 mlog_write_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
00484 hist_size - seg_size, MLOG_4BYTES, &mtr);
00485
00486 ut_ad(rseg->curr_size >= seg_size);
00487
00488 rseg->curr_size -= seg_size;
00489
00490 mutex_exit(&(rseg->mutex));
00491
00492 mtr_commit(&mtr);
00493 }
00494
00495
00497 static
00498 void
00499 trx_purge_truncate_rseg_history(
00500
00501 trx_rseg_t* rseg,
00502 trx_id_t limit_trx_no,
00504 undo_no_t limit_undo_no)
00507 {
00508 fil_addr_t hdr_addr;
00509 fil_addr_t prev_hdr_addr;
00510 trx_rsegf_t* rseg_hdr;
00511 page_t* undo_page;
00512 trx_ulogf_t* log_hdr;
00513 trx_usegf_t* seg_hdr;
00514 ulint n_removed_logs = 0;
00515 mtr_t mtr;
00516 trx_id_t undo_trx_no;
00517
00518 ut_ad(mutex_own(&(purge_sys->mutex)));
00519
00520 mtr_start(&mtr);
00521 mutex_enter(&(rseg->mutex));
00522
00523 rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
00524 rseg->page_no, &mtr);
00525
00526 hdr_addr = trx_purge_get_log_from_hist(
00527 flst_get_last(rseg_hdr + TRX_RSEG_HISTORY, &mtr));
00528 loop:
00529 if (hdr_addr.page == FIL_NULL) {
00530
00531 mutex_exit(&(rseg->mutex));
00532
00533 mtr_commit(&mtr);
00534
00535 return;
00536 }
00537
00538 undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
00539 hdr_addr.page, &mtr);
00540
00541 log_hdr = undo_page + hdr_addr.boffset;
00542 undo_trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
00543
00544 if (undo_trx_no >= limit_trx_no) {
00545 if (undo_trx_no == limit_trx_no) {
00546 trx_undo_truncate_start(rseg, rseg->space,
00547 hdr_addr.page,
00548 hdr_addr.boffset,
00549 limit_undo_no);
00550 }
00551
00552 mutex_enter(&kernel_mutex);
00553 ut_a(trx_sys->rseg_history_len >= n_removed_logs);
00554 trx_sys->rseg_history_len -= n_removed_logs;
00555 mutex_exit(&kernel_mutex);
00556
00557 flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY,
00558 log_hdr + TRX_UNDO_HISTORY_NODE,
00559 n_removed_logs, &mtr);
00560
00561 mutex_exit(&(rseg->mutex));
00562 mtr_commit(&mtr);
00563
00564 return;
00565 }
00566
00567 prev_hdr_addr = trx_purge_get_log_from_hist(
00568 flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));
00569 n_removed_logs++;
00570
00571 seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
00572
00573 if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE)
00574 && (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) {
00575
00576
00577
00578 mutex_exit(&(rseg->mutex));
00579 mtr_commit(&mtr);
00580
00581 trx_purge_free_segment(rseg, hdr_addr, n_removed_logs);
00582
00583 n_removed_logs = 0;
00584 } else {
00585 mutex_exit(&(rseg->mutex));
00586 mtr_commit(&mtr);
00587 }
00588
00589 mtr_start(&mtr);
00590 mutex_enter(&(rseg->mutex));
00591
00592 rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
00593 rseg->page_no, &mtr);
00594
00595 hdr_addr = prev_hdr_addr;
00596
00597 goto loop;
00598 }
00599
00600
00603 static
00604 void
00605 trx_purge_truncate_history(void)
00606
00607 {
00608 trx_rseg_t* rseg;
00609 trx_id_t limit_trx_no;
00610 undo_no_t limit_undo_no;
00611
00612 ut_ad(mutex_own(&(purge_sys->mutex)));
00613
00614 trx_purge_arr_get_biggest(purge_sys->arr, &limit_trx_no,
00615 &limit_undo_no);
00616
00617 if (limit_trx_no == 0) {
00618
00619 limit_trx_no = purge_sys->purge_trx_no;
00620 limit_undo_no = purge_sys->purge_undo_no;
00621 }
00622
00623
00624
00625
00626 if (limit_trx_no >= purge_sys->view->low_limit_no) {
00627 limit_trx_no = purge_sys->view->low_limit_no;
00628 limit_undo_no = 0;
00629 }
00630
00631 ut_ad(limit_trx_no <= purge_sys->view->low_limit_no);
00632
00633 rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
00634
00635 while (rseg) {
00636 trx_purge_truncate_rseg_history(rseg, limit_trx_no,
00637 limit_undo_no);
00638 rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
00639 }
00640 }
00641
00642
00646 UNIV_INLINE
00647 ibool
00648 trx_purge_truncate_if_arr_empty(void)
00649
00650 {
00651 ut_ad(mutex_own(&(purge_sys->mutex)));
00652
00653 if (purge_sys->arr->n_used == 0) {
00654
00655 trx_purge_truncate_history();
00656
00657 return(TRUE);
00658 }
00659
00660 return(FALSE);
00661 }
00662
00663
00666 static
00667 void
00668 trx_purge_rseg_get_next_history_log(
00669
00670 trx_rseg_t* rseg)
00671 {
00672 page_t* undo_page;
00673 trx_ulogf_t* log_hdr;
00674 fil_addr_t prev_log_addr;
00675 trx_id_t trx_no;
00676 ibool del_marks;
00677 mtr_t mtr;
00678
00679 ut_ad(mutex_own(&(purge_sys->mutex)));
00680
00681 mutex_enter(&(rseg->mutex));
00682
00683 ut_a(rseg->last_page_no != FIL_NULL);
00684
00685 purge_sys->purge_trx_no = rseg->last_trx_no + 1;
00686 purge_sys->purge_undo_no = 0;
00687 purge_sys->next_stored = FALSE;
00688
00689 mtr_start(&mtr);
00690
00691 undo_page = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
00692 rseg->last_page_no, &mtr);
00693 log_hdr = undo_page + rseg->last_offset;
00694
00695
00696
00697 purge_sys->n_pages_handled++;
00698
00699 prev_log_addr = trx_purge_get_log_from_hist(
00700 flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));
00701 if (prev_log_addr.page == FIL_NULL) {
00702
00703
00704 rseg->last_page_no = FIL_NULL;
00705
00706 mutex_exit(&(rseg->mutex));
00707 mtr_commit(&mtr);
00708
00709 mutex_enter(&kernel_mutex);
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719 if (trx_sys->rseg_history_len > 20000) {
00720 ut_print_timestamp(stderr);
00721 fprintf(stderr,
00722 " InnoDB: Warning: purge reached the"
00723 " head of the history list,\n"
00724 "InnoDB: but its length is still"
00725 " reported as %lu! Make a detailed bug\n"
00726 "InnoDB: report, and submit it"
00727 " to http://bugs.mysql.com\n",
00728 (ulong) trx_sys->rseg_history_len);
00729 }
00730
00731 mutex_exit(&kernel_mutex);
00732
00733 return;
00734 }
00735
00736 mutex_exit(&(rseg->mutex));
00737 mtr_commit(&mtr);
00738
00739
00740 mtr_start(&mtr);
00741
00742 log_hdr = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
00743 prev_log_addr.page, &mtr)
00744 + prev_log_addr.boffset;
00745
00746 trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
00747
00748 del_marks = mach_read_from_2(log_hdr + TRX_UNDO_DEL_MARKS);
00749
00750 mtr_commit(&mtr);
00751
00752 mutex_enter(&(rseg->mutex));
00753
00754 rseg->last_page_no = prev_log_addr.page;
00755 rseg->last_offset = prev_log_addr.boffset;
00756 rseg->last_trx_no = trx_no;
00757 rseg->last_del_marks = del_marks;
00758
00759 mutex_exit(&(rseg->mutex));
00760 }
00761
00762
00767 static
00768 void
00769 trx_purge_choose_next_log(void)
00770
00771 {
00772 trx_undo_rec_t* rec;
00773 trx_rseg_t* rseg;
00774 trx_rseg_t* min_rseg;
00775 trx_id_t min_trx_no;
00776 ulint space = 0;
00777 ulint zip_size = 0;
00778 ulint page_no = 0;
00779 ulint offset = 0;
00780 mtr_t mtr;
00781
00782 ut_ad(mutex_own(&(purge_sys->mutex)));
00783 ut_ad(purge_sys->next_stored == FALSE);
00784
00785 rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
00786
00787 min_trx_no = IB_ULONGLONG_MAX;
00788
00789 min_rseg = NULL;
00790
00791 while (rseg) {
00792 mutex_enter(&(rseg->mutex));
00793
00794 if (rseg->last_page_no != FIL_NULL) {
00795
00796 if (min_rseg == NULL
00797 || min_trx_no > rseg->last_trx_no) {
00798
00799 min_rseg = rseg;
00800 min_trx_no = rseg->last_trx_no;
00801 space = rseg->space;
00802 zip_size = rseg->zip_size;
00803 ut_a(space == 0);
00804
00805
00806 page_no = rseg->last_page_no;
00807 offset = rseg->last_offset;
00808 }
00809 }
00810
00811 mutex_exit(&(rseg->mutex));
00812
00813 rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
00814 }
00815
00816 if (min_rseg == NULL) {
00817
00818 return;
00819 }
00820
00821 mtr_start(&mtr);
00822
00823 if (!min_rseg->last_del_marks) {
00824
00825
00826 rec = &trx_purge_dummy_rec;
00827 } else {
00828 rec = trx_undo_get_first_rec(space, zip_size, page_no, offset,
00829 RW_S_LATCH, &mtr);
00830 if (rec == NULL) {
00831
00832
00833 rec = &trx_purge_dummy_rec;
00834 }
00835 }
00836
00837 purge_sys->next_stored = TRUE;
00838 purge_sys->rseg = min_rseg;
00839
00840 purge_sys->hdr_page_no = page_no;
00841 purge_sys->hdr_offset = offset;
00842
00843 purge_sys->purge_trx_no = min_trx_no;
00844
00845 if (rec == &trx_purge_dummy_rec) {
00846
00847 purge_sys->purge_undo_no = 0;
00848 purge_sys->page_no = page_no;
00849 purge_sys->offset = 0;
00850 } else {
00851 purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec);
00852
00853 purge_sys->page_no = page_get_page_no(page_align(rec));
00854 purge_sys->offset = page_offset(rec);
00855 }
00856
00857 mtr_commit(&mtr);
00858 }
00859
00860
00863 static
00864 trx_undo_rec_t*
00865 trx_purge_get_next_rec(
00866
00867 mem_heap_t* heap)
00868 {
00869 trx_undo_rec_t* rec;
00870 trx_undo_rec_t* rec_copy;
00871 trx_undo_rec_t* rec2;
00872 trx_undo_rec_t* next_rec;
00873 page_t* undo_page;
00874 page_t* page;
00875 ulint offset;
00876 ulint page_no;
00877 ulint space;
00878 ulint zip_size;
00879 ulint type;
00880 ulint cmpl_info;
00881 mtr_t mtr;
00882
00883 ut_ad(mutex_own(&(purge_sys->mutex)));
00884 ut_ad(purge_sys->next_stored);
00885
00886 space = purge_sys->rseg->space;
00887 zip_size = purge_sys->rseg->zip_size;
00888 page_no = purge_sys->page_no;
00889 offset = purge_sys->offset;
00890
00891 if (offset == 0) {
00892
00893
00894
00895 trx_purge_rseg_get_next_history_log(purge_sys->rseg);
00896
00897
00898
00899 trx_purge_choose_next_log();
00900
00901 return(&trx_purge_dummy_rec);
00902 }
00903
00904 mtr_start(&mtr);
00905
00906 undo_page = trx_undo_page_get_s_latched(space, zip_size,
00907 page_no, &mtr);
00908 rec = undo_page + offset;
00909
00910 rec2 = rec;
00911
00912 for (;;) {
00913
00914
00915
00916 next_rec = trx_undo_page_get_next_rec(rec2,
00917 purge_sys->hdr_page_no,
00918 purge_sys->hdr_offset);
00919 if (next_rec == NULL) {
00920 rec2 = trx_undo_get_next_rec(
00921 rec2, purge_sys->hdr_page_no,
00922 purge_sys->hdr_offset, &mtr);
00923 break;
00924 }
00925
00926 rec2 = next_rec;
00927
00928 type = trx_undo_rec_get_type(rec2);
00929
00930 if (type == TRX_UNDO_DEL_MARK_REC) {
00931
00932 break;
00933 }
00934
00935 cmpl_info = trx_undo_rec_get_cmpl_info(rec2);
00936
00937 if (trx_undo_rec_get_extern_storage(rec2)) {
00938 break;
00939 }
00940
00941 if ((type == TRX_UNDO_UPD_EXIST_REC)
00942 && !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
00943 break;
00944 }
00945 }
00946
00947 if (rec2 == NULL) {
00948 mtr_commit(&mtr);
00949
00950 trx_purge_rseg_get_next_history_log(purge_sys->rseg);
00951
00952
00953
00954 trx_purge_choose_next_log();
00955
00956 mtr_start(&mtr);
00957
00958 undo_page = trx_undo_page_get_s_latched(space, zip_size,
00959 page_no, &mtr);
00960
00961 rec = undo_page + offset;
00962 } else {
00963 page = page_align(rec2);
00964
00965 purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec2);
00966 purge_sys->page_no = page_get_page_no(page);
00967 purge_sys->offset = rec2 - page;
00968
00969 if (undo_page != page) {
00970
00971 purge_sys->n_pages_handled++;
00972 }
00973 }
00974
00975 rec_copy = trx_undo_rec_copy(rec, heap);
00976
00977 mtr_commit(&mtr);
00978
00979 return(rec_copy);
00980 }
00981
00982
00987 UNIV_INTERN
00988 trx_undo_rec_t*
00989 trx_purge_fetch_next_rec(
00990
00991 roll_ptr_t* roll_ptr,
00992 trx_undo_inf_t** cell,
00994 mem_heap_t* heap)
00995 {
00996 trx_undo_rec_t* undo_rec;
00997
00998 mutex_enter(&(purge_sys->mutex));
00999
01000 if (purge_sys->state == TRX_STOP_PURGE) {
01001 trx_purge_truncate_if_arr_empty();
01002
01003 mutex_exit(&(purge_sys->mutex));
01004
01005 return(NULL);
01006 }
01007
01008 if (!purge_sys->next_stored) {
01009 trx_purge_choose_next_log();
01010
01011 if (!purge_sys->next_stored) {
01012 purge_sys->state = TRX_STOP_PURGE;
01013
01014 trx_purge_truncate_if_arr_empty();
01015
01016 if (srv_print_thread_releases) {
01017 fprintf(stderr,
01018 "Purge: No logs left in the"
01019 " history list; pages handled %lu\n",
01020 (ulong) purge_sys->n_pages_handled);
01021 }
01022
01023 mutex_exit(&(purge_sys->mutex));
01024
01025 return(NULL);
01026 }
01027 }
01028
01029 if (purge_sys->n_pages_handled >= purge_sys->handle_limit) {
01030
01031 purge_sys->state = TRX_STOP_PURGE;
01032
01033 trx_purge_truncate_if_arr_empty();
01034
01035 mutex_exit(&(purge_sys->mutex));
01036
01037 return(NULL);
01038 }
01039
01040 if (purge_sys->purge_trx_no >= purge_sys->view->low_limit_no) {
01041 purge_sys->state = TRX_STOP_PURGE;
01042
01043 trx_purge_truncate_if_arr_empty();
01044
01045 mutex_exit(&(purge_sys->mutex));
01046
01047 return(NULL);
01048 }
01049
01050
01051
01052
01053
01054
01055 *roll_ptr = trx_undo_build_roll_ptr(FALSE, (purge_sys->rseg)->id,
01056 purge_sys->page_no,
01057 purge_sys->offset);
01058
01059 *cell = trx_purge_arr_store_info(purge_sys->purge_trx_no,
01060 purge_sys->purge_undo_no);
01061
01062 ut_ad(purge_sys->purge_trx_no < purge_sys->view->low_limit_no);
01063
01064
01065
01066
01067 undo_rec = trx_purge_get_next_rec(heap);
01068
01069 mutex_exit(&(purge_sys->mutex));
01070
01071 return(undo_rec);
01072 }
01073
01074
01076 UNIV_INTERN
01077 void
01078 trx_purge_rec_release(
01079
01080 trx_undo_inf_t* cell)
01081 {
01082 mutex_enter(&(purge_sys->mutex));
01083
01084 trx_purge_arr_remove_info(cell);
01085
01086 mutex_exit(&(purge_sys->mutex));
01087 }
01088
01089
01092 UNIV_INTERN
01093 ulint
01094 trx_purge(
01095
01096 ulint limit)
01098 {
01099 que_thr_t* thr;
01100
01101 ulint old_pages_handled;
01102
01103 mutex_enter(&(purge_sys->mutex));
01104
01105 if (purge_sys->trx->n_active_thrs > 0) {
01106
01107 mutex_exit(&(purge_sys->mutex));
01108
01109
01110
01111 ut_error;
01112
01113 return(0);
01114 }
01115
01116 rw_lock_x_lock(&(purge_sys->latch));
01117
01118 mutex_enter(&kernel_mutex);
01119
01120
01121
01122 read_view_close(purge_sys->view);
01123 purge_sys->view = NULL;
01124 mem_heap_empty(purge_sys->heap);
01125
01126
01127
01128
01129 srv_dml_needed_delay = 0;
01130
01131
01132
01133
01134 if (srv_max_purge_lag > 0
01135 && !UT_LIST_GET_LAST(trx_sys->view_list)) {
01136 float ratio = (float) trx_sys->rseg_history_len
01137 / srv_max_purge_lag;
01138 if (ratio > ULINT_MAX / 10000) {
01139
01140 srv_dml_needed_delay = ULINT_MAX;
01141 } else if (ratio > 1) {
01142
01143
01144
01145
01146 srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000);
01147 }
01148 }
01149
01150 purge_sys->view = read_view_oldest_copy_or_open_new(0,
01151 purge_sys->heap);
01152 mutex_exit(&kernel_mutex);
01153
01154 rw_lock_x_unlock(&(purge_sys->latch));
01155
01156 purge_sys->state = TRX_PURGE_ON;
01157
01158 purge_sys->handle_limit = purge_sys->n_pages_handled + limit;
01159
01160 old_pages_handled = purge_sys->n_pages_handled;
01161
01162 mutex_exit(&(purge_sys->mutex));
01163
01164 mutex_enter(&kernel_mutex);
01165
01166 thr = que_fork_start_command(purge_sys->query);
01167
01168 ut_ad(thr);
01169
01170
01171
01172
01173
01174
01175 mutex_exit(&kernel_mutex);
01176
01177
01178
01179 if (srv_print_thread_releases) {
01180
01181 fputs("Starting purge\n", stderr);
01182 }
01183
01184 que_run_threads(thr);
01185
01186 if (srv_print_thread_releases) {
01187
01188 fprintf(stderr,
01189 "Purge ends; pages handled %lu\n",
01190 (ulong) purge_sys->n_pages_handled);
01191 }
01192
01193 return(purge_sys->n_pages_handled - old_pages_handled);
01194 }
01195
01196
01198 UNIV_INTERN
01199 void
01200 trx_purge_sys_print(void)
01201
01202 {
01203 fprintf(stderr, "InnoDB: Purge system view:\n");
01204 read_view_print(purge_sys->view);
01205
01206 fprintf(stderr, "InnoDB: Purge trx n:o " TRX_ID_FMT
01207 ", undo n:o " TRX_ID_FMT "\n",
01208 purge_sys->purge_trx_no,
01209 purge_sys->purge_undo_no);
01210 fprintf(stderr,
01211 "InnoDB: Purge next stored %lu, page_no %lu, offset %lu,\n"
01212 "InnoDB: Purge hdr_page_no %lu, hdr_offset %lu\n",
01213 (ulong) purge_sys->next_stored,
01214 (ulong) purge_sys->page_no,
01215 (ulong) purge_sys->offset,
01216 (ulong) purge_sys->hdr_page_no,
01217 (ulong) purge_sys->hdr_offset);
01218 }