btr0pcur.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:15k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The index tree persistent cursor
  3. (c) 1996 Innobase Oy
  4. Created 2/23/1996 Heikki Tuuri
  5. *******************************************************/
  6. #include "btr0pcur.h"
  7. #ifdef UNIV_NONINL
  8. #include "btr0pcur.ic"
  9. #endif
  10. #include "ut0byte.h"
  11. #include "rem0cmp.h"
  12. #include "trx0trx.h"
  13. /******************************************************************
  14. Allocates memory for a persistent cursor object and initializes the cursor. */
  15. btr_pcur_t*
  16. btr_pcur_create_for_mysql(void)
  17. /*============================*/
  18. /* out, own: persistent cursor */
  19. {
  20. btr_pcur_t* pcur;
  21. pcur = mem_alloc(sizeof(btr_pcur_t));
  22. pcur->btr_cur.index = NULL;
  23. btr_pcur_init(pcur);
  24. return(pcur);
  25. }
  26. /******************************************************************
  27. Frees the memory for a persistent cursor object. */
  28. void
  29. btr_pcur_free_for_mysql(
  30. /*====================*/
  31. btr_pcur_t* cursor) /* in, own: persistent cursor */
  32. {
  33. if (cursor->old_rec_buf != NULL) {
  34. mem_free(cursor->old_rec_buf);
  35. cursor->old_rec = NULL;
  36. cursor->old_rec_buf = NULL;
  37. }
  38. cursor->btr_cur.page_cur.rec = NULL;
  39. cursor->old_rec = NULL;
  40. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  41. cursor->latch_mode = BTR_NO_LATCHES;
  42. cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
  43. mem_free(cursor);
  44. }
  45. /******************************************************************
  46. The position of the cursor is stored by taking an initial segment of the
  47. record the cursor is positioned on, before, or after, and copying it to the
  48. cursor data structure, or just setting a flag if the cursor id before the
  49. first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
  50. page where the cursor is positioned must not be empty if the index tree is
  51. not totally empty! */
  52. void
  53. btr_pcur_store_position(
  54. /*====================*/
  55. btr_pcur_t* cursor, /* in: persistent cursor */
  56. mtr_t* mtr) /* in: mtr */
  57. {
  58. page_cur_t* page_cursor;
  59. rec_t* rec;
  60. dict_tree_t* tree;
  61. page_t* page;
  62. ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  63. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  64. tree = btr_cur_get_tree(btr_pcur_get_btr_cur(cursor));
  65. page_cursor = btr_pcur_get_page_cur(cursor);
  66. rec = page_cur_get_rec(page_cursor);
  67. page = buf_frame_align(rec);
  68. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  69. MTR_MEMO_PAGE_S_FIX)
  70.       || mtr_memo_contains(mtr, buf_block_align(page),
  71. MTR_MEMO_PAGE_X_FIX));
  72. ut_a(cursor->latch_mode != BTR_NO_LATCHES);
  73. if (page_get_n_recs(page) == 0) {
  74. /* It must be an empty index tree; NOTE that in this case
  75. we do not store the modify_clock, but always do a search
  76. if we restore the cursor position */
  77. ut_a(btr_page_get_next(page, mtr) == FIL_NULL
  78.      && btr_page_get_prev(page, mtr) == FIL_NULL);
  79. if (rec == page_get_supremum_rec(page)) {
  80. cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
  81. cursor->old_stored = BTR_PCUR_OLD_STORED;
  82. return;
  83. }
  84. cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
  85. cursor->old_stored = BTR_PCUR_OLD_STORED;
  86. return;
  87. if (rec == page_get_supremum_rec(page)) {
  88. rec = page_rec_get_prev(rec);
  89. cursor->rel_pos = BTR_PCUR_AFTER;
  90. } else if (rec == page_get_infimum_rec(page)) {
  91. rec = page_rec_get_next(rec);
  92. cursor->rel_pos = BTR_PCUR_BEFORE;
  93. } else {
  94. cursor->rel_pos = BTR_PCUR_ON;
  95. }
  96. cursor->old_stored = BTR_PCUR_OLD_STORED;
  97. cursor->old_rec = dict_tree_copy_rec_order_prefix(tree, rec,
  98. &(cursor->old_rec_buf),
  99. &(cursor->buf_size));
  100. cursor->block_when_stored = buf_block_align(page);
  101. cursor->modify_clock = buf_frame_get_modify_clock(page);
  102. }
  103. /******************************************************************
  104. Copies the stored position of a pcur to another pcur. */
  105. void
  106. btr_pcur_copy_stored_position(
  107. /*==========================*/
  108. btr_pcur_t* pcur_receive, /* in: pcur which will receive the
  109. position info */
  110. btr_pcur_t* pcur_donate) /* in: pcur from which the info is
  111. copied */
  112. {
  113. if (pcur_receive->old_rec_buf) {
  114. mem_free(pcur_receive->old_rec_buf);
  115. }
  116. ut_memcpy((byte*)pcur_receive, (byte*)pcur_donate, sizeof(btr_pcur_t));
  117. if (pcur_donate->old_rec_buf) {
  118. pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
  119. ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
  120. pcur_donate->buf_size);
  121. pcur_receive->old_rec = pcur_receive->old_rec_buf
  122. + (pcur_donate->old_rec - pcur_donate->old_rec_buf);
  123. }
  124. }
  125. /******************************************************************
  126. Restores the stored position of a persistent cursor bufferfixing the page and
  127. obtaining the specified latches. If the cursor position was saved when the
  128. (1) cursor was positioned on a user record: this function restores the position
  129. to the last record LESS OR EQUAL to the stored record;
  130. (2) cursor was positioned on a page infimum record: restores the position to
  131. the last record LESS than the user record which was the successor of the page
  132. infimum;
  133. (3) cursor was positioned on the page supremum: restores to the first record
  134. GREATER than the user record which was the predecessor of the supremum.
  135. (4) cursor was positioned before the first or after the last in an empty tree:
  136. restores to before first or after the last in the tree. */
  137. ibool
  138. btr_pcur_restore_position(
  139. /*======================*/
  140. /* out: TRUE if the cursor position
  141. was stored when it was on a user record
  142. and it can be restored on a user record
  143. whose ordering fields are identical to
  144. the ones of the original user record */
  145. ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
  146. btr_pcur_t* cursor,  /* in: detached persistent cursor */
  147. mtr_t* mtr) /* in: mtr */
  148. {
  149. dict_tree_t* tree;
  150. page_t* page;
  151. dtuple_t* tuple;
  152. ulint mode;
  153. ulint old_mode;
  154. ibool from_left;
  155. mem_heap_t* heap;
  156. ut_a(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
  157. || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  158. if (cursor->old_stored != BTR_PCUR_OLD_STORED) {
  159. ut_print_buf(stderr, (const byte*)cursor, sizeof(btr_pcur_t));
  160. if (cursor->trx_if_known) {
  161. trx_print(stderr, cursor->trx_if_known);
  162. }
  163. ut_a(0);
  164. }
  165. if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
  166.     || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
  167.      /* In these cases we do not try an optimistic restoration,
  168.      but always do a search */
  169.      if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
  170.      from_left = TRUE;
  171.      } else {
  172.      from_left = FALSE;
  173.      }
  174. btr_cur_open_at_index_side(from_left,
  175. btr_pcur_get_btr_cur(cursor)->index, latch_mode,
  176. btr_pcur_get_btr_cur(cursor), mtr);
  177. cursor->block_when_stored =
  178. buf_block_align(btr_pcur_get_page(cursor));
  179. return(FALSE);
  180. }
  181. ut_a(cursor->old_rec);
  182. page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
  183. if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
  184. /* Try optimistic restoration */
  185.     
  186. if (buf_page_optimistic_get(latch_mode,
  187.     cursor->block_when_stored, page,
  188.     cursor->modify_clock, mtr)) {
  189. cursor->pos_state = BTR_PCUR_IS_POSITIONED;
  190. #ifdef UNIV_SYNC_DEBUG
  191. buf_page_dbg_add_level(page, SYNC_TREE_NODE);
  192. #endif /* UNIV_SYNC_DEBUG */
  193. if (cursor->rel_pos == BTR_PCUR_ON) {
  194. cursor->latch_mode = latch_mode;
  195. ut_ad(cmp_rec_rec(cursor->old_rec,
  196. btr_pcur_get_rec(cursor),
  197. dict_tree_find_index(
  198.     btr_cur_get_tree(
  199. btr_pcur_get_btr_cur(cursor)),
  200.     btr_pcur_get_rec(cursor)))
  201. == 0); 
  202. return(TRUE);
  203. }
  204. return(FALSE);
  205. }
  206. }
  207. /* If optimistic restoration did not succeed, open the cursor anew */
  208. heap = mem_heap_create(256);
  209. tree = btr_cur_get_tree(btr_pcur_get_btr_cur(cursor));
  210. tuple = dict_tree_build_data_tuple(tree, cursor->old_rec, heap);
  211. /* Save the old search mode of the cursor */
  212. old_mode = cursor->search_mode;
  213. if (cursor->rel_pos == BTR_PCUR_ON) {
  214. mode = PAGE_CUR_LE;
  215. } else if (cursor->rel_pos == BTR_PCUR_AFTER) {
  216. mode = PAGE_CUR_G;
  217. } else {
  218. ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
  219. mode = PAGE_CUR_L;
  220. }
  221. btr_pcur_open_with_no_init(btr_pcur_get_btr_cur(cursor)->index, tuple,
  222. mode, latch_mode, cursor, 0, mtr);
  223. /* Restore the old search mode */
  224. cursor->search_mode = old_mode;
  225. if (cursor->rel_pos == BTR_PCUR_ON
  226.     && btr_pcur_is_on_user_rec(cursor, mtr)
  227.     && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) {
  228. /* We have to store the NEW value for the modify clock, since
  229. the cursor can now be on a different page! But we can retain
  230. the value of old_rec */
  231. cursor->modify_clock =
  232. buf_frame_get_modify_clock(btr_pcur_get_page(cursor));
  233. cursor->block_when_stored =
  234. buf_block_align(btr_pcur_get_page(cursor));
  235. cursor->old_stored = BTR_PCUR_OLD_STORED;
  236. mem_heap_free(heap);
  237. return(TRUE);
  238. }
  239. mem_heap_free(heap);
  240. /* We have to store new position information, modify_clock etc.,
  241. to the cursor because it can now be on a different page, the record
  242. under it may have been removed, etc. */
  243. btr_pcur_store_position(cursor, mtr);
  244. return(FALSE);
  245. }
  246. /******************************************************************
  247. If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
  248. releases the page latch and bufferfix reserved by the cursor.
  249. NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
  250. made by the current mini-transaction to the data protected by the
  251. cursor latch, as then the latch must not be released until mtr_commit. */
  252. void
  253. btr_pcur_release_leaf(
  254. /*==================*/
  255. btr_pcur_t* cursor, /* in: persistent cursor */
  256. mtr_t* mtr) /* in: mtr */
  257. {
  258. page_t* page;
  259. ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  260. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  261. page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
  262. btr_leaf_page_release(page, cursor->latch_mode, mtr);
  263. cursor->latch_mode = BTR_NO_LATCHES;
  264. cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
  265. }
  266. /*************************************************************
  267. Moves the persistent cursor to the first record on the next page. Releases the
  268. latch on the current page, and bufferunfixes it. Note that there must not be
  269. modifications on the current page, as then the x-latch can be released only in
  270. mtr_commit. */
  271. void
  272. btr_pcur_move_to_next_page(
  273. /*=======================*/
  274. btr_pcur_t* cursor, /* in: persistent cursor; must be on the
  275. last record of the current page */
  276. mtr_t* mtr) /* in: mtr */
  277. {
  278. ulint next_page_no;
  279. ulint space;
  280. page_t* page;
  281. page_t* next_page;
  282. ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  283. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  284. ut_ad(btr_pcur_is_after_last_on_page(cursor, mtr));
  285. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  286. page = btr_pcur_get_page(cursor);
  287. next_page_no = btr_page_get_next(page, mtr);
  288. space = buf_frame_get_space_id(page);
  289. ut_ad(next_page_no != FIL_NULL);
  290. next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr);
  291. buf_block_align(next_page)->check_index_page_at_flush = TRUE;
  292. btr_leaf_page_release(page, cursor->latch_mode, mtr);
  293. page_cur_set_before_first(next_page, btr_pcur_get_page_cur(cursor));
  294. page_check_dir(next_page);
  295. }
  296. /*************************************************************
  297. Moves the persistent cursor backward if it is on the first record of the page.
  298. Commits mtr. Note that to prevent a possible deadlock, the operation
  299. first stores the position of the cursor, commits mtr, acquires the necessary
  300. latches and restores the cursor position again before returning. The
  301. alphabetical position of the cursor is guaranteed to be sensible on
  302. return, but it may happen that the cursor is not positioned on the last
  303. record of any page, because the structure of the tree may have changed
  304. during the time when the cursor had no latches. */
  305. void
  306. btr_pcur_move_backward_from_page(
  307. /*=============================*/
  308. btr_pcur_t* cursor, /* in: persistent cursor, must be on the first
  309. record of the current page */
  310. mtr_t* mtr) /* in: mtr */
  311. {
  312. ulint prev_page_no;
  313. ulint space;
  314. page_t* page;
  315. page_t* prev_page;
  316. ulint latch_mode;
  317. ulint latch_mode2;
  318. ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  319. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  320. ut_ad(btr_pcur_is_before_first_on_page(cursor, mtr));
  321. ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
  322. latch_mode = cursor->latch_mode;
  323. if (latch_mode == BTR_SEARCH_LEAF) {
  324. latch_mode2 = BTR_SEARCH_PREV;
  325. } else if (latch_mode == BTR_MODIFY_LEAF) {
  326. latch_mode2 = BTR_MODIFY_PREV;
  327. } else {
  328. latch_mode2 = 0; /* To eliminate compiler warning */
  329. ut_error;
  330. }
  331. btr_pcur_store_position(cursor, mtr);
  332. mtr_commit(mtr);
  333. mtr_start(mtr);
  334. btr_pcur_restore_position(latch_mode2, cursor, mtr);
  335. page = btr_pcur_get_page(cursor);
  336. prev_page_no = btr_page_get_prev(page, mtr);
  337. space = buf_frame_get_space_id(page);
  338. if (btr_pcur_is_before_first_on_page(cursor, mtr)
  339. && (prev_page_no != FIL_NULL)) {
  340. prev_page = btr_pcur_get_btr_cur(cursor)->left_page;
  341. btr_leaf_page_release(page, latch_mode, mtr);
  342. page_cur_set_after_last(prev_page,
  343. btr_pcur_get_page_cur(cursor));
  344. } else if (prev_page_no != FIL_NULL) {
  345. /* The repositioned cursor did not end on an infimum record on
  346. a page. Cursor repositioning acquired a latch also on the
  347. previous page, but we do not need the latch: release it. */
  348. prev_page = btr_pcur_get_btr_cur(cursor)->left_page;
  349. btr_leaf_page_release(prev_page, latch_mode, mtr);
  350. }
  351. cursor->latch_mode = latch_mode;
  352. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  353. }
  354. /*************************************************************
  355. Moves the persistent cursor to the previous record in the tree. If no records
  356. are left, the cursor stays 'before first in tree'. */
  357. ibool
  358. btr_pcur_move_to_prev(
  359. /*==================*/
  360. /* out: TRUE if the cursor was not before first
  361. in tree */
  362. btr_pcur_t* cursor, /* in: persistent cursor; NOTE that the
  363. function may release the page latch */
  364. mtr_t* mtr) /* in: mtr */
  365. {
  366. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  367. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  368. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  369. if (btr_pcur_is_before_first_on_page(cursor, mtr)) {
  370. if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
  371. return(FALSE);
  372. }
  373. btr_pcur_move_backward_from_page(cursor, mtr);
  374. return(TRUE);
  375. }
  376. btr_pcur_move_to_prev_on_page(cursor, mtr);
  377. return(TRUE);
  378. }
  379. /******************************************************************
  380. If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
  381. user record satisfying the search condition, in the case PAGE_CUR_L or
  382. PAGE_CUR_LE, on the last user record. If no such user record exists, then
  383. in the first case sets the cursor after last in tree, and in the latter case
  384. before first in tree. The latching mode must be BTR_SEARCH_LEAF or
  385. BTR_MODIFY_LEAF. */
  386. void
  387. btr_pcur_open_on_user_rec(
  388. /*======================*/
  389. dict_index_t* index, /* in: index */
  390. dtuple_t* tuple, /* in: tuple on which search done */
  391. ulint mode, /* in: PAGE_CUR_L, ... */
  392. ulint latch_mode, /* in: BTR_SEARCH_LEAF or
  393. BTR_MODIFY_LEAF */
  394. btr_pcur_t* cursor,  /* in: memory buffer for persistent
  395. cursor */
  396. mtr_t* mtr) /* in: mtr */
  397. {
  398. btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr);
  399. if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
  400. if (btr_pcur_is_after_last_on_page(cursor, mtr)) {
  401. btr_pcur_move_to_next_user_rec(cursor, mtr);
  402. }
  403. } else {
  404. ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
  405. /* Not implemented yet */
  406. ut_error;
  407. }
  408. }