trx0purge.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:25k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Purge old versions
  3. (c) 1996 Innobase Oy
  4. Created 3/26/1996 Heikki Tuuri
  5. *******************************************************/
  6. #include "trx0purge.h"
  7. #ifdef UNIV_NONINL
  8. #include "trx0purge.ic"
  9. #endif
  10. #include "fsp0fsp.h"
  11. #include "mach0data.h"
  12. #include "trx0rseg.h"
  13. #include "trx0trx.h"
  14. #include "trx0roll.h"
  15. #include "read0read.h"
  16. #include "fut0fut.h"
  17. #include "que0que.h"
  18. #include "row0purge.h"
  19. #include "row0upd.h"
  20. #include "trx0rec.h"
  21. #include "srv0que.h"
  22. #include "os0thread.h"
  23. /* The global data structure coordinating a purge */
  24. trx_purge_t* purge_sys = NULL;
  25. /* A dummy undo record used as a return value when we have a whole undo log
  26. which needs no purge */
  27. trx_undo_rec_t trx_purge_dummy_rec;
  28. /*********************************************************************
  29. Checks if trx_id is >= purge_view: then it is guaranteed that its update
  30. undo log still exists in the system. */
  31. ibool
  32. trx_purge_update_undo_must_exist(
  33. /*=============================*/
  34. /* out: TRUE if is sure that it is preserved, also
  35. if the function returns FALSE, it is possible that
  36. the undo log still exists in the system */
  37. dulint trx_id) /* in: transaction id */
  38. {
  39. ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
  40. if (!read_view_sees_trx_id(purge_sys->view, trx_id)) {
  41. return(TRUE);
  42. }
  43. return(FALSE);
  44. }
  45. /*=================== PURGE RECORD ARRAY =============================*/
  46. /***********************************************************************
  47. Stores info of an undo log record during a purge. */
  48. static
  49. trx_undo_inf_t*
  50. trx_purge_arr_store_info(
  51. /*=====================*/
  52. /* out: pointer to the storage cell */
  53. dulint trx_no, /* in: transaction number */
  54. dulint undo_no)/* in: undo number */
  55. {
  56. trx_undo_inf_t* cell;
  57. trx_undo_arr_t* arr;
  58. ulint i;
  59. arr = purge_sys->arr;
  60. for (i = 0;; i++) {
  61. cell = trx_undo_arr_get_nth_info(arr, i);
  62. if (!(cell->in_use)) {
  63. /* Not in use, we may store here */
  64. cell->undo_no = undo_no;
  65. cell->trx_no = trx_no;
  66. cell->in_use = TRUE;
  67. arr->n_used++;
  68. return(cell);
  69. }
  70. }
  71. }
  72. /***********************************************************************
  73. Removes info of an undo log record during a purge. */
  74. UNIV_INLINE
  75. void
  76. trx_purge_arr_remove_info(
  77. /*======================*/
  78. trx_undo_inf_t* cell) /* in: pointer to the storage cell */
  79. {
  80. trx_undo_arr_t* arr;
  81. arr = purge_sys->arr;
  82. cell->in_use = FALSE;
  83. ut_ad(arr->n_used > 0);
  84. arr->n_used--;
  85. }
  86. /***********************************************************************
  87. Gets the biggest pair of a trx number and an undo number in a purge array. */
  88. static
  89. void
  90. trx_purge_arr_get_biggest(
  91. /*======================*/
  92. trx_undo_arr_t* arr, /* in: purge array */
  93. dulint* trx_no, /* out: transaction number: ut_dulint_zero
  94. if array is empty */
  95. dulint* undo_no)/* out: undo number */
  96. {
  97. trx_undo_inf_t* cell;
  98. dulint pair_trx_no;
  99. dulint pair_undo_no;
  100. int trx_cmp;
  101. ulint n_used;
  102. ulint i;
  103. ulint n;
  104. n = 0;
  105. n_used = arr->n_used;
  106. pair_trx_no = ut_dulint_zero;
  107. pair_undo_no = ut_dulint_zero;
  108. for (i = 0;; i++) {
  109. cell = trx_undo_arr_get_nth_info(arr, i);
  110. if (cell->in_use) {
  111. n++;
  112.   trx_cmp = ut_dulint_cmp(cell->trx_no, pair_trx_no);
  113. if ((trx_cmp > 0)
  114.     || ((trx_cmp == 0)
  115.         && (ut_dulint_cmp(cell->undo_no,
  116. pair_undo_no) >= 0))) {
  117. pair_trx_no = cell->trx_no;
  118. pair_undo_no = cell->undo_no;
  119. }
  120. }
  121. if (n == n_used) {
  122. *trx_no = pair_trx_no;
  123. *undo_no = pair_undo_no;
  124. return;
  125. }
  126. }
  127. }
  128. /********************************************************************
  129. Builds a purge 'query' graph. The actual purge is performed by executing
  130. this query graph. */
  131. static
  132. que_t*
  133. trx_purge_graph_build(void)
  134. /*=======================*/
  135. /* out, own: the query graph */
  136. {
  137. mem_heap_t* heap;
  138. que_fork_t* fork;
  139. que_thr_t* thr;
  140. /* que_thr_t* thr2; */
  141. heap = mem_heap_create(512);
  142. fork = que_fork_create(NULL, NULL, QUE_FORK_PURGE, heap);
  143. fork->trx = purge_sys->trx;
  144. thr = que_thr_create(fork, heap);
  145. thr->child = row_purge_node_create(thr, heap);  
  146. /* thr2 = que_thr_create(fork, fork, heap);
  147. thr2->child = row_purge_node_create(fork, thr2, heap);   */
  148. return(fork);
  149. }
  150. /************************************************************************
  151. Creates the global purge system control structure and inits the history
  152. mutex. */
  153. void
  154. trx_purge_sys_create(void)
  155. /*======================*/
  156. {
  157. com_endpoint_t* com_endpoint;
  158. ut_ad(mutex_own(&kernel_mutex));
  159. purge_sys = mem_alloc(sizeof(trx_purge_t));
  160. purge_sys->state = TRX_STOP_PURGE;
  161. purge_sys->n_pages_handled = 0;
  162. purge_sys->purge_trx_no = ut_dulint_zero;
  163. purge_sys->purge_undo_no = ut_dulint_zero;
  164. purge_sys->next_stored = FALSE;
  165. rw_lock_create(&(purge_sys->purge_is_running));
  166. rw_lock_set_level(&(purge_sys->purge_is_running),
  167. SYNC_PURGE_IS_RUNNING);
  168. rw_lock_create(&(purge_sys->latch));
  169. rw_lock_set_level(&(purge_sys->latch), SYNC_PURGE_LATCH);
  170. mutex_create(&(purge_sys->mutex));
  171. mutex_set_level(&(purge_sys->mutex), SYNC_PURGE_SYS);
  172. purge_sys->heap = mem_heap_create(256);
  173. purge_sys->arr = trx_undo_arr_create();
  174. com_endpoint = (com_endpoint_t*)purge_sys; /* This is a dummy non-NULL
  175.    value */
  176. purge_sys->sess = sess_open(com_endpoint, (byte*)"purge_system", 13);
  177. purge_sys->trx = (purge_sys->sess)->trx;
  178. (purge_sys->trx)->type = TRX_PURGE;
  179. ut_a(trx_start_low(purge_sys->trx, ULINT_UNDEFINED));
  180. purge_sys->query = trx_purge_graph_build();
  181. purge_sys->view = read_view_oldest_copy_or_open_new(NULL,
  182. purge_sys->heap);
  183. }
  184. /*================ UNDO LOG HISTORY LIST =============================*/
  185. /************************************************************************
  186. Adds the update undo log as the first log in the history list. Removes the
  187. update undo log segment from the rseg slot if it is too big for reuse. */
  188. void
  189. trx_purge_add_update_undo_to_history(
  190. /*=================================*/
  191. trx_t* trx, /* in: transaction */
  192. page_t* undo_page, /* in: update undo log header page,
  193. x-latched */
  194. mtr_t* mtr) /* in: mtr */
  195. {
  196. trx_undo_t* undo;
  197. trx_rseg_t* rseg;
  198. trx_rsegf_t* rseg_header;
  199. trx_usegf_t* seg_header;
  200. trx_ulogf_t* undo_header;
  201. trx_upagef_t* page_header;
  202. ulint hist_size;
  203. undo = trx->update_undo;
  204. ut_ad(undo);
  205. rseg = undo->rseg;
  206. ut_ad(mutex_own(&(rseg->mutex)));
  207. rseg_header = trx_rsegf_get(rseg->space, rseg->page_no, mtr);
  208. undo_header = undo_page + undo->hdr_offset;
  209. seg_header  = undo_page + TRX_UNDO_SEG_HDR;
  210. page_header = undo_page + TRX_UNDO_PAGE_HDR;
  211. if (undo->state != TRX_UNDO_CACHED) {
  212. /* The undo log segment will not be reused */
  213. trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, mtr);
  214. hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
  215. MLOG_4BYTES, mtr);
  216. ut_ad(undo->size ==
  217. flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr));
  218. mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
  219. hist_size + undo->size, MLOG_4BYTES, mtr);
  220. }
  221. /* Add the log as the first in the history list */
  222. flst_add_first(rseg_header + TRX_RSEG_HISTORY,
  223. undo_header + TRX_UNDO_HISTORY_NODE, mtr);
  224. /* Write the trx number to the undo log header */
  225. mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, MLOG_8BYTES,
  226. mtr);
  227. /* Write information about delete markings to the undo log header */
  228. if (!undo->del_marks) {
  229. mlog_write_ulint(undo_header + TRX_UNDO_DEL_MARKS, FALSE,
  230. MLOG_2BYTES, mtr);
  231. }
  232. if (rseg->last_page_no == FIL_NULL) {
  233. rseg->last_page_no = undo->hdr_page_no;
  234. rseg->last_offset = undo->hdr_offset;
  235. rseg->last_trx_no = trx->no;
  236. rseg->last_del_marks = undo->del_marks;
  237. }
  238. }
  239. /**************************************************************************
  240. Frees an undo log segment which is in the history list. Cuts the end of the
  241. history list at the youngest undo log in this segment. */
  242. static
  243. void
  244. trx_purge_free_segment(
  245. /*===================*/
  246. trx_rseg_t* rseg, /* in: rollback segment */
  247. fil_addr_t hdr_addr, /* in: the file address of log_hdr */
  248. ulint n_removed_logs) /* in: count of how many undo logs we
  249. will cut off from the end of the
  250. history list */
  251. {
  252. page_t* undo_page;
  253. trx_rsegf_t* rseg_hdr;
  254. trx_ulogf_t* log_hdr;
  255. trx_usegf_t* seg_hdr;
  256. ibool freed;
  257. ulint seg_size;
  258. ulint hist_size;
  259. ibool marked = FALSE;
  260. mtr_t mtr;
  261. /* printf("Freeing an update undo log segmentn"); */
  262. ut_ad(mutex_own(&(purge_sys->mutex)));
  263. loop:
  264. mtr_start(&mtr);
  265. mutex_enter(&(rseg->mutex));
  266. rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr);
  267. undo_page = trx_undo_page_get(rseg->space, hdr_addr.page, &mtr);
  268. seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
  269. log_hdr = undo_page + hdr_addr.boffset;
  270. /* Mark the last undo log totally purged, so that if the system
  271. crashes, the tail of the undo log will not get accessed again. The
  272. list of pages in the undo log tail gets inconsistent during the
  273. freeing of the segment, and therefore purge should not try to access
  274. them again. */
  275. if (!marked) {
  276. mlog_write_ulint(log_hdr + TRX_UNDO_DEL_MARKS, FALSE,
  277. MLOG_2BYTES, &mtr);
  278. marked = TRUE;
  279. }
  280. freed = fseg_free_step_not_header(seg_hdr + TRX_UNDO_FSEG_HEADER,
  281. &mtr);
  282. if (!freed) {
  283. mutex_exit(&(rseg->mutex));
  284. mtr_commit(&mtr);
  285. goto loop;
  286. }
  287. /* The page list may now be inconsistent, but the length field
  288. stored in the list base node tells us how big it was before we
  289. started the freeing. */
  290. seg_size = flst_get_len(seg_hdr + TRX_UNDO_PAGE_LIST, &mtr);
  291. /* We may free the undo log segment header page; it must be freed
  292. within the same mtr as the undo log header is removed from the
  293. history list: otherwise, in case of a database crash, the segment
  294. could become inaccessible garbage in the file space. */
  295. flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY,
  296. log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr);
  297. freed = FALSE;
  298. while (!freed) {
  299. /* Here we assume that a file segment with just the header
  300. page can be freed in a few steps, so that the buffer pool
  301. is not flooded with bufferfixed pages: see the note in
  302. fsp0fsp.c. */
  303. freed = fseg_free_step(seg_hdr + TRX_UNDO_FSEG_HEADER,
  304. &mtr);
  305. }
  306. hist_size = mtr_read_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
  307. MLOG_4BYTES, &mtr);
  308. ut_ad(hist_size >= seg_size);
  309. mlog_write_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
  310. hist_size - seg_size, MLOG_4BYTES, &mtr);
  311. ut_ad(rseg->curr_size >= seg_size);
  312. rseg->curr_size -= seg_size;
  313. mutex_exit(&(rseg->mutex));
  314. mtr_commit(&mtr);
  315. }
  316. /************************************************************************
  317. Removes unnecessary history data from a rollback segment. */
  318. static
  319. void
  320. trx_purge_truncate_rseg_history(
  321. /*============================*/
  322. trx_rseg_t* rseg, /* in: rollback segment */
  323. dulint limit_trx_no, /* in: remove update undo logs whose
  324. trx number is < limit_trx_no */
  325. dulint limit_undo_no) /* in: if transaction number is equal
  326. to limit_trx_no, truncate undo records
  327. with undo number < limit_undo_no */
  328. {
  329. fil_addr_t hdr_addr;
  330. fil_addr_t prev_hdr_addr;
  331. trx_rsegf_t* rseg_hdr;
  332. page_t* undo_page;
  333. trx_ulogf_t* log_hdr;
  334. trx_usegf_t* seg_hdr;
  335. int cmp;
  336. ulint n_removed_logs = 0;
  337. mtr_t mtr;
  338. ut_ad(mutex_own(&(purge_sys->mutex)));
  339. mtr_start(&mtr);
  340. mutex_enter(&(rseg->mutex));
  341. rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr);
  342. hdr_addr = trx_purge_get_log_from_hist(
  343. flst_get_last(rseg_hdr + TRX_RSEG_HISTORY, &mtr));
  344. loop:
  345. if (hdr_addr.page == FIL_NULL) {
  346. mutex_exit(&(rseg->mutex));
  347. mtr_commit(&mtr);
  348. return;
  349. }
  350. undo_page = trx_undo_page_get(rseg->space, hdr_addr.page, &mtr);
  351. log_hdr = undo_page + hdr_addr.boffset;
  352.   cmp = ut_dulint_cmp(mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO),
  353.      limit_trx_no);
  354. if (cmp == 0) {
  355. trx_undo_truncate_start(rseg, rseg->space, hdr_addr.page,
  356. hdr_addr.boffset, limit_undo_no);
  357. }
  358. if (cmp >= 0) {
  359. flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY,
  360.      log_hdr + TRX_UNDO_HISTORY_NODE,
  361. n_removed_logs, &mtr);
  362. mutex_exit(&(rseg->mutex));
  363. mtr_commit(&mtr);
  364. return;
  365. }
  366. prev_hdr_addr = trx_purge_get_log_from_hist(
  367.   flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE,
  368. &mtr));
  369. n_removed_logs++;
  370. seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
  371. if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE)
  372.      && (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) {
  373. /* We can free the whole log segment */
  374. mutex_exit(&(rseg->mutex));
  375. mtr_commit(&mtr);
  376. trx_purge_free_segment(rseg, hdr_addr, n_removed_logs);
  377. n_removed_logs = 0;
  378. } else {
  379. mutex_exit(&(rseg->mutex));
  380. mtr_commit(&mtr);
  381. }
  382. mtr_start(&mtr);
  383. mutex_enter(&(rseg->mutex));
  384. rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr);
  385. hdr_addr = prev_hdr_addr;
  386. goto loop;
  387. }
  388. /************************************************************************
  389. Removes unnecessary history data from rollback segments. NOTE that when this
  390. function is called, the caller must not have any latches on undo log pages! */
  391. static
  392. void
  393. trx_purge_truncate_history(void)
  394. /*============================*/
  395. {
  396. trx_rseg_t* rseg;
  397. dulint limit_trx_no;
  398. dulint limit_undo_no;
  399. ut_ad(mutex_own(&(purge_sys->mutex)));
  400. trx_purge_arr_get_biggest(purge_sys->arr, &limit_trx_no,
  401. &limit_undo_no);
  402. if (ut_dulint_cmp(limit_trx_no, ut_dulint_zero) == 0) {
  403. limit_trx_no = purge_sys->purge_trx_no;
  404. limit_undo_no = purge_sys->purge_undo_no;
  405. }
  406. /* We play safe and set the truncate limit at most to the purge view
  407. low_limit number, though this is not necessary */
  408. if (ut_dulint_cmp(limit_trx_no, (purge_sys->view)->low_limit_no) >= 0) {
  409. limit_trx_no = (purge_sys->view)->low_limit_no;
  410. limit_undo_no = ut_dulint_zero;
  411. }
  412. ut_ad((ut_dulint_cmp(limit_trx_no,
  413. (purge_sys->view)->low_limit_no) <= 0));
  414. rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
  415. while (rseg) {
  416. trx_purge_truncate_rseg_history(rseg, limit_trx_no,
  417. limit_undo_no);
  418. rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
  419. }
  420. }
  421. /************************************************************************
  422. Does a truncate if the purge array is empty. NOTE that when this function is
  423. called, the caller must not have any latches on undo log pages! */
  424. UNIV_INLINE
  425. ibool
  426. trx_purge_truncate_if_arr_empty(void)
  427. /*=================================*/
  428. /* out: TRUE if array empty */
  429. {
  430. ut_ad(mutex_own(&(purge_sys->mutex)));
  431. if ((purge_sys->arr)->n_used == 0) {
  432. trx_purge_truncate_history();
  433. return(TRUE);
  434. }
  435. return(FALSE);
  436. }
  437. /***************************************************************************
  438. Updates the last not yet purged history log info in rseg when we have purged
  439. a whole undo log. Advances also purge_sys->purge_trx_no past the purged log. */
  440. static 
  441. void
  442. trx_purge_rseg_get_next_history_log(
  443. /*================================*/
  444. trx_rseg_t* rseg) /* in: rollback segment */
  445. {
  446. page_t*  undo_page;
  447. trx_ulogf_t* log_hdr;
  448. trx_usegf_t* seg_hdr;
  449. fil_addr_t prev_log_addr;
  450. dulint trx_no;
  451. ibool del_marks;
  452. mtr_t mtr;
  453. ut_ad(mutex_own(&(purge_sys->mutex)));
  454. mutex_enter(&(rseg->mutex));
  455. ut_ad(rseg->last_page_no != FIL_NULL);
  456. purge_sys->purge_trx_no = ut_dulint_add(rseg->last_trx_no, 1);
  457. purge_sys->purge_undo_no = ut_dulint_zero;
  458. purge_sys->next_stored = FALSE;
  459. mtr_start(&mtr);
  460. undo_page = trx_undo_page_get_s_latched(rseg->space,
  461. rseg->last_page_no, &mtr);
  462. log_hdr = undo_page + rseg->last_offset;
  463. seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
  464. if ((mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)
  465.     && (mach_read_from_2(seg_hdr + TRX_UNDO_STATE)
  466. == TRX_UNDO_TO_PURGE)) {
  467. /* This is the last log header on this page and the log
  468. segment cannot be reused: we may increment the number of
  469. pages handled */
  470. purge_sys->n_pages_handled++;
  471. }
  472. prev_log_addr = trx_purge_get_log_from_hist(
  473.  flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE,
  474. &mtr));
  475. if (prev_log_addr.page == FIL_NULL) {
  476. /* No logs left in the history list */
  477. rseg->last_page_no = FIL_NULL;
  478. mutex_exit(&(rseg->mutex));
  479. mtr_commit(&mtr);
  480. return;
  481. }
  482. mutex_exit(&(rseg->mutex));
  483. mtr_commit(&mtr);
  484. /* Read the trx number and del marks from the previous log header */
  485. mtr_start(&mtr);
  486. log_hdr = trx_undo_page_get_s_latched(rseg->space,
  487. prev_log_addr.page, &mtr)
  488.   + prev_log_addr.boffset;
  489. trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
  490. del_marks = mach_read_from_2(log_hdr + TRX_UNDO_DEL_MARKS);
  491. mtr_commit(&mtr);
  492. mutex_enter(&(rseg->mutex));
  493. rseg->last_page_no = prev_log_addr.page;
  494. rseg->last_offset = prev_log_addr.boffset;
  495. rseg->last_trx_no = trx_no;
  496. rseg->last_del_marks = del_marks;
  497. mutex_exit(&(rseg->mutex));
  498. }
  499. /***************************************************************************
  500. Chooses the next undo log to purge and updates the info in purge_sys. This
  501. function is used to initialize purge_sys when the next record to purge is
  502. not known, and also to update the purge system info on the next record when
  503. purge has handled the whole undo log for a transaction. */
  504. static 
  505. void
  506. trx_purge_choose_next_log(void)
  507. /*===========================*/
  508. {
  509. trx_undo_rec_t* rec;
  510. trx_rseg_t* rseg;
  511. trx_rseg_t* min_rseg;
  512. dulint min_trx_no;
  513. ulint space;
  514. ulint page_no;
  515. ulint offset;
  516. mtr_t mtr;
  517. ut_ad(mutex_own(&(purge_sys->mutex)));
  518. ut_ad(purge_sys->next_stored == FALSE);
  519. rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
  520. min_rseg = NULL;
  521. while (rseg) {
  522. mutex_enter(&(rseg->mutex));
  523. if (rseg->last_page_no != FIL_NULL) {
  524. if ((min_rseg == NULL)
  525.     || (ut_dulint_cmp(min_trx_no, rseg->last_trx_no)
  526.      > 0)) {
  527. min_rseg = rseg;
  528. min_trx_no = rseg->last_trx_no;
  529. space = rseg->space;
  530. page_no = rseg->last_page_no;
  531. offset = rseg->last_offset;
  532. }
  533. }
  534. mutex_exit(&(rseg->mutex));
  535. rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
  536. }
  537. if (min_rseg == NULL) {
  538. return;
  539. }
  540. mtr_start(&mtr);
  541. if (!min_rseg->last_del_marks) {
  542. /* No need to purge this log */
  543. rec = &trx_purge_dummy_rec;
  544. } else {
  545. rec = trx_undo_get_first_rec(space, page_no, offset,
  546. RW_S_LATCH, &mtr);
  547. if (rec == NULL) {
  548. /* Undo log empty */
  549. rec = &trx_purge_dummy_rec;
  550. }
  551. }
  552. purge_sys->next_stored = TRUE;
  553. purge_sys->rseg = min_rseg;
  554. purge_sys->hdr_page_no = page_no;
  555. purge_sys->hdr_offset = offset;
  556. purge_sys->purge_trx_no = min_trx_no;
  557. if (rec == &trx_purge_dummy_rec) {
  558. purge_sys->purge_undo_no = ut_dulint_zero;
  559. purge_sys->page_no = page_no;
  560. purge_sys->offset = 0;
  561. } else {
  562. purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec);
  563. purge_sys->page_no = buf_frame_get_page_no(rec);
  564. purge_sys->offset = rec - buf_frame_align(rec);
  565. }
  566. mtr_commit(&mtr);
  567. }
  568. /***************************************************************************
  569. Gets the next record to purge and updates the info in the purge system. */
  570. static
  571. trx_undo_rec_t*
  572. trx_purge_get_next_rec(
  573. /*===================*/
  574. /* out: copy of an undo log record or
  575. pointer to the dummy undo log record */
  576. mem_heap_t* heap) /* in: memory heap where copied */
  577. {
  578. trx_undo_rec_t* rec;
  579. trx_undo_rec_t* rec_copy;
  580. trx_undo_rec_t* rec2;
  581. trx_undo_rec_t* next_rec;
  582. page_t*  undo_page;
  583. page_t*  page;
  584. ulint offset;
  585. ulint page_no;
  586. ulint space;
  587. ulint type;
  588. ulint cmpl_info;
  589. mtr_t mtr;
  590. ut_ad(mutex_own(&(purge_sys->mutex)));
  591. ut_ad(purge_sys->next_stored);
  592. space = (purge_sys->rseg)->space;
  593. page_no = purge_sys->page_no;
  594. offset = purge_sys->offset;
  595. if (offset == 0) {
  596. /* It is the dummy undo log record, which means that there is
  597. no need to purge this undo log */
  598. trx_purge_rseg_get_next_history_log(purge_sys->rseg);
  599. /* Look for the next undo log and record to purge */
  600. trx_purge_choose_next_log();
  601. return(&trx_purge_dummy_rec);
  602. }
  603. mtr_start(&mtr);
  604. undo_page = trx_undo_page_get_s_latched(space, page_no, &mtr);
  605. rec = undo_page + offset;
  606. rec2 = rec;
  607. for (;;) {
  608. /* Try first to find the next record which requires a purge
  609. operation from the same page of the same undo log */
  610. next_rec = trx_undo_page_get_next_rec(rec2,
  611. purge_sys->hdr_page_no,
  612. purge_sys->hdr_offset);
  613. if (next_rec == NULL) {
  614. rec2 = trx_undo_get_next_rec(rec2,
  615. purge_sys->hdr_page_no,
  616. purge_sys->hdr_offset, &mtr);
  617. break;
  618. }
  619. rec2 = next_rec;
  620. type = trx_undo_rec_get_type(rec2);
  621. if (type == TRX_UNDO_DEL_MARK_REC) {
  622. break;
  623. }     
  624. cmpl_info = trx_undo_rec_get_cmpl_info(rec2);
  625. if ((type == TRX_UNDO_UPD_EXIST_REC)
  626. && !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
  627.           break;
  628.     }
  629. }
  630. if (rec2 == NULL) {
  631. mtr_commit(&mtr);
  632. trx_purge_rseg_get_next_history_log(purge_sys->rseg);
  633. /* Look for the next undo log and record to purge */
  634. trx_purge_choose_next_log();
  635. mtr_start(&mtr);
  636. undo_page = trx_undo_page_get_s_latched(space, page_no, &mtr);
  637. rec = undo_page + offset;
  638. } else {
  639. page = buf_frame_align(rec2);
  640. purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec2);
  641. purge_sys->page_no = buf_frame_get_page_no(page);
  642. purge_sys->offset = rec2 - page;
  643. if (undo_page != page) {
  644. /* We advance to a new page of the undo log: */
  645. purge_sys->n_pages_handled++;
  646. }
  647. }
  648. rec_copy = trx_undo_rec_copy(rec, heap);
  649. mtr_commit(&mtr);
  650. return(rec_copy);
  651. }
  652. /************************************************************************
  653. Fetches the next undo log record from the history list to purge. It must be
  654. released with the corresponding release function. */
  655. trx_undo_rec_t*
  656. trx_purge_fetch_next_rec(
  657. /*=====================*/
  658. /* out: copy of an undo log record or
  659. pointer to the dummy undo log record
  660. &trx_purge_dummy_rec, if the whole undo log
  661. can skipped in purge; NULL if none left */
  662. dulint* roll_ptr,/* out: roll pointer to undo record */
  663. trx_undo_inf_t** cell, /* out: storage cell for the record in the
  664. purge array */
  665. mem_heap_t* heap) /* in: memory heap where copied */
  666. {
  667. trx_undo_rec_t* undo_rec;
  668. mutex_enter(&(purge_sys->mutex));
  669. if (purge_sys->state == TRX_STOP_PURGE) {
  670. trx_purge_truncate_if_arr_empty();
  671. mutex_exit(&(purge_sys->mutex));
  672. return(NULL);
  673. }
  674. if (!purge_sys->next_stored) {
  675. trx_purge_choose_next_log();
  676. if (!purge_sys->next_stored) {
  677. purge_sys->state = TRX_STOP_PURGE;
  678. trx_purge_truncate_if_arr_empty();
  679. if (srv_print_thread_releases) {
  680. printf(
  681. "Purge: No logs left in the history list; pages handled %lun",
  682. purge_sys->n_pages_handled);
  683. }
  684. mutex_exit(&(purge_sys->mutex));
  685. return(NULL);
  686. }
  687. }
  688. if (purge_sys->n_pages_handled >= purge_sys->handle_limit) {
  689. purge_sys->state = TRX_STOP_PURGE;
  690. trx_purge_truncate_if_arr_empty();
  691. mutex_exit(&(purge_sys->mutex));
  692. return(NULL);
  693. }
  694. if (ut_dulint_cmp(purge_sys->purge_trx_no,
  695. (purge_sys->view)->low_limit_no) >= 0) {
  696. purge_sys->state = TRX_STOP_PURGE;
  697. trx_purge_truncate_if_arr_empty();
  698. mutex_exit(&(purge_sys->mutex));
  699. return(NULL);
  700. }
  701. /* printf("Thread %lu purging trx %lu undo record %lun",
  702. os_thread_get_curr_id(),
  703. ut_dulint_get_low(purge_sys->purge_trx_no),
  704. ut_dulint_get_low(purge_sys->purge_undo_no)); */
  705. *roll_ptr = trx_undo_build_roll_ptr(FALSE, (purge_sys->rseg)->id,
  706. purge_sys->page_no,
  707. purge_sys->offset);
  708. *cell = trx_purge_arr_store_info(purge_sys->purge_trx_no,
  709.  purge_sys->purge_undo_no);
  710. ut_ad(ut_dulint_cmp(purge_sys->purge_trx_no,
  711.     (purge_sys->view)->low_limit_no) < 0);
  712. /* The following call will advance the stored values of purge_trx_no
  713. and purge_undo_no, therefore we had to store them first */
  714. undo_rec = trx_purge_get_next_rec(heap);
  715. mutex_exit(&(purge_sys->mutex));
  716. return(undo_rec);
  717. }
  718. /***********************************************************************
  719. Releases a reserved purge undo record. */
  720. void
  721. trx_purge_rec_release(
  722. /*==================*/
  723. trx_undo_inf_t* cell) /* in: storage cell */
  724. {
  725. trx_undo_arr_t* arr;
  726. mutex_enter(&(purge_sys->mutex));
  727. arr = purge_sys->arr;
  728. trx_purge_arr_remove_info(cell);
  729. mutex_exit(&(purge_sys->mutex));
  730. }
  731. /***********************************************************************
  732. This function runs a purge batch. */
  733. ulint
  734. trx_purge(void)
  735. /*===========*/
  736. /* out: number of undo log pages handled in
  737. the batch */
  738. {
  739. que_thr_t* thr;
  740. /* que_thr_t* thr2; */
  741. ulint old_pages_handled;
  742. mutex_enter(&(purge_sys->mutex));
  743. if (purge_sys->trx->n_active_thrs > 0) {
  744. mutex_exit(&(purge_sys->mutex));
  745. /* Should not happen */
  746. ut_a(0);
  747. return(0);
  748. }
  749. rw_lock_x_lock(&(purge_sys->latch));
  750. mutex_enter(&kernel_mutex);
  751. /* Close and free the old purge view */
  752. read_view_close(purge_sys->view);
  753. purge_sys->view = NULL;
  754. mem_heap_empty(purge_sys->heap);
  755. purge_sys->view = read_view_oldest_copy_or_open_new(NULL,
  756. purge_sys->heap);
  757. mutex_exit(&kernel_mutex);
  758. rw_lock_x_unlock(&(purge_sys->latch));
  759. purge_sys->state = TRX_PURGE_ON;
  760. /* Handle at most 20 undo log pages in one purge batch */
  761. purge_sys->handle_limit = purge_sys->n_pages_handled + 20;
  762. old_pages_handled = purge_sys->n_pages_handled;
  763. mutex_exit(&(purge_sys->mutex));
  764. mutex_enter(&kernel_mutex);
  765. thr = que_fork_start_command(purge_sys->query, SESS_COMM_EXECUTE, 0);
  766. ut_ad(thr);
  767. /* thr2 = que_fork_start_command(purge_sys->query, SESS_COMM_EXECUTE, 0);
  768. ut_ad(thr2); */
  769. mutex_exit(&kernel_mutex);
  770. /* srv_que_task_enqueue(thr2); */
  771. if (srv_print_thread_releases) {
  772. printf("Starting purgen");
  773. }
  774. que_run_threads(thr);
  775. if (srv_print_thread_releases) {
  776. printf(
  777. "Purge ends; pages handled %lun", purge_sys->n_pages_handled);
  778. }
  779. return(purge_sys->n_pages_handled - old_pages_handled);
  780. }