You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
17 KiB

12 years ago
12 years ago
  1. /*****************************************************************************
  2. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
  3. This program is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free Software
  5. Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along with
  10. this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
  12. *****************************************************************************/
  13. /**************************************************//**
  14. @file include/btr0pcur.ic
  15. The index tree persistent cursor
  16. Created 2/23/1996 Heikki Tuuri
  17. *******************************************************/
  18. /*********************************************************//**
  19. Gets the rel_pos field for a cursor whose position has been stored.
  20. @return BTR_PCUR_ON, ... */
  21. UNIV_INLINE
  22. ulint
  23. btr_pcur_get_rel_pos(
  24. /*=================*/
  25. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  26. {
  27. ut_ad(cursor);
  28. ut_ad(cursor->old_rec);
  29. ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED);
  30. ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
  31. || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  32. return(cursor->rel_pos);
  33. }
  34. #ifdef UNIV_DEBUG
  35. /*********************************************************//**
  36. Returns the btr cursor component of a persistent cursor.
  37. @return pointer to btr cursor component */
  38. UNIV_INLINE
  39. btr_cur_t*
  40. btr_pcur_get_btr_cur(
  41. /*=================*/
  42. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  43. {
  44. const btr_cur_t* btr_cur = &cursor->btr_cur;
  45. return((btr_cur_t*) btr_cur);
  46. }
  47. /*********************************************************//**
  48. Returns the page cursor component of a persistent cursor.
  49. @return pointer to page cursor component */
  50. UNIV_INLINE
  51. page_cur_t*
  52. btr_pcur_get_page_cur(
  53. /*==================*/
  54. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  55. {
  56. return(btr_cur_get_page_cur(btr_pcur_get_btr_cur(cursor)));
  57. }
  58. /*********************************************************//**
  59. Returns the page of a persistent cursor.
  60. @return pointer to the page */
  61. UNIV_INLINE
  62. page_t*
  63. btr_pcur_get_page(
  64. /*==============*/
  65. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  66. {
  67. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  68. return(btr_cur_get_page(btr_pcur_get_btr_cur(cursor)));
  69. }
  70. /*********************************************************//**
  71. Returns the buffer block of a persistent cursor.
  72. @return pointer to the block */
  73. UNIV_INLINE
  74. buf_block_t*
  75. btr_pcur_get_block(
  76. /*===============*/
  77. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  78. {
  79. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  80. return(btr_cur_get_block(btr_pcur_get_btr_cur(cursor)));
  81. }
  82. /*********************************************************//**
  83. Returns the record of a persistent cursor.
  84. @return pointer to the record */
  85. UNIV_INLINE
  86. rec_t*
  87. btr_pcur_get_rec(
  88. /*=============*/
  89. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  90. {
  91. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  92. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  93. return(btr_cur_get_rec(btr_pcur_get_btr_cur(cursor)));
  94. }
  95. #endif /* UNIV_DEBUG */
  96. /**************************************************************//**
  97. Gets the up_match value for a pcur after a search.
  98. @return number of matched fields at the cursor or to the right if
  99. search mode was PAGE_CUR_GE, otherwise undefined */
  100. UNIV_INLINE
  101. ulint
  102. btr_pcur_get_up_match(
  103. /*==================*/
  104. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  105. {
  106. const btr_cur_t* btr_cursor;
  107. ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED)
  108. || (cursor->pos_state == BTR_PCUR_IS_POSITIONED));
  109. btr_cursor = btr_pcur_get_btr_cur(cursor);
  110. ut_ad(btr_cursor->up_match != ULINT_UNDEFINED);
  111. return(btr_cursor->up_match);
  112. }
  113. /**************************************************************//**
  114. Gets the low_match value for a pcur after a search.
  115. @return number of matched fields at the cursor or to the right if
  116. search mode was PAGE_CUR_LE, otherwise undefined */
  117. UNIV_INLINE
  118. ulint
  119. btr_pcur_get_low_match(
  120. /*===================*/
  121. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  122. {
  123. const btr_cur_t* btr_cursor;
  124. ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED)
  125. || (cursor->pos_state == BTR_PCUR_IS_POSITIONED));
  126. btr_cursor = btr_pcur_get_btr_cur(cursor);
  127. ut_ad(btr_cursor->low_match != ULINT_UNDEFINED);
  128. return(btr_cursor->low_match);
  129. }
  130. /*********************************************************//**
  131. Checks if the persistent cursor is after the last user record on
  132. a page. */
  133. UNIV_INLINE
  134. ibool
  135. btr_pcur_is_after_last_on_page(
  136. /*===========================*/
  137. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  138. {
  139. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  140. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  141. return(page_cur_is_after_last(btr_pcur_get_page_cur(cursor)));
  142. }
  143. /*********************************************************//**
  144. Checks if the persistent cursor is before the first user record on
  145. a page. */
  146. UNIV_INLINE
  147. ibool
  148. btr_pcur_is_before_first_on_page(
  149. /*=============================*/
  150. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  151. {
  152. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  153. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  154. return(page_cur_is_before_first(btr_pcur_get_page_cur(cursor)));
  155. }
  156. /*********************************************************//**
  157. Checks if the persistent cursor is on a user record. */
  158. UNIV_INLINE
  159. ibool
  160. btr_pcur_is_on_user_rec(
  161. /*====================*/
  162. const btr_pcur_t* cursor) /*!< in: persistent cursor */
  163. {
  164. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  165. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  166. if (btr_pcur_is_before_first_on_page(cursor)
  167. || btr_pcur_is_after_last_on_page(cursor)) {
  168. return(FALSE);
  169. }
  170. return(TRUE);
  171. }
  172. /*********************************************************//**
  173. Checks if the persistent cursor is before the first user record in
  174. the index tree. */
  175. UNIV_INLINE
  176. ibool
  177. btr_pcur_is_before_first_in_tree(
  178. /*=============================*/
  179. btr_pcur_t* cursor, /*!< in: persistent cursor */
  180. mtr_t* mtr) /*!< in: mtr */
  181. {
  182. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  183. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  184. if (btr_page_get_prev(btr_pcur_get_page(cursor), mtr) != FIL_NULL) {
  185. return(FALSE);
  186. }
  187. return(page_cur_is_before_first(btr_pcur_get_page_cur(cursor)));
  188. }
  189. /*********************************************************//**
  190. Checks if the persistent cursor is after the last user record in
  191. the index tree. */
  192. UNIV_INLINE
  193. ibool
  194. btr_pcur_is_after_last_in_tree(
  195. /*===========================*/
  196. btr_pcur_t* cursor, /*!< in: persistent cursor */
  197. mtr_t* mtr) /*!< in: mtr */
  198. {
  199. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  200. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  201. if (btr_page_get_next(btr_pcur_get_page(cursor), mtr) != FIL_NULL) {
  202. return(FALSE);
  203. }
  204. return(page_cur_is_after_last(btr_pcur_get_page_cur(cursor)));
  205. }
  206. /*********************************************************//**
  207. Moves the persistent cursor to the next record on the same page. */
  208. UNIV_INLINE
  209. void
  210. btr_pcur_move_to_next_on_page(
  211. /*==========================*/
  212. btr_pcur_t* cursor) /*!< in/out: persistent cursor */
  213. {
  214. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  215. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  216. page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
  217. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  218. }
  219. /*********************************************************//**
  220. Moves the persistent cursor to the previous record on the same page. */
  221. UNIV_INLINE
  222. void
  223. btr_pcur_move_to_prev_on_page(
  224. /*==========================*/
  225. btr_pcur_t* cursor) /*!< in/out: persistent cursor */
  226. {
  227. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  228. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  229. page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
  230. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  231. }
  232. /*********************************************************//**
  233. Moves the persistent cursor to the last record on the same page. */
  234. UNIV_INLINE
  235. void
  236. btr_pcur_move_to_last_on_page(
  237. /*==========================*/
  238. btr_pcur_t* cursor, /*!< in: persistent cursor */
  239. mtr_t* mtr) /*!< in: mtr */
  240. {
  241. UT_NOT_USED(mtr);
  242. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  243. page_cur_set_after_last(btr_pcur_get_block(cursor),
  244. btr_pcur_get_page_cur(cursor));
  245. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  246. }
  247. /*********************************************************//**
  248. Moves the persistent cursor to the next user record in the tree. If no user
  249. records are left, the cursor ends up 'after last in tree'.
  250. @return TRUE if the cursor moved forward, ending on a user record */
  251. UNIV_INLINE
  252. ibool
  253. btr_pcur_move_to_next_user_rec(
  254. /*===========================*/
  255. btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
  256. function may release the page latch */
  257. mtr_t* mtr) /*!< in: mtr */
  258. {
  259. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  260. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  261. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  262. loop:
  263. if (btr_pcur_is_after_last_on_page(cursor)) {
  264. if (btr_pcur_is_after_last_in_tree(cursor, mtr)) {
  265. return(FALSE);
  266. }
  267. btr_pcur_move_to_next_page(cursor, mtr);
  268. } else {
  269. btr_pcur_move_to_next_on_page(cursor);
  270. }
  271. if (btr_pcur_is_on_user_rec(cursor)) {
  272. return(TRUE);
  273. }
  274. goto loop;
  275. }
  276. /*********************************************************//**
  277. Moves the persistent cursor to the next record in the tree. If no records are
  278. left, the cursor stays 'after last in tree'.
  279. @return TRUE if the cursor was not after last in tree */
  280. UNIV_INLINE
  281. ibool
  282. btr_pcur_move_to_next(
  283. /*==================*/
  284. btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
  285. function may release the page latch */
  286. mtr_t* mtr) /*!< in: mtr */
  287. {
  288. ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
  289. ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
  290. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  291. if (btr_pcur_is_after_last_on_page(cursor)) {
  292. if (btr_pcur_is_after_last_in_tree(cursor, mtr)) {
  293. return(FALSE);
  294. }
  295. btr_pcur_move_to_next_page(cursor, mtr);
  296. return(TRUE);
  297. }
  298. btr_pcur_move_to_next_on_page(cursor);
  299. return(TRUE);
  300. }
  301. /**************************************************************//**
  302. Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES,
  303. that is, the cursor becomes detached.
  304. Function btr_pcur_store_position should be used before calling this,
  305. if restoration of cursor is wanted later. */
  306. UNIV_INLINE
  307. void
  308. btr_pcur_commit_specify_mtr(
  309. /*========================*/
  310. btr_pcur_t* pcur, /*!< in: persistent cursor */
  311. mtr_t* mtr) /*!< in: mtr to commit */
  312. {
  313. ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
  314. pcur->latch_mode = BTR_NO_LATCHES;
  315. mtr_commit(mtr);
  316. pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
  317. }
  318. /**************************************************************//**
  319. Sets the old_rec_buf field to NULL. */
  320. UNIV_INLINE
  321. void
  322. btr_pcur_init(
  323. /*==========*/
  324. btr_pcur_t* pcur) /*!< in: persistent cursor */
  325. {
  326. pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
  327. pcur->old_rec_buf = NULL;
  328. pcur->old_rec = NULL;
  329. }
  330. /**************************************************************//**
  331. Initializes and opens a persistent cursor to an index tree. It should be
  332. closed with btr_pcur_close. */
  333. UNIV_INLINE
  334. void
  335. btr_pcur_open_low(
  336. /*==============*/
  337. dict_index_t* index, /*!< in: index */
  338. ulint level, /*!< in: level in the btree */
  339. const dtuple_t* tuple, /*!< in: tuple on which search done */
  340. ulint mode, /*!< in: PAGE_CUR_L, ...;
  341. NOTE that if the search is made using a unique
  342. prefix of a record, mode should be
  343. PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
  344. may end up on the previous page from the
  345. record! */
  346. ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
  347. btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
  348. const char* file, /*!< in: file name */
  349. ulint line, /*!< in: line where called */
  350. mtr_t* mtr) /*!< in: mtr */
  351. {
  352. btr_cur_t* btr_cursor;
  353. /* Initialize the cursor */
  354. btr_pcur_init(cursor);
  355. cursor->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
  356. cursor->search_mode = mode;
  357. /* Search with the tree cursor */
  358. btr_cursor = btr_pcur_get_btr_cur(cursor);
  359. btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode,
  360. btr_cursor, 0, file, line, mtr);
  361. cursor->pos_state = BTR_PCUR_IS_POSITIONED;
  362. cursor->trx_if_known = NULL;
  363. }
  364. /**************************************************************//**
  365. Opens an persistent cursor to an index tree without initializing the
  366. cursor. */
  367. UNIV_INLINE
  368. void
  369. btr_pcur_open_with_no_init_func(
  370. /*============================*/
  371. dict_index_t* index, /*!< in: index */
  372. const dtuple_t* tuple, /*!< in: tuple on which search done */
  373. ulint mode, /*!< in: PAGE_CUR_L, ...;
  374. NOTE that if the search is made using a unique
  375. prefix of a record, mode should be
  376. PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
  377. may end up on the previous page of the
  378. record! */
  379. ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ...;
  380. NOTE that if has_search_latch != 0 then
  381. we maybe do not acquire a latch on the cursor
  382. page, but assume that the caller uses his
  383. btr search latch to protect the record! */
  384. btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
  385. ulint has_search_latch,/*!< in: latch mode the caller
  386. currently has on btr_search_latch:
  387. RW_S_LATCH, or 0 */
  388. const char* file, /*!< in: file name */
  389. ulint line, /*!< in: line where called */
  390. mtr_t* mtr) /*!< in: mtr */
  391. {
  392. btr_cur_t* btr_cursor;
  393. cursor->latch_mode = latch_mode;
  394. cursor->search_mode = mode;
  395. /* Search with the tree cursor */
  396. btr_cursor = btr_pcur_get_btr_cur(cursor);
  397. btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
  398. btr_cursor, has_search_latch,
  399. file, line, mtr);
  400. cursor->pos_state = BTR_PCUR_IS_POSITIONED;
  401. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  402. cursor->trx_if_known = NULL;
  403. }
  404. /*****************************************************************//**
  405. Opens a persistent cursor at either end of an index. */
  406. UNIV_INLINE
  407. void
  408. btr_pcur_open_at_index_side(
  409. /*========================*/
  410. bool from_left, /*!< in: true if open to the low end,
  411. false if to the high end */
  412. dict_index_t* index, /*!< in: index */
  413. ulint latch_mode, /*!< in: latch mode */
  414. btr_pcur_t* pcur, /*!< in/out: cursor */
  415. bool init_pcur, /*!< in: whether to initialize pcur */
  416. ulint level, /*!< in: level to search for
  417. (0=leaf) */
  418. mtr_t* mtr) /*!< in/out: mini-transaction */
  419. {
  420. pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
  421. pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
  422. if (init_pcur) {
  423. btr_pcur_init(pcur);
  424. }
  425. btr_cur_open_at_index_side(from_left, index, latch_mode,
  426. btr_pcur_get_btr_cur(pcur), level, mtr);
  427. pcur->pos_state = BTR_PCUR_IS_POSITIONED;
  428. pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
  429. pcur->trx_if_known = NULL;
  430. }
  431. /**********************************************************************//**
  432. Positions a cursor at a randomly chosen position within a B-tree. */
  433. UNIV_INLINE
  434. void
  435. btr_pcur_open_at_rnd_pos_func(
  436. /*==========================*/
  437. dict_index_t* index, /*!< in: index */
  438. ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
  439. btr_pcur_t* cursor, /*!< in/out: B-tree pcur */
  440. const char* file, /*!< in: file name */
  441. ulint line, /*!< in: line where called */
  442. mtr_t* mtr) /*!< in: mtr */
  443. {
  444. /* Initialize the cursor */
  445. cursor->latch_mode = latch_mode;
  446. cursor->search_mode = PAGE_CUR_G;
  447. btr_pcur_init(cursor);
  448. btr_cur_open_at_rnd_pos_func(index, latch_mode,
  449. btr_pcur_get_btr_cur(cursor),
  450. file, line, mtr);
  451. cursor->pos_state = BTR_PCUR_IS_POSITIONED;
  452. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  453. cursor->trx_if_known = NULL;
  454. }
  455. /**************************************************************//**
  456. Frees the possible memory heap of a persistent cursor and sets the latch
  457. mode of the persistent cursor to BTR_NO_LATCHES.
  458. WARNING: this function does not release the latch on the page where the
  459. cursor is currently positioned. The latch is acquired by the
  460. "move to next/previous" family of functions. Since recursive shared locks
  461. are not allowed, you must take care (if using the cursor in S-mode) to
  462. manually release the latch by either calling
  463. btr_leaf_page_release(btr_pcur_get_block(&pcur), pcur.latch_mode, mtr)
  464. or by committing the mini-transaction right after btr_pcur_close().
  465. A subsequent attempt to crawl the same page in the same mtr would cause
  466. an assertion failure. */
  467. UNIV_INLINE
  468. void
  469. btr_pcur_close(
  470. /*===========*/
  471. btr_pcur_t* cursor) /*!< in: persistent cursor */
  472. {
  473. if (cursor->old_rec_buf != NULL) {
  474. mem_free(cursor->old_rec_buf);
  475. cursor->old_rec = NULL;
  476. cursor->old_rec_buf = NULL;
  477. }
  478. cursor->btr_cur.page_cur.rec = NULL;
  479. cursor->btr_cur.page_cur.block = NULL;
  480. cursor->old_rec = NULL;
  481. cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
  482. cursor->latch_mode = BTR_NO_LATCHES;
  483. cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
  484. cursor->trx_if_known = NULL;
  485. }