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

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The index tree cursor
  3. All changes that row operations make to a B-tree or the records
  4. there must go through this module! Undo log records are written here
  5. of every modify or insert of a clustered index record.
  6. NOTE!!!
  7. To make sure we do not run out of disk space during a pessimistic
  8. insert or update, we have to reserve 2 x the height of the index tree
  9. many pages in the tablespace before we start the operation, because
  10. if leaf splitting has been started, it is difficult to undo, except
  11. by crashing the database and doing a roll-forward.
  12. (c) 1994-2001 Innobase Oy
  13. Created 10/16/1994 Heikki Tuuri
  14. *******************************************************/
  15. #include "btr0cur.h"
  16. #ifdef UNIV_NONINL
  17. #include "btr0cur.ic"
  18. #endif
  19. #include "page0page.h"
  20. #include "rem0rec.h"
  21. #include "rem0cmp.h"
  22. #include "btr0btr.h"
  23. #include "btr0sea.h"
  24. #include "row0upd.h"
  25. #include "trx0rec.h"
  26. #include "que0que.h"
  27. #include "row0row.h"
  28. #include "srv0srv.h"
  29. #include "ibuf0ibuf.h"
  30. #include "lock0lock.h"
  31. /* If the following is set to TRUE, this module prints a lot of
  32. trace information of individual record operations */
  33. ibool btr_cur_print_record_ops = FALSE;
  34. ulint btr_cur_rnd = 0;
  35. ulint btr_cur_n_non_sea = 0;
  36. ulint btr_cur_n_sea = 0;
  37. ulint btr_cur_n_non_sea_old = 0;
  38. ulint btr_cur_n_sea_old = 0;
  39. /* In the optimistic insert, if the insert does not fit, but this much space
  40. can be released by page reorganize, then it is reorganized */
  41. #define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32)
  42. /* When estimating number of different kay values in an index sample
  43. this many index pages */
  44. #define BTR_KEY_VAL_ESTIMATE_N_PAGES 8
  45. /* The structure of a BLOB part header */
  46. /*--------------------------------------*/
  47. #define BTR_BLOB_HDR_PART_LEN 0 /* BLOB part len on this
  48. page */
  49. #define BTR_BLOB_HDR_NEXT_PAGE_NO 4 /* next BLOB part page no,
  50. FIL_NULL if none */
  51. /*--------------------------------------*/
  52. #define BTR_BLOB_HDR_SIZE 8
  53. /***********************************************************************
  54. Marks all extern fields in a record as owned by the record. This function
  55. should be called if the delete mark of a record is removed: a not delete
  56. marked record always owns all its extern fields. */
  57. static
  58. void
  59. btr_cur_unmark_extern_fields(
  60. /*=========================*/
  61. rec_t* rec, /* in: record in a clustered index */
  62. mtr_t* mtr); /* in: mtr */
  63. /***********************************************************************
  64. Adds path information to the cursor for the current page, for which
  65. the binary search has been performed. */
  66. static
  67. void
  68. btr_cur_add_path_info(
  69. /*==================*/
  70. btr_cur_t* cursor, /* in: cursor positioned on a page */
  71. ulint height, /* in: height of the page in tree;
  72. 0 means leaf node */
  73. ulint root_height); /* in: root node height in tree */
  74. /***************************************************************
  75. Frees the externally stored fields for a record, if the field is mentioned
  76. in the update vector. */
  77. static
  78. void
  79. btr_rec_free_updated_extern_fields(
  80. /*===============================*/
  81. dict_index_t* index, /* in: index of rec; the index tree MUST be
  82. X-latched */
  83. rec_t* rec, /* in: record */
  84. upd_t* update, /* in: update vector */
  85. ibool do_not_free_inherited,/* in: TRUE if called in a
  86. rollback and we do not want to free
  87. inherited fields */
  88. mtr_t* mtr); /* in: mini-transaction handle which contains
  89. an X-latch to record page and to the tree */
  90. /***************************************************************
  91. Gets the externally stored size of a record, in units of a database page. */
  92. static
  93. ulint
  94. btr_rec_get_externally_stored_len(
  95. /*==============================*/
  96. /* out: externally stored part, in units of a
  97. database page */
  98. rec_t* rec); /* in: record */
  99. /*==================== B-TREE SEARCH =========================*/
  100. /************************************************************************
  101. Latches the leaf page or pages requested. */
  102. static
  103. void
  104. btr_cur_latch_leaves(
  105. /*=================*/
  106. page_t* page, /* in: leaf page where the search
  107. converged */
  108. ulint space, /* in: space id */
  109. ulint page_no, /* in: page number of the leaf */
  110. ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
  111. btr_cur_t* cursor,  /* in: cursor */
  112. mtr_t* mtr) /* in: mtr */
  113. {
  114. ulint left_page_no;
  115. ulint right_page_no;
  116. page_t* get_page;
  117. ut_ad(page && mtr);
  118. if (latch_mode == BTR_SEARCH_LEAF) {
  119. get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr);
  120. buf_block_align(get_page)->check_index_page_at_flush = TRUE;
  121. } else if (latch_mode == BTR_MODIFY_LEAF) {
  122. get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
  123. buf_block_align(get_page)->check_index_page_at_flush = TRUE;
  124. } else if (latch_mode == BTR_MODIFY_TREE) {
  125. /* x-latch also brothers from left to right */
  126. left_page_no = btr_page_get_prev(page, mtr);
  127. if (left_page_no != FIL_NULL) {
  128. get_page = btr_page_get(space, left_page_no,
  129. RW_X_LATCH, mtr);
  130. buf_block_align(get_page)->check_index_page_at_flush =
  131. TRUE;
  132. }
  133. get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
  134. buf_block_align(get_page)->check_index_page_at_flush = TRUE;
  135. right_page_no = btr_page_get_next(page, mtr);
  136. if (right_page_no != FIL_NULL) {
  137. get_page = btr_page_get(space, right_page_no,
  138. RW_X_LATCH, mtr);
  139. buf_block_align(get_page)->check_index_page_at_flush =
  140. TRUE;
  141. }
  142. } else if (latch_mode == BTR_SEARCH_PREV) {
  143. /* s-latch also left brother */
  144. left_page_no = btr_page_get_prev(page, mtr);
  145. if (left_page_no != FIL_NULL) {
  146. cursor->left_page = btr_page_get(space, left_page_no,
  147. RW_S_LATCH, mtr);
  148. buf_block_align(
  149. cursor->left_page)->check_index_page_at_flush = TRUE;
  150. }
  151. get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr);
  152. buf_block_align(get_page)->check_index_page_at_flush = TRUE;
  153. } else if (latch_mode == BTR_MODIFY_PREV) {
  154. /* x-latch also left brother */
  155. left_page_no = btr_page_get_prev(page, mtr);
  156. if (left_page_no != FIL_NULL) {
  157. cursor->left_page = btr_page_get(space, left_page_no,
  158. RW_X_LATCH, mtr);
  159. buf_block_align(
  160. cursor->left_page)->check_index_page_at_flush = TRUE;
  161. }
  162. get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
  163. buf_block_align(get_page)->check_index_page_at_flush = TRUE;
  164. } else {
  165. ut_error;
  166. }
  167. }
  168. /************************************************************************
  169. Searches an index tree and positions a tree cursor on a given level.
  170. NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
  171. to node pointer page number fields on the upper levels of the tree!
  172. Note that if mode is PAGE_CUR_LE, which is used in inserts, then
  173. cursor->up_match and cursor->low_match both will have sensible values.
  174. If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
  175. void
  176. btr_cur_search_to_nth_level(
  177. /*========================*/
  178. dict_index_t* index, /* in: index */
  179. ulint level, /* in: the tree level of search */
  180. dtuple_t* tuple, /* in: data tuple; NOTE: n_fields_cmp in
  181. tuple must be set so that it cannot get
  182. compared to the node ptr page number field! */
  183. ulint mode, /* in: PAGE_CUR_L, ...;
  184. Inserts should always be made using
  185. PAGE_CUR_LE to search the position! */
  186. ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with
  187. BTR_INSERT and BTR_ESTIMATE;
  188. cursor->left_page is used to store a pointer
  189. to the left neighbor page, in the cases
  190. BTR_SEARCH_PREV and BTR_MODIFY_PREV;
  191. NOTE that if has_search_latch
  192. is != 0, we maybe do not have a latch set
  193. on the cursor page, we assume
  194. the caller uses his search latch
  195. to protect the record! */
  196. btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is
  197. s- or x-latched, but see also above! */
  198. ulint has_search_latch,/* in: info on the latch mode the
  199. caller currently has on btr_search_latch:
  200. RW_S_LATCH, or 0 */
  201. mtr_t* mtr) /* in: mtr */
  202. {
  203. dict_tree_t* tree;
  204. page_cur_t* page_cursor;
  205. page_t* page;
  206. page_t* guess;
  207. rec_t* node_ptr;
  208. ulint page_no;
  209. ulint space;
  210. ulint up_match;
  211. ulint up_bytes;
  212. ulint low_match;
  213. ulint  low_bytes;
  214. ulint height;
  215. ulint savepoint;
  216. ulint rw_latch;
  217. ulint page_mode;
  218. ulint insert_planned;
  219. ulint buf_mode;
  220. ulint estimate;
  221. ulint ignore_sec_unique;
  222. ulint root_height = 0; /* remove warning */
  223. #ifdef BTR_CUR_ADAPT
  224. btr_search_t* info;
  225. #endif
  226. /* Currently, PAGE_CUR_LE is the only search mode used for searches
  227. ending to upper levels */
  228. ut_ad(level == 0 || mode == PAGE_CUR_LE);
  229. ut_ad(dict_tree_check_search_tuple(index->tree, tuple));
  230. ut_ad(!(index->type & DICT_IBUF) || ibuf_inside());
  231. ut_ad(dtuple_check_typed(tuple));
  232. #ifdef UNIV_DEBUG
  233. cursor->up_match = ULINT_UNDEFINED;
  234. cursor->low_match = ULINT_UNDEFINED;
  235. #endif
  236. insert_planned = latch_mode & BTR_INSERT;
  237. estimate = latch_mode & BTR_ESTIMATE;
  238. ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE;
  239. latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE
  240. | BTR_IGNORE_SEC_UNIQUE);
  241. ut_ad(!insert_planned || (mode == PAGE_CUR_LE));
  242. cursor->flag = BTR_CUR_BINARY;
  243. cursor->index = index;
  244. #ifndef BTR_CUR_ADAPT
  245. guess = NULL;
  246. #else
  247. info = btr_search_get_info(index);
  248. guess = info->root_guess;
  249. #ifdef BTR_CUR_HASH_ADAPT
  250. #ifdef UNIV_SEARCH_PERF_STAT
  251. info->n_searches++;
  252. #endif
  253. if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED
  254. && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
  255. && !estimate
  256. && mode != PAGE_CUR_LE_OR_EXTENDS
  257. && srv_use_adaptive_hash_indexes
  258.         && btr_search_guess_on_hash(index, info, tuple, mode,
  259. latch_mode, cursor,
  260. has_search_latch, mtr)) {
  261. /* Search using the hash index succeeded */
  262. ut_ad(cursor->up_match != ULINT_UNDEFINED
  263. || mode != PAGE_CUR_GE);
  264. ut_ad(cursor->up_match != ULINT_UNDEFINED
  265. || mode != PAGE_CUR_LE);
  266. ut_ad(cursor->low_match != ULINT_UNDEFINED
  267. || mode != PAGE_CUR_LE);
  268. btr_cur_n_sea++;
  269.         return;
  270. }
  271. #endif
  272. #endif
  273. btr_cur_n_non_sea++;
  274. /* If the hash search did not succeed, do binary search down the
  275. tree */
  276. if (has_search_latch) {
  277. /* Release possible search latch to obey latching order */
  278. rw_lock_s_unlock(&btr_search_latch);
  279. }
  280. /* Store the position of the tree latch we push to mtr so that we
  281. know how to release it when we have latched leaf node(s) */
  282. savepoint = mtr_set_savepoint(mtr);
  283. tree = index->tree;
  284. if (latch_mode == BTR_MODIFY_TREE) {
  285. mtr_x_lock(dict_tree_get_lock(tree), mtr);
  286. } else if (latch_mode == BTR_CONT_MODIFY_TREE) {
  287. /* Do nothing */
  288. ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
  289. MTR_MEMO_X_LOCK));
  290. } else {
  291. mtr_s_lock(dict_tree_get_lock(tree), mtr);
  292. }
  293. page_cursor = btr_cur_get_page_cur(cursor);
  294. space = dict_tree_get_space(tree);
  295. page_no = dict_tree_get_page(tree);
  296. up_match = 0;
  297. up_bytes = 0;
  298. low_match = 0;
  299. low_bytes = 0;
  300. height = ULINT_UNDEFINED;
  301. rw_latch = RW_NO_LATCH;
  302. buf_mode = BUF_GET;
  303. /* We use these modified search modes on non-leaf levels of the
  304. B-tree. These let us end up in the right B-tree leaf. In that leaf
  305. we use the original search mode. */
  306. switch (mode) {
  307. case PAGE_CUR_GE:
  308. page_mode = PAGE_CUR_L;
  309. break;
  310. case PAGE_CUR_G:
  311. page_mode = PAGE_CUR_LE;
  312. break;
  313. default:
  314. ut_ad(mode == PAGE_CUR_L
  315. || mode == PAGE_CUR_LE
  316. || mode == PAGE_CUR_LE_OR_EXTENDS);
  317. page_mode = mode;
  318. break;
  319. }
  320. /* Loop and search until we arrive at the desired level */
  321. for (;;) {
  322. if ((height == 0) && (latch_mode <= BTR_MODIFY_LEAF)) {
  323. rw_latch = latch_mode;
  324. if (insert_planned && ibuf_should_try(index,
  325. ignore_sec_unique)) {
  326. /* Try insert to the insert buffer if the
  327. page is not in the buffer pool */
  328. buf_mode = BUF_GET_IF_IN_POOL;
  329. }
  330. }
  331. retry_page_get:
  332. page = buf_page_get_gen(space, page_no, rw_latch, guess,
  333. buf_mode,
  334. __FILE__, __LINE__,
  335. mtr);
  336. if (page == NULL) {
  337. /* This must be a search to perform an insert;
  338. try insert to the insert buffer */
  339. ut_ad(buf_mode == BUF_GET_IF_IN_POOL);
  340. ut_ad(insert_planned);
  341. ut_ad(cursor->thr);
  342. if (ibuf_should_try(index, ignore_sec_unique) &&
  343. ibuf_insert(tuple, index, space, page_no,
  344. cursor->thr)) {
  345. /* Insertion to the insert buffer succeeded */
  346. cursor->flag = BTR_CUR_INSERT_TO_IBUF;
  347. return;
  348. }
  349. /* Insert to the insert buffer did not succeed:
  350. retry page get */
  351. buf_mode = BUF_GET;
  352. goto retry_page_get;
  353. }
  354. buf_block_align(page)->check_index_page_at_flush = TRUE;
  355. #ifdef UNIV_SYNC_DEBUG
  356. if (rw_latch != RW_NO_LATCH) {
  357. buf_page_dbg_add_level(page, SYNC_TREE_NODE);
  358. }
  359. #endif
  360. ut_ad(0 == ut_dulint_cmp(tree->id,
  361. btr_page_get_index_id(page)));
  362. if (height == ULINT_UNDEFINED) {
  363. /* We are in the root node */
  364. height = btr_page_get_level(page, mtr);
  365. root_height = height;
  366. cursor->tree_height = root_height + 1;
  367. #ifdef BTR_CUR_ADAPT
  368. if (page != guess) {
  369. info->root_guess = page;
  370. }
  371. #endif
  372. }
  373. if (height == 0) {
  374. if (rw_latch == RW_NO_LATCH) {
  375. btr_cur_latch_leaves(page, space,
  376. page_no, latch_mode, cursor,
  377. mtr);
  378. }
  379. if ((latch_mode != BTR_MODIFY_TREE)
  380.     && (latch_mode != BTR_CONT_MODIFY_TREE)) {
  381. /* Release the tree s-latch */
  382. mtr_release_s_latch_at_savepoint(
  383. mtr, savepoint,
  384. dict_tree_get_lock(tree));
  385. }
  386. page_mode = mode;
  387. }
  388. page_cur_search_with_match(page, tuple, page_mode, &up_match,
  389. &up_bytes, &low_match, &low_bytes,
  390. page_cursor);
  391. if (estimate) {
  392. btr_cur_add_path_info(cursor, height, root_height);
  393. }
  394. /* If this is the desired level, leave the loop */
  395. ut_ad(height
  396. == btr_page_get_level(page_cur_get_page(page_cursor), mtr));
  397. if (level == height) {
  398. if (level > 0) {
  399. /* x-latch the page */
  400. btr_page_get(space, page_no, RW_X_LATCH, mtr);
  401. }
  402. break;
  403. }
  404. ut_ad(height > 0);
  405. height--;
  406. guess = NULL;
  407. node_ptr = page_cur_get_rec(page_cursor);
  408. /* Go to the child node */
  409. page_no = btr_node_ptr_get_child_page_no(node_ptr);
  410. }
  411. if (level == 0) {
  412. cursor->low_match = low_match;
  413. cursor->low_bytes = low_bytes;
  414. cursor->up_match = up_match;
  415. cursor->up_bytes = up_bytes;
  416. #ifdef BTR_CUR_ADAPT
  417. if (srv_use_adaptive_hash_indexes) {
  418. btr_search_info_update(index, cursor);
  419. }
  420. #endif
  421. ut_ad(cursor->up_match != ULINT_UNDEFINED
  422. || mode != PAGE_CUR_GE);
  423. ut_ad(cursor->up_match != ULINT_UNDEFINED
  424. || mode != PAGE_CUR_LE);
  425. ut_ad(cursor->low_match != ULINT_UNDEFINED
  426. || mode != PAGE_CUR_LE);
  427. }
  428. if (has_search_latch) {
  429. rw_lock_s_lock(&btr_search_latch);
  430. }
  431. }
  432. /*********************************************************************
  433. Opens a cursor at either end of an index. */
  434. void
  435. btr_cur_open_at_index_side(
  436. /*=======================*/
  437. ibool from_left, /* in: TRUE if open to the low end,
  438. FALSE if to the high end */
  439. dict_index_t* index, /* in: index */
  440. ulint latch_mode, /* in: latch mode */
  441. btr_cur_t* cursor, /* in: cursor */
  442. mtr_t* mtr) /* in: mtr */
  443. {
  444. page_cur_t* page_cursor;
  445. dict_tree_t* tree;
  446. page_t* page;
  447. ulint page_no;
  448. ulint space;
  449. ulint height;
  450. ulint root_height = 0; /* remove warning */
  451. rec_t* node_ptr;
  452. ulint estimate;
  453. ulint           savepoint;
  454. estimate = latch_mode & BTR_ESTIMATE;
  455. latch_mode = latch_mode & ~BTR_ESTIMATE;
  456. tree = index->tree;
  457. /* Store the position of the tree latch we push to mtr so that we
  458. know how to release it when we have latched the leaf node */
  459. savepoint = mtr_set_savepoint(mtr);
  460. if (latch_mode == BTR_MODIFY_TREE) {
  461. mtr_x_lock(dict_tree_get_lock(tree), mtr);
  462. } else {
  463. mtr_s_lock(dict_tree_get_lock(tree), mtr);
  464. }
  465. page_cursor = btr_cur_get_page_cur(cursor);
  466. cursor->index = index;
  467. space = dict_tree_get_space(tree);
  468. page_no = dict_tree_get_page(tree);
  469. height = ULINT_UNDEFINED;
  470. for (;;) {
  471. page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
  472. BUF_GET,
  473. __FILE__, __LINE__,
  474. mtr);
  475. ut_ad(0 == ut_dulint_cmp(tree->id,
  476. btr_page_get_index_id(page)));
  477. buf_block_align(page)->check_index_page_at_flush = TRUE;
  478. if (height == ULINT_UNDEFINED) {
  479. /* We are in the root node */
  480. height = btr_page_get_level(page, mtr);
  481. root_height = height;
  482. }
  483. if (height == 0) {
  484. btr_cur_latch_leaves(page, space, page_no,
  485. latch_mode, cursor, mtr);
  486. /* In versions <= 3.23.52 we had forgotten to
  487. release the tree latch here. If in an index scan
  488. we had to scan far to find a record visible to the
  489. current transaction, that could starve others
  490. waiting for the tree latch. */
  491.  
  492. if ((latch_mode != BTR_MODIFY_TREE)
  493.     && (latch_mode != BTR_CONT_MODIFY_TREE)) {
  494. /* Release the tree s-latch */
  495. mtr_release_s_latch_at_savepoint(
  496. mtr, savepoint,
  497. dict_tree_get_lock(tree));
  498. }
  499. }
  500. if (from_left) {
  501. page_cur_set_before_first(page, page_cursor);
  502. } else {
  503. page_cur_set_after_last(page, page_cursor);
  504. }
  505. if (height == 0) {
  506.         if (estimate) {
  507.         btr_cur_add_path_info(cursor, height,
  508.       root_height);
  509.         }
  510. break;
  511. }
  512. ut_ad(height > 0);
  513. if (from_left) {
  514. page_cur_move_to_next(page_cursor);
  515. } else {
  516. page_cur_move_to_prev(page_cursor);
  517. }
  518. if (estimate) {
  519. btr_cur_add_path_info(cursor, height, root_height);
  520. }
  521. height--;
  522. node_ptr = page_cur_get_rec(page_cursor);
  523. /* Go to the child node */
  524. page_no = btr_node_ptr_get_child_page_no(node_ptr);
  525. }
  526. }
  527. /**************************************************************************
  528. Positions a cursor at a randomly chosen position within a B-tree. */
  529. void
  530. btr_cur_open_at_rnd_pos(
  531. /*====================*/
  532. dict_index_t* index, /* in: index */
  533. ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
  534. btr_cur_t* cursor, /* in/out: B-tree cursor */
  535. mtr_t* mtr) /* in: mtr */
  536. {
  537. page_cur_t* page_cursor;
  538. dict_tree_t* tree;
  539. page_t* page;
  540. ulint page_no;
  541. ulint space;
  542. ulint height;
  543. rec_t* node_ptr;
  544. tree = index->tree;
  545. if (latch_mode == BTR_MODIFY_TREE) {
  546. mtr_x_lock(dict_tree_get_lock(tree), mtr);
  547. } else {
  548. mtr_s_lock(dict_tree_get_lock(tree), mtr);
  549. }
  550. page_cursor = btr_cur_get_page_cur(cursor);
  551. cursor->index = index;
  552. space = dict_tree_get_space(tree);
  553. page_no = dict_tree_get_page(tree);
  554. height = ULINT_UNDEFINED;
  555. for (;;) {
  556. page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
  557. BUF_GET,
  558. __FILE__, __LINE__,
  559. mtr);
  560. ut_ad(0 == ut_dulint_cmp(tree->id,
  561. btr_page_get_index_id(page)));
  562. if (height == ULINT_UNDEFINED) {
  563. /* We are in the root node */
  564. height = btr_page_get_level(page, mtr);
  565. }
  566. if (height == 0) {
  567. btr_cur_latch_leaves(page, space, page_no,
  568. latch_mode, cursor, mtr);
  569. }
  570. page_cur_open_on_rnd_user_rec(page, page_cursor);
  571. if (height == 0) {
  572. break;
  573. }
  574. ut_ad(height > 0);
  575. height--;
  576. node_ptr = page_cur_get_rec(page_cursor);
  577. /* Go to the child node */
  578. page_no = btr_node_ptr_get_child_page_no(node_ptr);
  579. }
  580. }
  581. /*==================== B-TREE INSERT =========================*/
  582. /*****************************************************************
  583. Inserts a record if there is enough space, or if enough space can
  584. be freed by reorganizing. Differs from _optimistic_insert because
  585. no heuristics is applied to whether it pays to use CPU time for
  586. reorganizing the page or not. */
  587. static
  588. rec_t*
  589. btr_cur_insert_if_possible(
  590. /*=======================*/
  591. /* out: pointer to inserted record if succeed,
  592. else NULL */
  593. btr_cur_t* cursor, /* in: cursor on page after which to insert;
  594. cursor stays valid */
  595. dtuple_t* tuple, /* in: tuple to insert; the size info need not
  596. have been stored to tuple */
  597. ibool* reorg, /* out: TRUE if reorganization occurred */
  598. mtr_t* mtr) /* in: mtr */
  599. {
  600. page_cur_t* page_cursor;
  601. page_t* page;
  602. rec_t* rec;
  603. ut_ad(dtuple_check_typed(tuple));
  604. *reorg = FALSE;
  605. page = btr_cur_get_page(cursor);
  606. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  607. MTR_MEMO_PAGE_X_FIX));
  608. page_cursor = btr_cur_get_page_cur(cursor);
  609. /* Now, try the insert */
  610. rec = page_cur_tuple_insert(page_cursor, tuple, mtr);
  611. if (!rec) {
  612. /* If record did not fit, reorganize */
  613. btr_page_reorganize(page, mtr);
  614. *reorg = TRUE;
  615. page_cur_search(page, tuple, PAGE_CUR_LE, page_cursor);
  616. rec = page_cur_tuple_insert(page_cursor, tuple, mtr);
  617. }
  618. return(rec);
  619. }
  620. /*****************************************************************
  621. For an insert, checks the locks and does the undo logging if desired. */
  622. UNIV_INLINE
  623. ulint
  624. btr_cur_ins_lock_and_undo(
  625. /*======================*/
  626. /* out: DB_SUCCESS, DB_WAIT_LOCK,
  627. DB_FAIL, or error number */
  628. ulint flags, /* in: undo logging and locking flags: if
  629. not zero, the parameters index and thr
  630. should be specified */
  631. btr_cur_t* cursor, /* in: cursor on page after which to insert */
  632. dtuple_t* entry, /* in: entry to insert */
  633. que_thr_t* thr, /* in: query thread or NULL */
  634. ibool* inherit)/* out: TRUE if the inserted new record maybe
  635. should inherit LOCK_GAP type locks from the
  636. successor record */
  637. {
  638. dict_index_t* index;
  639. ulint err;
  640. rec_t* rec;
  641. dulint roll_ptr;
  642. /* Check if we have to wait for a lock: enqueue an explicit lock
  643. request if yes */
  644. rec = btr_cur_get_rec(cursor);
  645. index = cursor->index;
  646. err = lock_rec_insert_check_and_lock(flags, rec, index, thr, inherit);
  647. if (err != DB_SUCCESS) {
  648. return(err);
  649. }
  650. if ((index->type & DICT_CLUSTERED) && !(index->type & DICT_IBUF)) {
  651. err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP,
  652. thr, index, entry, NULL, 0, NULL,
  653. &roll_ptr);
  654. if (err != DB_SUCCESS) {
  655. return(err);
  656. }
  657. /* Now we can fill in the roll ptr field in entry */
  658. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  659. row_upd_index_entry_sys_field(entry, index,
  660. DATA_ROLL_PTR, roll_ptr);
  661. }
  662. }
  663. return(DB_SUCCESS);
  664. }
  665. /*****************************************************************
  666. Report information about a transaction. */
  667. static
  668. void
  669. btr_cur_trx_report(
  670. /*===============*/
  671. trx_t* trx, /* in: transaction */
  672. const dict_index_t* index, /* in: index */
  673. const char* op) /* in: operation */
  674. {
  675. fprintf(stderr, "Trx with id %lu %lu going to ",
  676. ut_dulint_get_high(trx->id),
  677. ut_dulint_get_low(trx->id));
  678. fputs(op, stderr);
  679. dict_index_name_print(stderr, trx, index);
  680. putc('n', stderr);
  681. }
  682. /*****************************************************************
  683. Tries to perform an insert to a page in an index tree, next to cursor.
  684. It is assumed that mtr holds an x-latch on the page. The operation does
  685. not succeed if there is too little space on the page. If there is just
  686. one record on the page, the insert will always succeed; this is to
  687. prevent trying to split a page with just one record. */
  688. ulint
  689. btr_cur_optimistic_insert(
  690. /*======================*/
  691. /* out: DB_SUCCESS, DB_WAIT_LOCK,
  692. DB_FAIL, or error number */
  693. ulint flags, /* in: undo logging and locking flags: if not
  694. zero, the parameters index and thr should be
  695. specified */
  696. btr_cur_t* cursor, /* in: cursor on page after which to insert;
  697. cursor stays valid */
  698. dtuple_t* entry, /* in: entry to insert */
  699. rec_t** rec, /* out: pointer to inserted record if
  700. succeed */
  701. big_rec_t** big_rec,/* out: big rec vector whose fields have to
  702. be stored externally by the caller, or
  703. NULL */
  704. que_thr_t* thr, /* in: query thread or NULL */
  705. mtr_t* mtr) /* in: mtr */
  706. {
  707. big_rec_t* big_rec_vec = NULL;
  708. dict_index_t* index;
  709. page_cur_t* page_cursor;
  710. page_t* page;
  711. ulint max_size;
  712. rec_t* dummy_rec;
  713. ulint level;
  714. ibool reorg;
  715. ibool inherit;
  716. ulint rec_size;
  717. ulint data_size;
  718. ulint extra_size;
  719. ulint type;
  720. ulint err;
  721. *big_rec = NULL;
  722. page = btr_cur_get_page(cursor);
  723. index = cursor->index;
  724. if (!dtuple_check_typed_no_assert(entry)) {
  725. fputs("InnoDB: Error in a tuple to insert into ", stderr);
  726. dict_index_name_print(stderr, thr_get_trx(thr), index);
  727. }
  728. if (btr_cur_print_record_ops && thr) {
  729. btr_cur_trx_report(thr_get_trx(thr), index, "insert into ");
  730. dtuple_print(stderr, entry);
  731. }
  732. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  733. MTR_MEMO_PAGE_X_FIX));
  734. max_size = page_get_max_insert_size_after_reorganize(page, 1);
  735. level = btr_page_get_level(page, mtr);
  736. calculate_sizes_again:
  737. /* Calculate the record size when entry is converted to a record */
  738. data_size = dtuple_get_data_size(entry);
  739. extra_size = rec_get_converted_extra_size(data_size,
  740. dtuple_get_n_fields(entry));
  741. rec_size = data_size + extra_size;
  742. if ((rec_size >= page_get_free_space_of_empty() / 2)
  743.     || (rec_size >= REC_MAX_DATA_SIZE)) {
  744. /* The record is so big that we have to store some fields
  745. externally on separate database pages */
  746.                 big_rec_vec = dtuple_convert_big_rec(index, entry, NULL, 0);
  747. if (big_rec_vec == NULL) {
  748. return(DB_TOO_BIG_RECORD);
  749. }
  750. goto calculate_sizes_again;
  751. }
  752. /* If there have been many consecutive inserts, and we are on the leaf
  753. level, check if we have to split the page to reserve enough free space
  754. for future updates of records. */
  755. type = index->type;
  756. if ((type & DICT_CLUSTERED)
  757.     && (dict_tree_get_space_reserve(index->tree) + rec_size > max_size)
  758.     && (page_get_n_recs(page) >= 2)
  759.     && (0 == level)
  760.     && (btr_page_get_split_rec_to_right(cursor, &dummy_rec)
  761.         || btr_page_get_split_rec_to_left(cursor, &dummy_rec))) {
  762.         if (big_rec_vec) {
  763. dtuple_convert_back_big_rec(index, entry, big_rec_vec);
  764. }
  765. return(DB_FAIL);
  766. }
  767. if (!(((max_size >= rec_size)
  768.        && (max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT))
  769.       || (page_get_max_insert_size(page, 1) >= rec_size)
  770.       || (page_get_n_recs(page) <= 1))) {
  771.         if (big_rec_vec) {
  772. dtuple_convert_back_big_rec(index, entry, big_rec_vec);
  773. }
  774. return(DB_FAIL);
  775. }
  776.         /* Check locks and write to the undo log, if specified */
  777.         err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &inherit);
  778. if (err != DB_SUCCESS) {
  779.         if (big_rec_vec) {
  780. dtuple_convert_back_big_rec(index, entry, big_rec_vec);
  781. }
  782. return(err);
  783. }
  784. page_cursor = btr_cur_get_page_cur(cursor);
  785. reorg = FALSE;
  786. /* Now, try the insert */
  787. *rec = page_cur_insert_rec_low(page_cursor, entry, data_size,
  788. NULL, mtr);
  789. if (!(*rec)) {
  790. /* If the record did not fit, reorganize */
  791. btr_page_reorganize(page, mtr);
  792. ut_ad(page_get_max_insert_size(page, 1) == max_size);
  793. reorg = TRUE;
  794. page_cur_search(page, entry, PAGE_CUR_LE, page_cursor);
  795. *rec = page_cur_tuple_insert(page_cursor, entry, mtr);
  796. if (!*rec) {
  797. fputs("InnoDB: Error: cannot insert tuple ", stderr);
  798. dtuple_print(stderr, entry);
  799. fputs(" into ", stderr);
  800. dict_index_name_print(stderr, thr_get_trx(thr), index);
  801. fprintf(stderr, "nInnoDB: max insert size %lun",
  802. (ulong) max_size);
  803. ut_error;
  804. }
  805. }
  806. #ifdef BTR_CUR_HASH_ADAPT
  807. if (!reorg && (0 == level) && (cursor->flag == BTR_CUR_HASH)) {
  808. btr_search_update_hash_node_on_insert(cursor);
  809. } else {
  810. btr_search_update_hash_on_insert(cursor);
  811. }
  812. #endif
  813. if (!(flags & BTR_NO_LOCKING_FLAG) && inherit) {
  814. lock_update_insert(*rec);
  815. }
  816. /* fprintf(stderr, "Insert into page %lu, max ins size %lu,"
  817. " rec %lu ind type %lun",
  818. buf_frame_get_page_no(page), max_size,
  819. rec_size + PAGE_DIR_SLOT_SIZE, type);
  820. */
  821. if (!(type & DICT_CLUSTERED)) {
  822. /* We have added a record to page: update its free bits */
  823. ibuf_update_free_bits_if_full(cursor->index, page, max_size,
  824. rec_size + PAGE_DIR_SLOT_SIZE);
  825. }
  826. *big_rec = big_rec_vec;
  827. return(DB_SUCCESS);
  828. }
  829. /*****************************************************************
  830. Performs an insert on a page of an index tree. It is assumed that mtr
  831. holds an x-latch on the tree and on the cursor page. If the insert is
  832. made on the leaf level, to avoid deadlocks, mtr must also own x-latches
  833. to brothers of page, if those brothers exist. */
  834. ulint
  835. btr_cur_pessimistic_insert(
  836. /*=======================*/
  837. /* out: DB_SUCCESS or error number */
  838. ulint flags, /* in: undo logging and locking flags: if not
  839. zero, the parameter thr should be
  840. specified; if no undo logging is specified,
  841. then the caller must have reserved enough
  842. free extents in the file space so that the
  843. insertion will certainly succeed */
  844. btr_cur_t* cursor, /* in: cursor after which to insert;
  845. cursor stays valid */
  846. dtuple_t* entry, /* in: entry to insert */
  847. rec_t** rec, /* out: pointer to inserted record if
  848. succeed */
  849. big_rec_t** big_rec,/* out: big rec vector whose fields have to
  850. be stored externally by the caller, or
  851. NULL */
  852. que_thr_t* thr, /* in: query thread or NULL */
  853. mtr_t* mtr) /* in: mtr */
  854. {
  855. dict_index_t* index = cursor->index;
  856. big_rec_t* big_rec_vec = NULL;
  857. page_t* page;
  858. ulint err;
  859. ibool dummy_inh;
  860. ibool success;
  861. ulint n_extents = 0;
  862. ulint n_reserved;
  863. ut_ad(dtuple_check_typed(entry));
  864. *big_rec = NULL;
  865. page = btr_cur_get_page(cursor);
  866. ut_ad(mtr_memo_contains(mtr,
  867. dict_tree_get_lock(btr_cur_get_tree(cursor)),
  868. MTR_MEMO_X_LOCK));
  869. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  870. MTR_MEMO_PAGE_X_FIX));
  871. /* Try first an optimistic insert; reset the cursor flag: we do not
  872. assume anything of how it was positioned */
  873. cursor->flag = BTR_CUR_BINARY;
  874. err = btr_cur_optimistic_insert(flags, cursor, entry, rec, big_rec,
  875. thr, mtr);
  876. if (err != DB_FAIL) {
  877. return(err);
  878. }
  879. /* Retry with a pessimistic insert. Check locks and write to undo log,
  880. if specified */
  881. err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &dummy_inh);
  882. if (err != DB_SUCCESS) {
  883. return(err);
  884. }
  885. if (!(flags & BTR_NO_UNDO_LOG_FLAG)) {
  886. /* First reserve enough free space for the file segments
  887. of the index tree, so that the insert will not fail because
  888. of lack of space */
  889. n_extents = cursor->tree_height / 16 + 3;
  890. success = fsp_reserve_free_extents(&n_reserved, index->space,
  891. n_extents, FSP_NORMAL, mtr);
  892. if (!success) {
  893. err = DB_OUT_OF_FILE_SPACE;
  894. return(err);
  895. }
  896. }
  897. if ((rec_get_converted_size(entry)
  898. >= page_get_free_space_of_empty() / 2)
  899.     || (rec_get_converted_size(entry) >= REC_MAX_DATA_SIZE)) {
  900. /* The record is so big that we have to store some fields
  901. externally on separate database pages */
  902.                 big_rec_vec = dtuple_convert_big_rec(index, entry, NULL, 0);
  903. if (big_rec_vec == NULL) {
  904. if (n_extents > 0) {
  905.         fil_space_release_free_extents(index->space,
  906. n_reserved);
  907. }
  908. return(DB_TOO_BIG_RECORD);
  909. }
  910. }
  911. if (dict_tree_get_page(index->tree)
  912. == buf_frame_get_page_no(page)) {
  913. /* The page is the root page */
  914. *rec = btr_root_raise_and_insert(cursor, entry, mtr);
  915. } else {
  916. *rec = btr_page_split_and_insert(cursor, entry, mtr);
  917. }
  918. btr_cur_position(index, page_rec_get_prev(*rec), cursor);
  919. #ifdef BTR_CUR_ADAPT
  920. btr_search_update_hash_on_insert(cursor);
  921. #endif
  922. if (!(flags & BTR_NO_LOCKING_FLAG)) {
  923. lock_update_insert(*rec);
  924. }
  925. err = DB_SUCCESS;
  926. if (n_extents > 0) {
  927. fil_space_release_free_extents(index->space, n_reserved);
  928. }
  929. *big_rec = big_rec_vec;
  930. return(err);
  931. }
  932. /*==================== B-TREE UPDATE =========================*/
  933. /*****************************************************************
  934. For an update, checks the locks and does the undo logging. */
  935. UNIV_INLINE
  936. ulint
  937. btr_cur_upd_lock_and_undo(
  938. /*======================*/
  939. /* out: DB_SUCCESS, DB_WAIT_LOCK, or error
  940. number */
  941. ulint flags, /* in: undo logging and locking flags */
  942. btr_cur_t* cursor, /* in: cursor on record to update */
  943. upd_t* update, /* in: update vector */
  944. ulint cmpl_info,/* in: compiler info on secondary index
  945. updates */
  946. que_thr_t* thr, /* in: query thread */
  947. dulint* roll_ptr)/* out: roll pointer */
  948. {
  949. dict_index_t* index;
  950. rec_t* rec;
  951. ulint err;
  952. ut_ad(cursor && update && thr && roll_ptr);
  953. rec = btr_cur_get_rec(cursor);
  954. index = cursor->index;
  955. if (!(index->type & DICT_CLUSTERED)) {
  956. /* We do undo logging only when we update a clustered index
  957. record */
  958. return(lock_sec_rec_modify_check_and_lock(flags, rec, index,
  959. thr));
  960. }
  961. /* Check if we have to wait for a lock: enqueue an explicit lock
  962. request if yes */
  963. err = DB_SUCCESS;
  964. if (!(flags & BTR_NO_LOCKING_FLAG)) {
  965. err = lock_clust_rec_modify_check_and_lock(flags, rec, index,
  966. thr);
  967. if (err != DB_SUCCESS) {
  968. return(err);
  969. }
  970. }
  971. /* Append the info about the update in the undo log */
  972. err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
  973. index, NULL, update,
  974. cmpl_info, rec, roll_ptr);
  975. return(err);
  976. }
  977. /***************************************************************
  978. Writes a redo log record of updating a record in-place. */
  979. UNIV_INLINE
  980. void
  981. btr_cur_update_in_place_log(
  982. /*========================*/
  983. ulint flags, /* in: flags */
  984. rec_t* rec, /* in: record */
  985. dict_index_t* index, /* in: index where cursor positioned */
  986. upd_t* update, /* in: update vector */
  987. trx_t* trx, /* in: transaction */
  988. dulint roll_ptr, /* in: roll ptr */
  989. mtr_t* mtr) /* in: mtr */
  990. {
  991. byte* log_ptr;
  992. log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN);
  993. log_ptr = mlog_write_initial_log_record_fast(rec,
  994. MLOG_REC_UPDATE_IN_PLACE, log_ptr, mtr);
  995. mach_write_to_1(log_ptr, flags);
  996. log_ptr++;
  997. /* The code below assumes index is a clustered index: change index to
  998. the clustered index if we are updating a secondary index record (or we
  999. could as well skip writing the sys col values to the log in this case
  1000. because they are not needed for a secondary index record update) */
  1001. index = dict_table_get_first_index(index->table);
  1002. log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
  1003. mtr);
  1004. mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
  1005. log_ptr += 2;
  1006. row_upd_index_write_log(update, log_ptr, mtr);
  1007. }
  1008. /***************************************************************
  1009. Parses a redo log record of updating a record in-place. */
  1010. byte*
  1011. btr_cur_parse_update_in_place(
  1012. /*==========================*/
  1013. /* out: end of log record or NULL */
  1014. byte* ptr, /* in: buffer */
  1015. byte* end_ptr,/* in: buffer end */
  1016. page_t* page) /* in: page or NULL */
  1017. {
  1018. ulint flags;
  1019. rec_t* rec;
  1020. upd_t* update;
  1021. ulint pos;
  1022. dulint trx_id;
  1023. dulint roll_ptr;
  1024. ulint rec_offset;
  1025. mem_heap_t* heap;
  1026. if (end_ptr < ptr + 1) {
  1027. return(NULL);
  1028. }
  1029. flags = mach_read_from_1(ptr);
  1030. ptr++;
  1031. ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr);
  1032. if (ptr == NULL) {
  1033. return(NULL);
  1034. }
  1035. if (end_ptr < ptr + 2) {
  1036. return(NULL);
  1037. }
  1038. rec_offset = mach_read_from_2(ptr);
  1039. ptr += 2;
  1040. ut_a(rec_offset <= UNIV_PAGE_SIZE);
  1041. heap = mem_heap_create(256);
  1042. ptr = row_upd_index_parse(ptr, end_ptr, heap, &update);
  1043. if (ptr == NULL) {
  1044. mem_heap_free(heap);
  1045. return(NULL);
  1046. }
  1047. if (!page) {
  1048. mem_heap_free(heap);
  1049. return(ptr);
  1050. }
  1051. rec = page + rec_offset;
  1052. /* We do not need to reserve btr_search_latch, as the page is only
  1053. being recovered, and there cannot be a hash index to it. */
  1054. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  1055. row_upd_rec_sys_fields_in_recovery(rec, pos, trx_id, roll_ptr);
  1056. }
  1057. row_upd_rec_in_place(rec, update);
  1058. mem_heap_free(heap);
  1059. return(ptr);
  1060. }
  1061. /*****************************************************************
  1062. Updates a record when the update causes no size changes in its fields.
  1063. We assume here that the ordering fields of the record do not change. */
  1064. ulint
  1065. btr_cur_update_in_place(
  1066. /*====================*/
  1067. /* out: DB_SUCCESS or error number */
  1068. ulint flags, /* in: undo logging and locking flags */
  1069. btr_cur_t* cursor, /* in: cursor on the record to update;
  1070. cursor stays valid and positioned on the
  1071. same record */
  1072. upd_t* update, /* in: update vector */
  1073. ulint cmpl_info,/* in: compiler info on secondary index
  1074. updates */
  1075. que_thr_t* thr, /* in: query thread */
  1076. mtr_t* mtr) /* in: mtr */
  1077. {
  1078. dict_index_t* index;
  1079. buf_block_t* block;
  1080. ulint err;
  1081. rec_t* rec;
  1082. dulint roll_ptr = ut_dulint_zero;
  1083. trx_t* trx;
  1084. ibool was_delete_marked;
  1085. rec = btr_cur_get_rec(cursor);
  1086. index = cursor->index;
  1087. trx = thr_get_trx(thr);
  1088. if (btr_cur_print_record_ops && thr) {
  1089. btr_cur_trx_report(trx, index, "update ");
  1090. rec_print(stderr, rec);
  1091. }
  1092. /* Do lock checking and undo logging */
  1093. err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
  1094. thr, &roll_ptr);
  1095. if (err != DB_SUCCESS) {
  1096. return(err);
  1097. }
  1098. block = buf_block_align(rec);
  1099. if (block->is_hashed) {
  1100. /* The function row_upd_changes_ord_field_binary works only
  1101. if the update vector was built for a clustered index, we must
  1102. NOT call it if index is secondary */
  1103.         if (!(index->type & DICT_CLUSTERED)
  1104.     || row_upd_changes_ord_field_binary(NULL, index, update)) {
  1105.         /* Remove possible hash index pointer to this record */
  1106.                 btr_search_update_hash_on_delete(cursor);
  1107.         }
  1108. rw_lock_x_lock(&btr_search_latch);
  1109. }
  1110. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  1111. row_upd_rec_sys_fields(rec, index, trx, roll_ptr);
  1112. }
  1113. /* FIXME: in a mixed tree, all records may not have enough ordering
  1114. fields for btr search: */
  1115. was_delete_marked = rec_get_deleted_flag(rec);
  1116. row_upd_rec_in_place(rec, update);
  1117. if (block->is_hashed) {
  1118. rw_lock_x_unlock(&btr_search_latch);
  1119. }
  1120. btr_cur_update_in_place_log(flags, rec, index, update, trx, roll_ptr,
  1121. mtr);
  1122. if (was_delete_marked && !rec_get_deleted_flag(rec)) {
  1123. /* The new updated record owns its possible externally
  1124. stored fields */
  1125. btr_cur_unmark_extern_fields(rec, mtr);
  1126. }
  1127. return(DB_SUCCESS);
  1128. }
  1129. /*****************************************************************
  1130. Tries to update a record on a page in an index tree. It is assumed that mtr
  1131. holds an x-latch on the page. The operation does not succeed if there is too
  1132. little space on the page or if the update would result in too empty a page,
  1133. so that tree compression is recommended. We assume here that the ordering
  1134. fields of the record do not change. */
  1135. ulint
  1136. btr_cur_optimistic_update(
  1137. /*======================*/
  1138. /* out: DB_SUCCESS, or DB_OVERFLOW if the
  1139. updated record does not fit, DB_UNDERFLOW
  1140. if the page would become too empty */
  1141. ulint flags, /* in: undo logging and locking flags */
  1142. btr_cur_t* cursor, /* in: cursor on the record to update;
  1143. cursor stays valid and positioned on the
  1144. same record */
  1145. upd_t* update, /* in: update vector; this must also
  1146. contain trx id and roll ptr fields */
  1147. ulint cmpl_info,/* in: compiler info on secondary index
  1148. updates */
  1149. que_thr_t* thr, /* in: query thread */
  1150. mtr_t* mtr) /* in: mtr */
  1151. {
  1152. dict_index_t* index;
  1153. page_cur_t* page_cursor;
  1154. ulint err;
  1155. page_t* page;
  1156. rec_t* rec;
  1157. ulint max_size;
  1158. ulint new_rec_size;
  1159. ulint old_rec_size;
  1160. dtuple_t* new_entry;
  1161. dulint roll_ptr;
  1162. trx_t* trx;
  1163. mem_heap_t* heap;
  1164. ibool reorganized = FALSE;
  1165. ulint i;
  1166. page = btr_cur_get_page(cursor);
  1167. rec = btr_cur_get_rec(cursor);
  1168. index = cursor->index;
  1169. if (btr_cur_print_record_ops && thr) {
  1170. btr_cur_trx_report(thr_get_trx(thr), index, "update ");
  1171. rec_print(stderr, rec);
  1172. }
  1173. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  1174. MTR_MEMO_PAGE_X_FIX));
  1175. if (!row_upd_changes_field_size_or_external(rec, index, update)) {
  1176. /* The simplest and the most common case: the update does not
  1177. change the size of any field and none of the updated fields is
  1178. externally stored in rec or update */
  1179. return(btr_cur_update_in_place(flags, cursor, update,
  1180. cmpl_info, thr, mtr));
  1181. }
  1182. for (i = 0; i < upd_get_n_fields(update); i++) {
  1183. if (upd_get_nth_field(update, i)->extern_storage) {
  1184. /* Externally stored fields are treated in pessimistic
  1185. update */
  1186. return(DB_OVERFLOW);
  1187. }
  1188. }
  1189. if (rec_contains_externally_stored_field(btr_cur_get_rec(cursor))) {
  1190. /* Externally stored fields are treated in pessimistic
  1191. update */
  1192. return(DB_OVERFLOW);
  1193. }
  1194. page_cursor = btr_cur_get_page_cur(cursor);
  1195. heap = mem_heap_create(1024);
  1196. new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
  1197. row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
  1198. NULL);
  1199. old_rec_size = rec_get_size(rec);
  1200. new_rec_size = rec_get_converted_size(new_entry);
  1201. if (new_rec_size >= page_get_free_space_of_empty() / 2) {
  1202. mem_heap_free(heap);
  1203. return(DB_OVERFLOW);
  1204. }
  1205. max_size = old_rec_size
  1206. + page_get_max_insert_size_after_reorganize(page, 1);
  1207. if (page_get_data_size(page) - old_rec_size + new_rec_size
  1208. < BTR_CUR_PAGE_COMPRESS_LIMIT) {
  1209. /* The page would become too empty */
  1210. mem_heap_free(heap);
  1211. return(DB_UNDERFLOW);
  1212. }
  1213. if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)
  1214.         && (max_size >= new_rec_size))
  1215.       || (page_get_n_recs(page) <= 1))) {
  1216. /* There was not enough space, or it did not pay to
  1217. reorganize: for simplicity, we decide what to do assuming a
  1218. reorganization is needed, though it might not be necessary */
  1219. mem_heap_free(heap);
  1220. return(DB_OVERFLOW);
  1221. }
  1222. /* Do lock checking and undo logging */
  1223. err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, thr,
  1224. &roll_ptr);
  1225. if (err != DB_SUCCESS) {
  1226. mem_heap_free(heap);
  1227. return(err);
  1228. }
  1229.         
  1230.         /* Ok, we may do the replacement. Store on the page infimum the
  1231. explicit locks on rec, before deleting rec (see the comment in
  1232. .._pessimistic_update). */
  1233. lock_rec_store_on_page_infimum(rec);
  1234. btr_search_update_hash_on_delete(cursor);
  1235.         page_cur_delete_rec(page_cursor, mtr);
  1236. page_cur_move_to_prev(page_cursor);
  1237.         
  1238. trx = thr_get_trx(thr);
  1239. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  1240. row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
  1241. roll_ptr);
  1242. row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
  1243. trx->id);
  1244. }
  1245. rec = btr_cur_insert_if_possible(cursor, new_entry, &reorganized, mtr);
  1246. ut_a(rec); /* <- We calculated above the insert would fit */
  1247. if (!rec_get_deleted_flag(rec)) {
  1248. /* The new inserted record owns its possible externally
  1249. stored fields */
  1250. btr_cur_unmark_extern_fields(rec, mtr);
  1251. }
  1252. /* Restore the old explicit lock state on the record */
  1253. lock_rec_restore_from_page_infimum(rec, page);
  1254.         page_cur_move_to_next(page_cursor);
  1255. mem_heap_free(heap);
  1256. return(DB_SUCCESS);
  1257. }
  1258. /*****************************************************************
  1259. If, in a split, a new supremum record was created as the predecessor of the
  1260. updated record, the supremum record must inherit exactly the locks on the
  1261. updated record. In the split it may have inherited locks from the successor
  1262. of the updated record, which is not correct. This function restores the
  1263. right locks for the new supremum. */
  1264. static
  1265. void
  1266. btr_cur_pess_upd_restore_supremum(
  1267. /*==============================*/
  1268. rec_t* rec, /* in: updated record */
  1269. mtr_t* mtr) /* in: mtr */
  1270. {
  1271. page_t* page;
  1272. page_t* prev_page;
  1273. ulint space;
  1274. ulint prev_page_no;
  1275. page = buf_frame_align(rec);
  1276. if (page_rec_get_next(page_get_infimum_rec(page)) != rec) {
  1277. /* Updated record is not the first user record on its page */ 
  1278. return;
  1279. }
  1280. space = buf_frame_get_space_id(page);
  1281. prev_page_no = btr_page_get_prev(page, mtr);
  1282. ut_ad(prev_page_no != FIL_NULL);
  1283. prev_page = buf_page_get_with_no_latch(space, prev_page_no, mtr);
  1284. /* We must already have an x-latch to prev_page! */
  1285. ut_ad(mtr_memo_contains(mtr, buf_block_align(prev_page),
  1286.        MTR_MEMO_PAGE_X_FIX));
  1287. lock_rec_reset_and_inherit_gap_locks(page_get_supremum_rec(prev_page),
  1288. rec);
  1289. }
  1290. /*****************************************************************
  1291. Performs an update of a record on a page of a tree. It is assumed
  1292. that mtr holds an x-latch on the tree and on the cursor page. If the
  1293. update is made on the leaf level, to avoid deadlocks, mtr must also
  1294. own x-latches to brothers of page, if those brothers exist. We assume
  1295. here that the ordering fields of the record do not change. */
  1296. ulint
  1297. btr_cur_pessimistic_update(
  1298. /*=======================*/
  1299. /* out: DB_SUCCESS or error code */
  1300. ulint flags, /* in: undo logging, locking, and rollback
  1301. flags */
  1302. btr_cur_t* cursor, /* in: cursor on the record to update */
  1303. big_rec_t** big_rec,/* out: big rec vector whose fields have to
  1304. be stored externally by the caller, or NULL */
  1305. upd_t* update, /* in: update vector; this is allowed also
  1306. contain trx id and roll ptr fields, but
  1307. the values in update vector have no effect */
  1308. ulint cmpl_info,/* in: compiler info on secondary index
  1309. updates */
  1310. que_thr_t* thr, /* in: query thread */
  1311. mtr_t* mtr) /* in: mtr */
  1312. {
  1313. big_rec_t* big_rec_vec = NULL;
  1314. big_rec_t* dummy_big_rec;
  1315. dict_index_t* index;
  1316. page_t* page;
  1317. dict_tree_t* tree;
  1318. rec_t* rec;
  1319. page_cur_t* page_cursor;
  1320. dtuple_t* new_entry;
  1321. mem_heap_t* heap;
  1322. ulint err;
  1323. ulint optim_err;
  1324. ibool dummy_reorganized;
  1325. dulint roll_ptr;
  1326. trx_t* trx;
  1327. ibool was_first;
  1328. ibool success;
  1329. ulint n_extents = 0;
  1330. ulint n_reserved;
  1331. ulint* ext_vect;
  1332. ulint n_ext_vect;
  1333. ulint reserve_flag;
  1334. *big_rec = NULL;
  1335. page = btr_cur_get_page(cursor);
  1336. rec = btr_cur_get_rec(cursor);
  1337. index = cursor->index;
  1338. tree = index->tree;
  1339. ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
  1340. MTR_MEMO_X_LOCK));
  1341. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  1342. MTR_MEMO_PAGE_X_FIX));
  1343. optim_err = btr_cur_optimistic_update(flags, cursor, update,
  1344. cmpl_info, thr, mtr);
  1345. if (optim_err != DB_UNDERFLOW && optim_err != DB_OVERFLOW) {
  1346. return(optim_err);
  1347. }
  1348. /* Do lock checking and undo logging */
  1349. err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
  1350. thr, &roll_ptr);
  1351. if (err != DB_SUCCESS) {
  1352. return(err);
  1353. }
  1354. if (optim_err == DB_OVERFLOW) {
  1355. /* First reserve enough free space for the file segments
  1356. of the index tree, so that the update will not fail because
  1357. of lack of space */
  1358. n_extents = cursor->tree_height / 16 + 3;
  1359. if (flags & BTR_NO_UNDO_LOG_FLAG) {
  1360. reserve_flag = FSP_CLEANING;
  1361. } else {
  1362. reserve_flag = FSP_NORMAL;
  1363. }
  1364. success = fsp_reserve_free_extents(&n_reserved,
  1365. cursor->index->space,
  1366. n_extents, reserve_flag, mtr);
  1367. if (!success) {
  1368. err = DB_OUT_OF_FILE_SPACE;
  1369. return(err);
  1370. }
  1371. }
  1372. heap = mem_heap_create(1024);
  1373. trx = thr_get_trx(thr);
  1374. new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
  1375. row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
  1376. heap);
  1377. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  1378. row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
  1379. roll_ptr);
  1380. row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
  1381. trx->id);
  1382. }
  1383. if (flags & BTR_NO_UNDO_LOG_FLAG) {
  1384. /* We are in a transaction rollback undoing a row
  1385. update: we must free possible externally stored fields
  1386. which got new values in the update, if they are not
  1387. inherited values. They can be inherited if we have
  1388. updated the primary key to another value, and then
  1389. update it back again. */
  1390. ut_a(big_rec_vec == NULL);
  1391. btr_rec_free_updated_extern_fields(index, rec, update,
  1392.   TRUE, mtr);
  1393. }
  1394. /* We have to set appropriate extern storage bits in the new
  1395. record to be inserted: we have to remember which fields were such */
  1396. ext_vect = mem_heap_alloc(heap, sizeof(ulint) * rec_get_n_fields(rec));
  1397. n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, update);
  1398. if ((rec_get_converted_size(new_entry) >=
  1399. page_get_free_space_of_empty() / 2)
  1400.     || (rec_get_converted_size(new_entry) >= REC_MAX_DATA_SIZE)) {
  1401.                 big_rec_vec = dtuple_convert_big_rec(index, new_entry,
  1402.                  ext_vect, n_ext_vect);
  1403. if (big_rec_vec == NULL) {
  1404. mem_heap_free(heap);
  1405. err = DB_TOO_BIG_RECORD;
  1406. goto return_after_reservations;
  1407. }
  1408. }
  1409. page_cursor = btr_cur_get_page_cur(cursor);
  1410. /* Store state of explicit locks on rec on the page infimum record,
  1411. before deleting rec. The page infimum acts as a dummy carrier of the
  1412. locks, taking care also of lock releases, before we can move the locks
  1413. back on the actual record. There is a special case: if we are
  1414. inserting on the root page and the insert causes a call of
  1415. btr_root_raise_and_insert. Therefore we cannot in the lock system
  1416. delete the lock structs set on the root page even if the root
  1417. page carries just node pointers. */
  1418. lock_rec_store_on_page_infimum(rec);
  1419. btr_search_update_hash_on_delete(cursor);
  1420. page_cur_delete_rec(page_cursor, mtr);
  1421. page_cur_move_to_prev(page_cursor);
  1422. rec = btr_cur_insert_if_possible(cursor, new_entry,
  1423. &dummy_reorganized, mtr);
  1424. ut_a(rec || optim_err != DB_UNDERFLOW);
  1425. if (rec) {
  1426. lock_rec_restore_from_page_infimum(rec, page);
  1427. rec_set_field_extern_bits(rec, ext_vect, n_ext_vect, mtr);
  1428. if (!rec_get_deleted_flag(rec)) {
  1429. /* The new inserted record owns its possible externally
  1430. stored fields */
  1431. btr_cur_unmark_extern_fields(rec, mtr);
  1432. }
  1433. btr_cur_compress_if_useful(cursor, mtr);
  1434. err = DB_SUCCESS;
  1435. mem_heap_free(heap);
  1436. goto return_after_reservations;
  1437. }
  1438. if (page_cur_is_before_first(page_cursor)) {
  1439. /* The record to be updated was positioned as the first user
  1440. record on its page */
  1441. was_first = TRUE;
  1442. } else {
  1443. was_first = FALSE;
  1444. }
  1445. /* The first parameter means that no lock checking and undo logging
  1446. is made in the insert */
  1447. err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG
  1448. | BTR_NO_LOCKING_FLAG
  1449. | BTR_KEEP_SYS_FLAG,
  1450. cursor, new_entry, &rec,
  1451. &dummy_big_rec, NULL, mtr);
  1452. ut_a(rec);
  1453. ut_a(err == DB_SUCCESS);
  1454. ut_a(dummy_big_rec == NULL);
  1455. rec_set_field_extern_bits(rec, ext_vect, n_ext_vect, mtr);
  1456. if (!rec_get_deleted_flag(rec)) {
  1457. /* The new inserted record owns its possible externally
  1458. stored fields */
  1459. btr_cur_unmark_extern_fields(rec, mtr);
  1460. }
  1461. lock_rec_restore_from_page_infimum(rec, page);
  1462. /* If necessary, restore also the correct lock state for a new,
  1463. preceding supremum record created in a page split. While the old
  1464. record was nonexistent, the supremum might have inherited its locks
  1465. from a wrong record. */
  1466. if (!was_first) {
  1467. btr_cur_pess_upd_restore_supremum(rec, mtr);
  1468. }
  1469. mem_heap_free(heap);
  1470. return_after_reservations:
  1471. if (n_extents > 0) {
  1472. fil_space_release_free_extents(cursor->index->space,
  1473. n_reserved);
  1474. }
  1475. *big_rec = big_rec_vec;
  1476. return(err);
  1477. }
  1478. /*==================== B-TREE DELETE MARK AND UNMARK ===============*/
  1479. /********************************************************************
  1480. Writes the redo log record for delete marking or unmarking of an index
  1481. record. */
  1482. UNIV_INLINE
  1483. void
  1484. btr_cur_del_mark_set_clust_rec_log(
  1485. /*===============================*/
  1486. ulint flags, /* in: flags */
  1487. rec_t* rec, /* in: record */
  1488. dict_index_t* index, /* in: index of the record */
  1489. ibool val, /* in: value to set */
  1490. trx_t* trx, /* in: deleting transaction */
  1491. dulint roll_ptr,/* in: roll ptr to the undo log record */
  1492. mtr_t* mtr) /* in: mtr */
  1493. {
  1494. byte* log_ptr;
  1495. log_ptr = mlog_open(mtr, 30);
  1496. log_ptr = mlog_write_initial_log_record_fast(rec,
  1497. MLOG_REC_CLUST_DELETE_MARK, log_ptr, mtr);
  1498. mach_write_to_1(log_ptr, flags);
  1499. log_ptr++;
  1500. mach_write_to_1(log_ptr, val);
  1501. log_ptr++;
  1502. log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
  1503. mtr);
  1504. mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
  1505. log_ptr += 2;
  1506. mlog_close(mtr, log_ptr);
  1507. }
  1508. /********************************************************************
  1509. Parses the redo log record for delete marking or unmarking of a clustered
  1510. index record. */
  1511. byte*
  1512. btr_cur_parse_del_mark_set_clust_rec(
  1513. /*=================================*/
  1514. /* out: end of log record or NULL */
  1515. byte* ptr, /* in: buffer */
  1516. byte* end_ptr,/* in: buffer end */
  1517. page_t* page) /* in: page or NULL */
  1518. {
  1519. ulint flags;
  1520. ibool val;
  1521. ulint pos;
  1522. dulint trx_id;
  1523. dulint roll_ptr;
  1524. ulint offset;
  1525. rec_t* rec;
  1526. if (end_ptr < ptr + 2) {
  1527. return(NULL);
  1528. }
  1529. flags = mach_read_from_1(ptr);
  1530. ptr++;
  1531. val = mach_read_from_1(ptr);
  1532. ptr++;
  1533. ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr);
  1534. if (ptr == NULL) {
  1535. return(NULL);
  1536. }
  1537. if (end_ptr < ptr + 2) {
  1538. return(NULL);
  1539. }
  1540. offset = mach_read_from_2(ptr);
  1541. ptr += 2;
  1542. ut_a(offset <= UNIV_PAGE_SIZE);
  1543. if (page) {
  1544. rec = page + offset;
  1545. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  1546. row_upd_rec_sys_fields_in_recovery(rec, pos, trx_id,
  1547. roll_ptr);
  1548. }
  1549. /* We do not need to reserve btr_search_latch, as the page
  1550. is only being recovered, and there cannot be a hash index to
  1551. it. */
  1552. rec_set_deleted_flag(rec, val);
  1553. }
  1554. return(ptr);
  1555. }
  1556. /***************************************************************
  1557. Marks a clustered index record deleted. Writes an undo log record to
  1558. undo log on this delete marking. Writes in the trx id field the id
  1559. of the deleting transaction, and in the roll ptr field pointer to the
  1560. undo log record created. */
  1561. ulint
  1562. btr_cur_del_mark_set_clust_rec(
  1563. /*===========================*/
  1564. /* out: DB_SUCCESS, DB_LOCK_WAIT, or error
  1565. number */
  1566. ulint flags, /* in: undo logging and locking flags */
  1567. btr_cur_t* cursor, /* in: cursor */
  1568. ibool val, /* in: value to set */
  1569. que_thr_t* thr, /* in: query thread */
  1570. mtr_t* mtr) /* in: mtr */
  1571. {
  1572. dict_index_t* index;
  1573. buf_block_t* block;
  1574. dulint roll_ptr;
  1575. ulint err;
  1576. rec_t* rec;
  1577. trx_t* trx;
  1578. rec = btr_cur_get_rec(cursor);
  1579. index = cursor->index;
  1580. if (btr_cur_print_record_ops && thr) {
  1581. btr_cur_trx_report(thr_get_trx(thr), index, "del mark ");
  1582. rec_print(stderr, rec);
  1583. }
  1584. ut_ad(index->type & DICT_CLUSTERED);
  1585. ut_ad(rec_get_deleted_flag(rec) == FALSE);
  1586. err = lock_clust_rec_modify_check_and_lock(flags, rec, index, thr);
  1587. if (err != DB_SUCCESS) {
  1588. return(err);
  1589. }
  1590. err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
  1591. index, NULL, NULL, 0, rec,
  1592. &roll_ptr);
  1593. if (err != DB_SUCCESS) {
  1594. return(err);
  1595. }
  1596. block = buf_block_align(rec);
  1597. if (block->is_hashed) {
  1598. rw_lock_x_lock(&btr_search_latch);
  1599. }
  1600. rec_set_deleted_flag(rec, val);
  1601. trx = thr_get_trx(thr);
  1602. if (!(flags & BTR_KEEP_SYS_FLAG)) {
  1603. row_upd_rec_sys_fields(rec, index, trx, roll_ptr);
  1604. }
  1605. if (block->is_hashed) {
  1606. rw_lock_x_unlock(&btr_search_latch);
  1607. }
  1608. btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx,
  1609. roll_ptr, mtr);
  1610. return(DB_SUCCESS);
  1611. }
  1612. /********************************************************************
  1613. Writes the redo log record for a delete mark setting of a secondary
  1614. index record. */
  1615. UNIV_INLINE
  1616. void
  1617. btr_cur_del_mark_set_sec_rec_log(
  1618. /*=============================*/
  1619. rec_t* rec, /* in: record */
  1620. ibool val, /* in: value to set */
  1621. mtr_t* mtr) /* in: mtr */
  1622. {
  1623. byte* log_ptr;
  1624. log_ptr = mlog_open(mtr, 30);
  1625. log_ptr = mlog_write_initial_log_record_fast(rec,
  1626. MLOG_REC_SEC_DELETE_MARK, log_ptr, mtr);
  1627. mach_write_to_1(log_ptr, val);
  1628. log_ptr++;
  1629. mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
  1630. log_ptr += 2;
  1631. mlog_close(mtr, log_ptr);
  1632. }
  1633. /********************************************************************
  1634. Parses the redo log record for delete marking or unmarking of a secondary
  1635. index record. */
  1636. byte*
  1637. btr_cur_parse_del_mark_set_sec_rec(
  1638. /*===============================*/
  1639. /* out: end of log record or NULL */
  1640. byte* ptr, /* in: buffer */
  1641. byte* end_ptr,/* in: buffer end */
  1642. page_t* page) /* in: page or NULL */
  1643. {
  1644. ibool val;
  1645. ulint offset;
  1646. rec_t* rec;
  1647. if (end_ptr < ptr + 3) {
  1648. return(NULL);
  1649. }
  1650. val = mach_read_from_1(ptr);
  1651. ptr++;
  1652. offset = mach_read_from_2(ptr);
  1653. ptr += 2;
  1654. ut_a(offset <= UNIV_PAGE_SIZE);
  1655. if (page) {
  1656. rec = page + offset;
  1657. /* We do not need to reserve btr_search_latch, as the page
  1658. is only being recovered, and there cannot be a hash index to
  1659. it. */
  1660. rec_set_deleted_flag(rec, val);
  1661. }
  1662. return(ptr);
  1663. }
  1664. /***************************************************************
  1665. Sets a secondary index record delete mark to TRUE or FALSE. */
  1666. ulint
  1667. btr_cur_del_mark_set_sec_rec(
  1668. /*=========================*/
  1669. /* out: DB_SUCCESS, DB_LOCK_WAIT, or error
  1670. number */
  1671. ulint flags, /* in: locking flag */
  1672. btr_cur_t* cursor, /* in: cursor */
  1673. ibool val, /* in: value to set */
  1674. que_thr_t* thr, /* in: query thread */
  1675. mtr_t* mtr) /* in: mtr */
  1676. {
  1677. buf_block_t* block;
  1678. rec_t* rec;
  1679. ulint err;
  1680. rec = btr_cur_get_rec(cursor);
  1681. if (btr_cur_print_record_ops && thr) {
  1682. btr_cur_trx_report(thr_get_trx(thr), cursor->index,
  1683. "del mark ");
  1684. rec_print(stderr, rec);
  1685. }
  1686. err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index,
  1687. thr);
  1688. if (err != DB_SUCCESS) {
  1689. return(err);
  1690. }
  1691. block = buf_block_align(rec);
  1692. if (block->is_hashed) {
  1693. rw_lock_x_lock(&btr_search_latch);
  1694. }
  1695. rec_set_deleted_flag(rec, val);
  1696. if (block->is_hashed) {
  1697. rw_lock_x_unlock(&btr_search_latch);
  1698. }
  1699. btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
  1700. return(DB_SUCCESS);
  1701. }
  1702. /***************************************************************
  1703. Sets a secondary index record delete mark to FALSE. This function is only
  1704. used by the insert buffer insert merge mechanism. */
  1705. void
  1706. btr_cur_del_unmark_for_ibuf(
  1707. /*========================*/
  1708. rec_t* rec, /* in: record to delete unmark */
  1709. mtr_t* mtr) /* in: mtr */
  1710. {
  1711. /* We do not need to reserve btr_search_latch, as the page has just
  1712. been read to the buffer pool and there cannot be a hash index to it. */
  1713. rec_set_deleted_flag(rec, FALSE);
  1714. btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr);
  1715. }
  1716. /*==================== B-TREE RECORD REMOVE =========================*/
  1717. /*****************************************************************
  1718. Tries to compress a page of the tree on the leaf level. It is assumed
  1719. that mtr holds an x-latch on the tree and on the cursor page. To avoid
  1720. deadlocks, mtr must also own x-latches to brothers of page, if those
  1721. brothers exist. NOTE: it is assumed that the caller has reserved enough
  1722. free extents so that the compression will always succeed if done! */
  1723. void
  1724. btr_cur_compress(
  1725. /*=============*/
  1726. btr_cur_t* cursor, /* in: cursor on the page to compress;
  1727. cursor does not stay valid */
  1728. mtr_t* mtr) /* in: mtr */
  1729. {
  1730. ut_ad(mtr_memo_contains(mtr,
  1731. dict_tree_get_lock(btr_cur_get_tree(cursor)),
  1732. MTR_MEMO_X_LOCK));
  1733. ut_ad(mtr_memo_contains(mtr, buf_block_align(
  1734. btr_cur_get_page(cursor)),
  1735. MTR_MEMO_PAGE_X_FIX));
  1736. ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0);
  1737. btr_compress(cursor, mtr);
  1738. }
  1739. /*****************************************************************
  1740. Tries to compress a page of the tree if it seems useful. It is assumed
  1741. that mtr holds an x-latch on the tree and on the cursor page. To avoid
  1742. deadlocks, mtr must also own x-latches to brothers of page, if those
  1743. brothers exist. NOTE: it is assumed that the caller has reserved enough
  1744. free extents so that the compression will always succeed if done! */
  1745. ibool
  1746. btr_cur_compress_if_useful(
  1747. /*=======================*/
  1748. /* out: TRUE if compression occurred */
  1749. btr_cur_t* cursor, /* in: cursor on the page to compress;
  1750. cursor does not stay valid if compression
  1751. occurs */
  1752. mtr_t* mtr) /* in: mtr */
  1753. {
  1754. ut_ad(mtr_memo_contains(mtr,
  1755. dict_tree_get_lock(btr_cur_get_tree(cursor)),
  1756. MTR_MEMO_X_LOCK));
  1757. ut_ad(mtr_memo_contains(mtr, buf_block_align(
  1758. btr_cur_get_page(cursor)),
  1759. MTR_MEMO_PAGE_X_FIX));
  1760. if (btr_cur_compress_recommendation(cursor, mtr)) {
  1761. btr_compress(cursor, mtr);
  1762. return(TRUE);
  1763. }
  1764. return(FALSE);
  1765. }
  1766. /***********************************************************
  1767. Removes the record on which the tree cursor is positioned on a leaf page.
  1768. It is assumed that the mtr has an x-latch on the page where the cursor is
  1769. positioned, but no latch on the whole tree. */
  1770. ibool
  1771. btr_cur_optimistic_delete(
  1772. /*======================*/
  1773. /* out: TRUE if success, i.e., the page
  1774. did not become too empty */
  1775. btr_cur_t* cursor, /* in: cursor on leaf page, on the record to
  1776. delete; cursor stays valid: if deletion
  1777. succeeds, on function exit it points to the
  1778. successor of the deleted record */
  1779. mtr_t* mtr) /* in: mtr */
  1780. {
  1781. page_t* page;
  1782. ulint max_ins_size;
  1783. ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)),
  1784. MTR_MEMO_PAGE_X_FIX));
  1785. /* This is intended only for leaf page deletions */
  1786. page = btr_cur_get_page(cursor);
  1787. ut_ad(btr_page_get_level(page, mtr) == 0);
  1788. if (rec_contains_externally_stored_field(btr_cur_get_rec(cursor))) {
  1789. return(FALSE);
  1790. }
  1791. if (btr_cur_can_delete_without_compress(cursor, mtr)) {
  1792. lock_update_delete(btr_cur_get_rec(cursor));
  1793. btr_search_update_hash_on_delete(cursor);
  1794. max_ins_size = page_get_max_insert_size_after_reorganize(page,
  1795. 1);
  1796. page_cur_delete_rec(btr_cur_get_page_cur(cursor), mtr);
  1797. ibuf_update_free_bits_low(cursor->index, page, max_ins_size,
  1798. mtr);
  1799. return(TRUE);
  1800. }
  1801. return(FALSE);
  1802. }
  1803. /*****************************************************************
  1804. Removes the record on which the tree cursor is positioned. Tries
  1805. to compress the page if its fillfactor drops below a threshold
  1806. or if it is the only page on the level. It is assumed that mtr holds
  1807. an x-latch on the tree and on the cursor page. To avoid deadlocks,
  1808. mtr must also own x-latches to brothers of page, if those brothers
  1809. exist. */
  1810. ibool
  1811. btr_cur_pessimistic_delete(
  1812. /*=======================*/
  1813. /* out: TRUE if compression occurred */
  1814. ulint* err, /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE;
  1815. the latter may occur because we may have
  1816. to update node pointers on upper levels,
  1817. and in the case of variable length keys
  1818. these may actually grow in size */
  1819. ibool has_reserved_extents, /* in: TRUE if the
  1820. caller has already reserved enough free
  1821. extents so that he knows that the operation
  1822. will succeed */
  1823. btr_cur_t* cursor, /* in: cursor on the record to delete;
  1824. if compression does not occur, the cursor
  1825. stays valid: it points to successor of
  1826. deleted record on function exit */
  1827. ibool in_rollback,/* in: TRUE if called in rollback */
  1828. mtr_t* mtr) /* in: mtr */
  1829. {
  1830. page_t* page;
  1831. dict_tree_t* tree;
  1832. rec_t* rec;
  1833. dtuple_t* node_ptr;
  1834. ulint n_extents = 0;
  1835. ulint n_reserved;
  1836. ibool success;
  1837. ibool ret = FALSE;
  1838. mem_heap_t* heap;
  1839. page = btr_cur_get_page(cursor);
  1840. tree = btr_cur_get_tree(cursor);
  1841. ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
  1842. MTR_MEMO_X_LOCK));
  1843. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  1844. MTR_MEMO_PAGE_X_FIX));
  1845. if (!has_reserved_extents) {
  1846. /* First reserve enough free space for the file segments
  1847. of the index tree, so that the node pointer updates will
  1848. not fail because of lack of space */
  1849. n_extents = cursor->tree_height / 32 + 1;
  1850. success = fsp_reserve_free_extents(&n_reserved,
  1851. cursor->index->space,
  1852. n_extents, FSP_CLEANING, mtr);
  1853. if (!success) {
  1854. *err = DB_OUT_OF_FILE_SPACE;
  1855. return(FALSE);
  1856. }
  1857. }
  1858. btr_rec_free_externally_stored_fields(cursor->index,
  1859. btr_cur_get_rec(cursor), in_rollback, mtr);
  1860. if ((page_get_n_recs(page) < 2)
  1861.     && (dict_tree_get_page(btr_cur_get_tree(cursor))
  1862. != buf_frame_get_page_no(page))) {
  1863. /* If there is only one record, drop the whole page in
  1864. btr_discard_page, if this is not the root page */
  1865. btr_discard_page(cursor, mtr);
  1866. *err = DB_SUCCESS;
  1867. ret = TRUE;
  1868. goto return_after_reservations;
  1869. }
  1870. rec = btr_cur_get_rec(cursor);
  1871. lock_update_delete(rec);
  1872. if ((btr_page_get_level(page, mtr) > 0)
  1873.     && (page_rec_get_next(page_get_infimum_rec(page)) == rec)) {
  1874. if (btr_page_get_prev(page, mtr) == FIL_NULL) {
  1875. /* If we delete the leftmost node pointer on a
  1876. non-leaf level, we must mark the new leftmost node
  1877. pointer as the predefined minimum record */
  1878.      btr_set_min_rec_mark(page_rec_get_next(rec), mtr);
  1879. } else {
  1880. /* Otherwise, if we delete the leftmost node pointer
  1881. on a page, we have to change the father node pointer
  1882. so that it is equal to the new leftmost node pointer
  1883. on the page */
  1884. btr_node_ptr_delete(tree, page, mtr);
  1885. heap = mem_heap_create(256);
  1886. node_ptr = dict_tree_build_node_ptr(
  1887. tree, page_rec_get_next(rec),
  1888. buf_frame_get_page_no(page),
  1889.         heap, btr_page_get_level(page, mtr));
  1890. btr_insert_on_non_leaf_level(tree,
  1891. btr_page_get_level(page, mtr) + 1,
  1892. node_ptr, mtr);
  1893. mem_heap_free(heap);
  1894. }
  1895. btr_search_update_hash_on_delete(cursor);
  1896. page_cur_delete_rec(btr_cur_get_page_cur(cursor), mtr);
  1897. ut_ad(btr_check_node_ptr(tree, page, mtr));
  1898. *err = DB_SUCCESS;
  1899. return_after_reservations:
  1900. if (ret == FALSE) {
  1901. ret = btr_cur_compress_if_useful(cursor, mtr);
  1902. }
  1903. if (n_extents > 0) {
  1904. fil_space_release_free_extents(cursor->index->space,
  1905. n_reserved);
  1906. }
  1907. return(ret);
  1908. }
  1909. /***********************************************************************
  1910. Adds path information to the cursor for the current page, for which
  1911. the binary search has been performed. */
  1912. static
  1913. void
  1914. btr_cur_add_path_info(
  1915. /*==================*/
  1916. btr_cur_t* cursor, /* in: cursor positioned on a page */
  1917. ulint height, /* in: height of the page in tree;
  1918. 0 means leaf node */
  1919. ulint root_height) /* in: root node height in tree */
  1920. {
  1921. btr_path_t* slot;
  1922. rec_t* rec;
  1923. ut_a(cursor->path_arr);
  1924. if (root_height >= BTR_PATH_ARRAY_N_SLOTS - 1) {
  1925. /* Do nothing; return empty path */
  1926. slot = cursor->path_arr;
  1927. slot->nth_rec = ULINT_UNDEFINED;
  1928. return;
  1929. }
  1930. if (height == 0) {
  1931. /* Mark end of slots for path */
  1932. slot = cursor->path_arr + root_height + 1;
  1933. slot->nth_rec = ULINT_UNDEFINED;
  1934. }
  1935. rec = btr_cur_get_rec(cursor);
  1936. slot = cursor->path_arr + (root_height - height);
  1937. slot->nth_rec = page_rec_get_n_recs_before(rec);
  1938. slot->n_recs = page_get_n_recs(buf_frame_align(rec));
  1939. }
  1940. /***********************************************************************
  1941. Estimates the number of rows in a given index range. */
  1942. ib_longlong
  1943. btr_estimate_n_rows_in_range(
  1944. /*=========================*/
  1945. /* out: estimated number of rows */
  1946. dict_index_t* index, /* in: index */
  1947. dtuple_t* tuple1, /* in: range start, may also be empty tuple */
  1948. ulint mode1, /* in: search mode for range start */
  1949. dtuple_t* tuple2, /* in: range end, may also be empty tuple */
  1950. ulint mode2) /* in: search mode for range end */
  1951. {
  1952. btr_path_t path1[BTR_PATH_ARRAY_N_SLOTS];
  1953. btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS];
  1954. btr_cur_t cursor;
  1955. btr_path_t* slot1;
  1956. btr_path_t* slot2;
  1957. ibool diverged;
  1958. ibool           diverged_lot;
  1959. ulint           divergence_level;           
  1960. ib_longlong n_rows;
  1961. ulint i;
  1962. mtr_t mtr;
  1963. mtr_start(&mtr);
  1964. cursor.path_arr = path1;
  1965. if (dtuple_get_n_fields(tuple1) > 0) {
  1966. btr_cur_search_to_nth_level(index, 0, tuple1, mode1,
  1967. BTR_SEARCH_LEAF | BTR_ESTIMATE,
  1968. &cursor, 0, &mtr);
  1969. } else {
  1970. btr_cur_open_at_index_side(TRUE, index,
  1971. BTR_SEARCH_LEAF | BTR_ESTIMATE,
  1972. &cursor, &mtr);
  1973. }
  1974. mtr_commit(&mtr);
  1975. mtr_start(&mtr);
  1976. cursor.path_arr = path2;
  1977. if (dtuple_get_n_fields(tuple2) > 0) {
  1978. btr_cur_search_to_nth_level(index, 0, tuple2, mode2,
  1979. BTR_SEARCH_LEAF | BTR_ESTIMATE,
  1980. &cursor, 0, &mtr);
  1981. } else {
  1982. btr_cur_open_at_index_side(FALSE, index,
  1983. BTR_SEARCH_LEAF | BTR_ESTIMATE,
  1984. &cursor, &mtr);
  1985. }
  1986. mtr_commit(&mtr);
  1987. /* We have the path information for the range in path1 and path2 */
  1988. n_rows = 1;
  1989. diverged = FALSE;           /* This becomes true when the path is not
  1990.     the same any more */
  1991. diverged_lot = FALSE;       /* This becomes true when the paths are
  1992.     not the same or adjacent any more */
  1993. divergence_level = 1000000; /* This is the level where paths diverged
  1994.     a lot */ 
  1995.         for (i = 0; ; i++) {
  1996. ut_ad(i < BTR_PATH_ARRAY_N_SLOTS);
  1997. slot1 = path1 + i;
  1998. slot2 = path2 + i;
  1999. if (slot1->nth_rec == ULINT_UNDEFINED
  2000. || slot2->nth_rec == ULINT_UNDEFINED) {
  2001.         if (i > divergence_level + 1) {
  2002.                 /* In trees whose height is > 1 our algorithm
  2003.                 tends to underestimate: multiply the estimate
  2004.                 by 2: */
  2005.                 n_rows = n_rows * 2;
  2006.         }
  2007. /* Do not estimate the number of rows in the range
  2008.         to over 1 / 2 of the estimated rows in the whole
  2009. table */
  2010. if (n_rows > index->table->stat_n_rows / 2) {
  2011.         n_rows = index->table->stat_n_rows / 2;
  2012. /* If there are just 0 or 1 rows in the table,
  2013. then we estimate all rows are in the range */
  2014.   
  2015.         if (n_rows == 0) {
  2016.         n_rows = index->table->stat_n_rows;
  2017.         }
  2018. }
  2019. return(n_rows);
  2020. }
  2021. if (!diverged && slot1->nth_rec != slot2->nth_rec) {
  2022. diverged = TRUE;
  2023. if (slot1->nth_rec < slot2->nth_rec) {
  2024. n_rows = slot2->nth_rec - slot1->nth_rec;
  2025. if (n_rows > 1) {
  2026.           diverged_lot = TRUE;
  2027.   divergence_level = i;
  2028. }
  2029. } else {
  2030. /* Maybe the tree has changed between
  2031. searches */
  2032. return(10);
  2033. }
  2034. } else if (diverged && !diverged_lot) {
  2035.         if (slot1->nth_rec < slot1->n_recs
  2036.             || slot2->nth_rec > 1) {
  2037.                 diverged_lot = TRUE;
  2038. divergence_level = i;
  2039. n_rows = 0;
  2040.                 if (slot1->nth_rec < slot1->n_recs) {
  2041.         n_rows += slot1->n_recs
  2042.              - slot1->nth_rec;
  2043. }
  2044. if (slot2->nth_rec > 1) {
  2045.         n_rows += slot2->nth_rec - 1;
  2046. }
  2047.        }
  2048. } else if (diverged_lot) {
  2049. n_rows = (n_rows * (slot1->n_recs + slot2->n_recs))
  2050. / 2;
  2051. }
  2052. }
  2053. }
  2054. /***********************************************************************
  2055. Estimates the number of different key values in a given index, for
  2056. each n-column prefix of the index where n <= dict_index_get_n_unique(index).
  2057. The estimates are stored in the array index->stat_n_diff_key_vals. */
  2058. void
  2059. btr_estimate_number_of_different_key_vals(
  2060. /*======================================*/
  2061. dict_index_t* index) /* in: index */
  2062. {
  2063. btr_cur_t cursor;
  2064. page_t* page;
  2065. rec_t* rec;
  2066. ulint n_cols;
  2067. ulint matched_fields;
  2068. ulint matched_bytes;
  2069. ib_longlong* n_diff;
  2070. ulint not_empty_flag = 0;
  2071. ulint total_external_size = 0;
  2072. ulint i;
  2073. ulint j;
  2074. ulint add_on;
  2075. mtr_t mtr;
  2076. n_cols = dict_index_get_n_unique(index);
  2077. n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong));
  2078. for (j = 0; j <= n_cols; j++) {
  2079. n_diff[j] = 0;
  2080. }
  2081. /* We sample some pages in the index to get an estimate */
  2082. for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++) {
  2083. mtr_start(&mtr);
  2084. btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
  2085. /* Count the number of different key values for each prefix of
  2086. the key on this index page. If the prefix does not determine
  2087. the index record uniquely in te B-tree, then we subtract one
  2088. because otherwise our algorithm would give a wrong estimate
  2089. for an index where there is just one key value. */
  2090. page = btr_cur_get_page(&cursor);
  2091. rec = page_get_infimum_rec(page);
  2092. rec = page_rec_get_next(rec);
  2093. if (rec != page_get_supremum_rec(page)) {
  2094. not_empty_flag = 1;
  2095. }
  2096. while (rec != page_get_supremum_rec(page)
  2097.        && page_rec_get_next(rec)
  2098. != page_get_supremum_rec(page)) {
  2099. matched_fields = 0;
  2100. matched_bytes = 0;
  2101. cmp_rec_rec_with_match(rec, page_rec_get_next(rec),
  2102. index, &matched_fields,
  2103. &matched_bytes);
  2104. for (j = matched_fields + 1; j <= n_cols; j++) {
  2105. /* We add one if this index record has
  2106. a different prefix from the previous */
  2107. n_diff[j]++;
  2108. }
  2109. total_external_size +=
  2110. btr_rec_get_externally_stored_len(rec);
  2111. rec = page_rec_get_next(rec);
  2112. }
  2113. if (n_cols == dict_index_get_n_unique_in_tree(index)) {
  2114. /* If there is more than one leaf page in the tree,
  2115. we add one because we know that the first record
  2116. on the page certainly had a different prefix than the
  2117. last record on the previous index page in the
  2118. alphabetical order. Before this fix, if there was
  2119. just one big record on each clustered index page, the
  2120. algorithm grossly underestimated the number of rows
  2121. in the table. */
  2122. if (btr_page_get_prev(page, &mtr) != FIL_NULL
  2123.     || btr_page_get_next(page, &mtr) != FIL_NULL) {
  2124. n_diff[n_cols]++;
  2125. }
  2126. }
  2127. total_external_size +=
  2128. btr_rec_get_externally_stored_len(rec);
  2129. mtr_commit(&mtr);
  2130. }
  2131. /* If we saw k borders between different key values on
  2132. BTR_KEY_VAL_ESTIMATE_N_PAGES leaf pages, we can estimate how many
  2133. there will be in index->stat_n_leaf_pages */
  2134. /* We must take into account that our sample actually represents
  2135. also the pages used for external storage of fields (those pages are
  2136. included in index->stat_n_leaf_pages) */ 
  2137. for (j = 0; j <= n_cols; j++) {
  2138. index->stat_n_diff_key_vals[j] =
  2139. (n_diff[j]
  2140.  * (ib_longlong)index->stat_n_leaf_pages
  2141.  + BTR_KEY_VAL_ESTIMATE_N_PAGES - 1
  2142.  + total_external_size
  2143.  + not_empty_flag)
  2144.                  / (BTR_KEY_VAL_ESTIMATE_N_PAGES
  2145.                     + total_external_size);
  2146. /* If the tree is small, smaller than <
  2147. 10 * BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size, then
  2148. the above estimate is ok. For bigger trees it is common that we
  2149. do not see any borders between key values in the few pages
  2150. we pick. But still there may be BTR_KEY_VAL_ESTIMATE_N_PAGES
  2151. different key values, or even more. Let us try to approximate
  2152. that: */
  2153. add_on = index->stat_n_leaf_pages /
  2154.    (10 * (BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size));
  2155. if (add_on > BTR_KEY_VAL_ESTIMATE_N_PAGES) {
  2156. add_on = BTR_KEY_VAL_ESTIMATE_N_PAGES;
  2157. }
  2158. index->stat_n_diff_key_vals[j] += add_on;
  2159. }
  2160. mem_free(n_diff);
  2161. }
  2162. /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
  2163. /***************************************************************
  2164. Gets the externally stored size of a record, in units of a database page. */
  2165. static
  2166. ulint
  2167. btr_rec_get_externally_stored_len(
  2168. /*==============================*/
  2169. /* out: externally stored part, in units of a
  2170. database page */
  2171. rec_t* rec) /* in: record */
  2172. {
  2173. ulint n_fields;
  2174. byte* data;
  2175. ulint local_len;
  2176. ulint extern_len;
  2177. ulint total_extern_len = 0;
  2178. ulint i;
  2179. if (rec_get_data_size(rec) <= REC_1BYTE_OFFS_LIMIT) {
  2180. return(0);
  2181. }
  2182. n_fields = rec_get_n_fields(rec);
  2183. for (i = 0; i < n_fields; i++) {
  2184. if (rec_get_nth_field_extern_bit(rec, i)) {
  2185. data = rec_get_nth_field(rec, i, &local_len);
  2186. local_len -= BTR_EXTERN_FIELD_REF_SIZE;
  2187. extern_len = mach_read_from_4(data + local_len
  2188. + BTR_EXTERN_LEN + 4);
  2189. total_extern_len += ut_calc_align(extern_len,
  2190. UNIV_PAGE_SIZE);
  2191. }
  2192. }
  2193. return(total_extern_len / UNIV_PAGE_SIZE);
  2194. }
  2195. /***********************************************************************
  2196. Sets the ownership bit of an externally stored field in a record. */
  2197. static
  2198. void
  2199. btr_cur_set_ownership_of_extern_field(
  2200. /*==================================*/
  2201. rec_t* rec, /* in: clustered index record */
  2202. ulint i, /* in: field number */
  2203. ibool val, /* in: value to set */
  2204. mtr_t* mtr) /* in: mtr */
  2205. {
  2206. byte* data;
  2207. ulint local_len;
  2208. ulint byte_val;
  2209. data = rec_get_nth_field(rec, i, &local_len);
  2210. ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
  2211. local_len -= BTR_EXTERN_FIELD_REF_SIZE;
  2212. byte_val = mach_read_from_1(data + local_len + BTR_EXTERN_LEN);
  2213. if (val) {
  2214. byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
  2215. } else {
  2216. byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
  2217. }
  2218. mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val,
  2219. MLOG_1BYTE, mtr);
  2220. }
  2221. /***********************************************************************
  2222. Marks not updated extern fields as not-owned by this record. The ownership
  2223. is transferred to the updated record which is inserted elsewhere in the
  2224. index tree. In purge only the owner of externally stored field is allowed
  2225. to free the field. */
  2226. void
  2227. btr_cur_mark_extern_inherited_fields(
  2228. /*=================================*/
  2229. rec_t* rec, /* in: record in a clustered index */
  2230. upd_t* update, /* in: update vector */
  2231. mtr_t* mtr) /* in: mtr */
  2232. {
  2233. ibool is_updated;
  2234. ulint n;
  2235. ulint j;
  2236. ulint i;
  2237. n = rec_get_n_fields(rec);
  2238. for (i = 0; i < n; i++) {
  2239. if (rec_get_nth_field_extern_bit(rec, i)) {
  2240. /* Check it is not in updated fields */
  2241. is_updated = FALSE;
  2242. if (update) {
  2243. for (j = 0; j < upd_get_n_fields(update);
  2244. j++) {
  2245. if (upd_get_nth_field(update, j)
  2246. ->field_no == i) {
  2247. is_updated = TRUE;
  2248. }
  2249. }
  2250. }
  2251. if (!is_updated) {
  2252. btr_cur_set_ownership_of_extern_field(rec, i,
  2253. FALSE, mtr);
  2254. }
  2255. }
  2256. }
  2257. }
  2258. /***********************************************************************
  2259. The complement of the previous function: in an update entry may inherit
  2260. some externally stored fields from a record. We must mark them as inherited
  2261. in entry, so that they are not freed in a rollback. */
  2262. void
  2263. btr_cur_mark_dtuple_inherited_extern(
  2264. /*=================================*/
  2265. dtuple_t* entry, /* in: updated entry to be inserted to
  2266. clustered index */
  2267. ulint* ext_vec, /* in: array of extern fields in the
  2268. original record */
  2269. ulint n_ext_vec, /* in: number of elements in ext_vec */
  2270. upd_t* update) /* in: update vector */
  2271. {
  2272. dfield_t* dfield;
  2273. ulint byte_val;
  2274. byte* data;
  2275. ulint len;
  2276. ibool is_updated;
  2277. ulint j;
  2278. ulint i;
  2279. if (ext_vec == NULL) {
  2280. return;
  2281. }
  2282. for (i = 0; i < n_ext_vec; i++) {
  2283. /* Check ext_vec[i] is in updated fields */
  2284. is_updated = FALSE;
  2285. for (j = 0; j < upd_get_n_fields(update); j++) {
  2286. if (upd_get_nth_field(update, j)->field_no
  2287. == ext_vec[i]) {
  2288. is_updated = TRUE;
  2289. }
  2290. }
  2291. if (!is_updated) {
  2292. dfield = dtuple_get_nth_field(entry, ext_vec[i]);
  2293. data = (byte*) dfield_get_data(dfield);
  2294. len = dfield_get_len(dfield);
  2295. len -= BTR_EXTERN_FIELD_REF_SIZE;
  2296. byte_val = mach_read_from_1(data + len
  2297. + BTR_EXTERN_LEN);
  2298. byte_val = byte_val | BTR_EXTERN_INHERITED_FLAG;
  2299. mach_write_to_1(data + len + BTR_EXTERN_LEN, byte_val);
  2300. }
  2301. }
  2302. }
  2303. /***********************************************************************
  2304. Marks all extern fields in a record as owned by the record. This function
  2305. should be called if the delete mark of a record is removed: a not delete
  2306. marked record always owns all its extern fields. */
  2307. static
  2308. void
  2309. btr_cur_unmark_extern_fields(
  2310. /*=========================*/
  2311. rec_t* rec, /* in: record in a clustered index */
  2312. mtr_t* mtr) /* in: mtr */
  2313. {
  2314. ulint n;
  2315. ulint i;
  2316. n = rec_get_n_fields(rec);
  2317. for (i = 0; i < n; i++) {
  2318. if (rec_get_nth_field_extern_bit(rec, i)) {
  2319. btr_cur_set_ownership_of_extern_field(rec, i,
  2320. TRUE, mtr);
  2321. }
  2322. }
  2323. }
  2324. /***********************************************************************
  2325. Marks all extern fields in a dtuple as owned by the record. */
  2326. void
  2327. btr_cur_unmark_dtuple_extern_fields(
  2328. /*================================*/
  2329. dtuple_t* entry, /* in: clustered index entry */
  2330. ulint* ext_vec, /* in: array of numbers of fields
  2331. which have been stored externally */
  2332. ulint n_ext_vec) /* in: number of elements in ext_vec */
  2333. {
  2334. dfield_t* dfield;
  2335. ulint byte_val;
  2336. byte* data;
  2337. ulint len;
  2338. ulint i;
  2339. for (i = 0; i < n_ext_vec; i++) {
  2340. dfield = dtuple_get_nth_field(entry, ext_vec[i]);
  2341. data = (byte*) dfield_get_data(dfield);
  2342. len = dfield_get_len(dfield);
  2343. len -= BTR_EXTERN_FIELD_REF_SIZE;
  2344. byte_val = mach_read_from_1(data + len + BTR_EXTERN_LEN);
  2345. byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
  2346. mach_write_to_1(data + len + BTR_EXTERN_LEN, byte_val);
  2347. }
  2348. }
  2349. /***********************************************************************
  2350. Stores the positions of the fields marked as extern storage in the update
  2351. vector, and also those fields who are marked as extern storage in rec
  2352. and not mentioned in updated fields. We use this function to remember
  2353. which fields we must mark as extern storage in a record inserted for an
  2354. update. */
  2355. ulint
  2356. btr_push_update_extern_fields(
  2357. /*==========================*/
  2358. /* out: number of values stored in ext_vect */
  2359. ulint* ext_vect, /* in: array of ulints, must be preallocated
  2360. to have space for all fields in rec */
  2361. rec_t* rec, /* in: record */
  2362. upd_t* update) /* in: update vector or NULL */
  2363. {
  2364. ulint n_pushed = 0;
  2365. ibool is_updated;
  2366. ulint n;
  2367. ulint j;
  2368. ulint i;
  2369. if (update) {
  2370. n = upd_get_n_fields(update);
  2371. for (i = 0; i < n; i++) {
  2372. if (upd_get_nth_field(update, i)->extern_storage) {
  2373. ext_vect[n_pushed] =
  2374. upd_get_nth_field(update, i)->field_no;
  2375. n_pushed++;
  2376. }
  2377. }
  2378. }
  2379. n = rec_get_n_fields(rec);
  2380. for (i = 0; i < n; i++) {
  2381. if (rec_get_nth_field_extern_bit(rec, i)) {
  2382. /* Check it is not in updated fields */
  2383. is_updated = FALSE;
  2384. if (update) {
  2385. for (j = 0; j < upd_get_n_fields(update);
  2386. j++) {
  2387. if (upd_get_nth_field(update, j)
  2388. ->field_no == i) {
  2389. is_updated = TRUE;
  2390. }
  2391. }
  2392. }
  2393. if (!is_updated) {
  2394. ext_vect[n_pushed] = i;
  2395. n_pushed++;
  2396. }
  2397. }
  2398. }
  2399. return(n_pushed);
  2400. }
  2401. /***********************************************************************
  2402. Returns the length of a BLOB part stored on the header page. */
  2403. static
  2404. ulint
  2405. btr_blob_get_part_len(
  2406. /*==================*/
  2407. /* out: part length */
  2408. byte* blob_header) /* in: blob header */
  2409. {
  2410. return(mach_read_from_4(blob_header + BTR_BLOB_HDR_PART_LEN));
  2411. }
  2412. /***********************************************************************
  2413. Returns the page number where the next BLOB part is stored. */
  2414. static
  2415. ulint
  2416. btr_blob_get_next_page_no(
  2417. /*======================*/
  2418. /* out: page number or FIL_NULL if
  2419. no more pages */
  2420. byte* blob_header) /* in: blob header */
  2421. {
  2422. return(mach_read_from_4(blob_header + BTR_BLOB_HDR_NEXT_PAGE_NO));
  2423. }
  2424. /***********************************************************************
  2425. Stores the fields in big_rec_vec to the tablespace and puts pointers to
  2426. them in rec. The fields are stored on pages allocated from leaf node
  2427. file segment of the index tree. */
  2428. ulint
  2429. btr_store_big_rec_extern_fields(
  2430. /*============================*/
  2431. /* out: DB_SUCCESS or error */
  2432. dict_index_t* index, /* in: index of rec; the index tree
  2433. MUST be X-latched */
  2434. rec_t* rec, /* in: record */
  2435. big_rec_t* big_rec_vec, /* in: vector containing fields
  2436. to be stored externally */
  2437. mtr_t* local_mtr __attribute__((unused))) /* in: mtr
  2438.                                         containing the latch to rec and to the
  2439.                                         tree */
  2440. {
  2441. byte* data;
  2442. ulint local_len;
  2443. ulint extern_len;
  2444. ulint store_len;
  2445. ulint page_no;
  2446. page_t* page;
  2447. ulint space_id;
  2448. page_t* prev_page;
  2449. page_t* rec_page;
  2450. ulint prev_page_no;
  2451. ulint hint_page_no;
  2452. ulint i;
  2453. mtr_t mtr;
  2454. ut_ad(mtr_memo_contains(local_mtr, dict_tree_get_lock(index->tree),
  2455. MTR_MEMO_X_LOCK));
  2456. ut_ad(mtr_memo_contains(local_mtr, buf_block_align(rec),
  2457. MTR_MEMO_PAGE_X_FIX));
  2458. ut_a(index->type & DICT_CLUSTERED);
  2459. space_id = buf_frame_get_space_id(rec);
  2460. /* We have to create a file segment to the tablespace
  2461. for each field and put the pointer to the field in rec */
  2462. for (i = 0; i < big_rec_vec->n_fields; i++) {
  2463. data = rec_get_nth_field(rec, big_rec_vec->fields[i].field_no,
  2464. &local_len);
  2465. ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
  2466. local_len -= BTR_EXTERN_FIELD_REF_SIZE;
  2467. extern_len = big_rec_vec->fields[i].len;
  2468. ut_a(extern_len > 0);
  2469. prev_page_no = FIL_NULL;
  2470. while (extern_len > 0) {
  2471. mtr_start(&mtr);
  2472. if (prev_page_no == FIL_NULL) {
  2473. hint_page_no = buf_frame_get_page_no(rec) + 1;
  2474. } else {
  2475. hint_page_no = prev_page_no + 1;
  2476. }
  2477. page = btr_page_alloc(index->tree, hint_page_no,
  2478. FSP_NO_DIR, 0, &mtr);
  2479. if (page == NULL) {
  2480. mtr_commit(&mtr);
  2481. return(DB_OUT_OF_FILE_SPACE);
  2482. }
  2483. page_no = buf_frame_get_page_no(page);
  2484. if (prev_page_no != FIL_NULL) {
  2485. prev_page = buf_page_get(space_id,
  2486. prev_page_no,
  2487. RW_X_LATCH, &mtr);
  2488. #ifdef UNIV_SYNC_DEBUG
  2489. buf_page_dbg_add_level(prev_page,
  2490. SYNC_EXTERN_STORAGE);
  2491. #endif /* UNIV_SYNC_DEBUG */
  2492. mlog_write_ulint(prev_page + FIL_PAGE_DATA
  2493. + BTR_BLOB_HDR_NEXT_PAGE_NO,
  2494. page_no, MLOG_4BYTES, &mtr);
  2495. }
  2496. if (extern_len > (UNIV_PAGE_SIZE - FIL_PAGE_DATA
  2497. - BTR_BLOB_HDR_SIZE
  2498. - FIL_PAGE_DATA_END)) {
  2499. store_len = UNIV_PAGE_SIZE - FIL_PAGE_DATA
  2500. - BTR_BLOB_HDR_SIZE
  2501. - FIL_PAGE_DATA_END;
  2502. } else {
  2503. store_len = extern_len;
  2504. }
  2505. mlog_write_string(page + FIL_PAGE_DATA
  2506. + BTR_BLOB_HDR_SIZE,
  2507. big_rec_vec->fields[i].data
  2508. + big_rec_vec->fields[i].len
  2509. - extern_len,
  2510. store_len, &mtr);
  2511. mlog_write_ulint(page + FIL_PAGE_DATA
  2512. + BTR_BLOB_HDR_PART_LEN,
  2513. store_len, MLOG_4BYTES, &mtr);
  2514. mlog_write_ulint(page + FIL_PAGE_DATA
  2515. + BTR_BLOB_HDR_NEXT_PAGE_NO,
  2516. FIL_NULL, MLOG_4BYTES, &mtr);
  2517. extern_len -= store_len;
  2518. rec_page = buf_page_get(space_id,
  2519. buf_frame_get_page_no(data),
  2520. RW_X_LATCH, &mtr);
  2521. #ifdef UNIV_SYNC_DEBUG
  2522. buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK);
  2523. #endif /* UNIV_SYNC_DEBUG */
  2524. mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, 0,
  2525. MLOG_4BYTES, &mtr);
  2526. mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4,
  2527. big_rec_vec->fields[i].len
  2528. - extern_len,
  2529. MLOG_4BYTES, &mtr);
  2530. if (prev_page_no == FIL_NULL) {
  2531. mlog_write_ulint(data + local_len
  2532. + BTR_EXTERN_SPACE_ID,
  2533. space_id,
  2534. MLOG_4BYTES, &mtr);
  2535. mlog_write_ulint(data + local_len
  2536. + BTR_EXTERN_PAGE_NO,
  2537. page_no,
  2538. MLOG_4BYTES, &mtr);
  2539. mlog_write_ulint(data + local_len
  2540. + BTR_EXTERN_OFFSET,
  2541. FIL_PAGE_DATA,
  2542. MLOG_4BYTES, &mtr);
  2543. /* Set the bit denoting that this field
  2544. in rec is stored externally */
  2545. rec_set_nth_field_extern_bit(rec,
  2546. big_rec_vec->fields[i].field_no,
  2547. TRUE, &mtr);
  2548. }
  2549. prev_page_no = page_no;
  2550. mtr_commit(&mtr);
  2551. }
  2552. }
  2553. return(DB_SUCCESS);
  2554. }
  2555. /***********************************************************************
  2556. Frees the space in an externally stored field to the file space
  2557. management if the field in data is owned the externally stored field,
  2558. in a rollback we may have the additional condition that the field must
  2559. not be inherited. */
  2560. void
  2561. btr_free_externally_stored_field(
  2562. /*=============================*/
  2563. dict_index_t* index, /* in: index of the data, the index
  2564. tree MUST be X-latched; if the tree
  2565. height is 1, then also the root page
  2566. must be X-latched! (this is relevant
  2567. in the case this function is called
  2568. from purge where 'data' is located on
  2569. an undo log page, not an index
  2570. page) */
  2571. byte* data, /* in: internally stored data
  2572. + reference to the externally
  2573. stored part */
  2574. ulint local_len, /* in: length of data */
  2575. ibool do_not_free_inherited,/* in: TRUE if called in a
  2576. rollback and we do not want to free
  2577. inherited fields */
  2578. mtr_t* local_mtr __attribute__((unused))) /* in: mtr 
  2579.                                         containing the latch to data an an 
  2580.                                         X-latch to the index tree */
  2581. {
  2582. page_t* page;
  2583. page_t* rec_page;
  2584. ulint space_id;
  2585. ulint page_no;
  2586. ulint offset;
  2587. ulint extern_len;
  2588. ulint next_page_no;
  2589. ulint part_len;
  2590. mtr_t mtr;
  2591. ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
  2592. ut_ad(mtr_memo_contains(local_mtr, dict_tree_get_lock(index->tree),
  2593. MTR_MEMO_X_LOCK));
  2594. ut_ad(mtr_memo_contains(local_mtr, buf_block_align(data),
  2595. MTR_MEMO_PAGE_X_FIX));
  2596. ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
  2597. local_len -= BTR_EXTERN_FIELD_REF_SIZE;
  2598. for (;;) {
  2599. mtr_start(&mtr);
  2600. rec_page = buf_page_get(buf_frame_get_space_id(data),
  2601. buf_frame_get_page_no(data), RW_X_LATCH, &mtr);
  2602. #ifdef UNIV_SYNC_DEBUG
  2603. buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK);
  2604. #endif /* UNIV_SYNC_DEBUG */
  2605. space_id = mach_read_from_4(data + local_len
  2606. + BTR_EXTERN_SPACE_ID);
  2607. page_no = mach_read_from_4(data + local_len
  2608. + BTR_EXTERN_PAGE_NO);
  2609. offset = mach_read_from_4(data + local_len
  2610. + BTR_EXTERN_OFFSET);
  2611. extern_len = mach_read_from_4(data + local_len
  2612. + BTR_EXTERN_LEN + 4);
  2613. /* If extern len is 0, then there is no external storage data
  2614. at all */
  2615. if (extern_len == 0) {
  2616. mtr_commit(&mtr);
  2617. return;
  2618. }
  2619. if (mach_read_from_1(data + local_len + BTR_EXTERN_LEN)
  2620. & BTR_EXTERN_OWNER_FLAG) {
  2621. /* This field does not own the externally
  2622. stored field: do not free! */
  2623. mtr_commit(&mtr);
  2624. return;
  2625. }
  2626. if (do_not_free_inherited
  2627. && mach_read_from_1(data + local_len + BTR_EXTERN_LEN)
  2628. & BTR_EXTERN_INHERITED_FLAG) {
  2629. /* Rollback and inherited field: do not free! */
  2630. mtr_commit(&mtr);
  2631. return;
  2632. }
  2633. page = buf_page_get(space_id, page_no, RW_X_LATCH, &mtr);
  2634. #ifdef UNIV_SYNC_DEBUG
  2635. buf_page_dbg_add_level(page, SYNC_EXTERN_STORAGE);
  2636. #endif /* UNIV_SYNC_DEBUG */
  2637. next_page_no = mach_read_from_4(page + FIL_PAGE_DATA
  2638. + BTR_BLOB_HDR_NEXT_PAGE_NO);
  2639. part_len = btr_blob_get_part_len(page + FIL_PAGE_DATA);
  2640. ut_a(extern_len >= part_len);
  2641. /* We must supply the page level (= 0) as an argument
  2642. because we did not store it on the page (we save the space
  2643. overhead from an index page header. */
  2644. btr_page_free_low(index->tree, page, 0, &mtr);
  2645. mlog_write_ulint(data + local_len + BTR_EXTERN_PAGE_NO,
  2646. next_page_no,
  2647. MLOG_4BYTES, &mtr);
  2648. mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4,
  2649. extern_len - part_len,
  2650. MLOG_4BYTES, &mtr);
  2651. if (next_page_no == FIL_NULL) {
  2652. ut_a(extern_len - part_len == 0);
  2653. }
  2654. if (extern_len - part_len == 0) {
  2655. ut_a(next_page_no == FIL_NULL);
  2656. }
  2657. mtr_commit(&mtr);
  2658. }
  2659. }
  2660. /***************************************************************
  2661. Frees the externally stored fields for a record. */
  2662. void
  2663. btr_rec_free_externally_stored_fields(
  2664. /*==================================*/
  2665. dict_index_t* index, /* in: index of the data, the index
  2666. tree MUST be X-latched */
  2667. rec_t* rec, /* in: record */
  2668. ibool do_not_free_inherited,/* in: TRUE if called in a
  2669. rollback and we do not want to free
  2670. inherited fields */
  2671. mtr_t* mtr) /* in: mini-transaction handle which contains
  2672. an X-latch to record page and to the index
  2673. tree */
  2674. {
  2675. ulint n_fields;
  2676. byte* data;
  2677. ulint len;
  2678. ulint i;
  2679. ut_ad(mtr_memo_contains(mtr, buf_block_align(rec),
  2680. MTR_MEMO_PAGE_X_FIX));
  2681. if (rec_get_data_size(rec) <= REC_1BYTE_OFFS_LIMIT) {
  2682. return;
  2683. }
  2684. /* Free possible externally stored fields in the record */
  2685. n_fields = rec_get_n_fields(rec);
  2686. for (i = 0; i < n_fields; i++) {
  2687. if (rec_get_nth_field_extern_bit(rec, i)) {
  2688. data = rec_get_nth_field(rec, i, &len);
  2689. btr_free_externally_stored_field(index, data, len,
  2690. do_not_free_inherited, mtr);
  2691. }
  2692. }
  2693. }
  2694. /***************************************************************
  2695. Frees the externally stored fields for a record, if the field is mentioned
  2696. in the update vector. */
  2697. static
  2698. void
  2699. btr_rec_free_updated_extern_fields(
  2700. /*===============================*/
  2701. dict_index_t* index, /* in: index of rec; the index tree MUST be
  2702. X-latched */
  2703. rec_t* rec, /* in: record */
  2704. upd_t* update, /* in: update vector */
  2705. ibool do_not_free_inherited,/* in: TRUE if called in a
  2706. rollback and we do not want to free
  2707. inherited fields */
  2708. mtr_t* mtr) /* in: mini-transaction handle which contains
  2709. an X-latch to record page and to the tree */
  2710. {
  2711. upd_field_t* ufield;
  2712. ulint n_fields;
  2713. byte* data;
  2714. ulint len;
  2715. ulint i;
  2716. ut_ad(mtr_memo_contains(mtr, buf_block_align(rec),
  2717. MTR_MEMO_PAGE_X_FIX));
  2718. if (rec_get_data_size(rec) <= REC_1BYTE_OFFS_LIMIT) {
  2719. return;
  2720. }
  2721. /* Free possible externally stored fields in the record */
  2722. n_fields = upd_get_n_fields(update);
  2723. for (i = 0; i < n_fields; i++) {
  2724. ufield = upd_get_nth_field(update, i);
  2725. if (rec_get_nth_field_extern_bit(rec, ufield->field_no)) {
  2726. data = rec_get_nth_field(rec, ufield->field_no, &len);
  2727. btr_free_externally_stored_field(index, data, len,
  2728. do_not_free_inherited, mtr);
  2729. }
  2730. }
  2731. }
  2732. /***********************************************************************
  2733. Copies an externally stored field of a record to mem heap. Parameter
  2734. data contains a pointer to 'internally' stored part of the field:
  2735. possibly some data, and the reference to the externally stored part in
  2736. the last 20 bytes of data. */
  2737. byte*
  2738. btr_copy_externally_stored_field(
  2739. /*=============================*/
  2740. /* out: the whole field copied to heap */
  2741. ulint* len, /* out: length of the whole field */
  2742. byte* data, /* in: 'internally' stored part of the
  2743. field containing also the reference to
  2744. the external part */
  2745. ulint local_len,/* in: length of data */
  2746. mem_heap_t* heap) /* in: mem heap */
  2747. {
  2748. page_t* page;
  2749. ulint space_id;
  2750. ulint page_no;
  2751. ulint offset;
  2752. ulint extern_len;
  2753. byte* blob_header;
  2754. ulint part_len;
  2755. byte* buf;
  2756. ulint copied_len;
  2757. mtr_t mtr;
  2758. ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
  2759. local_len -= BTR_EXTERN_FIELD_REF_SIZE;
  2760. space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
  2761. page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
  2762. offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
  2763. /* Currently a BLOB cannot be bigger that 4 GB; we
  2764. leave the 4 upper bytes in the length field unused */
  2765. extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
  2766. buf = mem_heap_alloc(heap, local_len + extern_len);
  2767. ut_memcpy(buf, data, local_len);
  2768. copied_len = local_len;
  2769. if (extern_len == 0) {
  2770. *len = copied_len;
  2771. return(buf);
  2772. }
  2773. for (;;) {
  2774. mtr_start(&mtr);
  2775. page = buf_page_get(space_id, page_no, RW_S_LATCH, &mtr);
  2776. #ifdef UNIV_SYNC_DEBUG
  2777. buf_page_dbg_add_level(page, SYNC_EXTERN_STORAGE);
  2778. #endif /* UNIV_SYNC_DEBUG */
  2779. blob_header = page + offset;
  2780. part_len = btr_blob_get_part_len(blob_header);
  2781. ut_memcpy(buf + copied_len, blob_header + BTR_BLOB_HDR_SIZE,
  2782. part_len);
  2783. copied_len += part_len;
  2784. page_no = btr_blob_get_next_page_no(blob_header);
  2785. /* On other BLOB pages except the first the BLOB header
  2786. always is at the page data start: */
  2787. offset = FIL_PAGE_DATA;
  2788. mtr_commit(&mtr);
  2789. if (page_no == FIL_NULL) {
  2790. ut_a(copied_len == local_len + extern_len);
  2791. *len = copied_len;
  2792. return(buf);
  2793. }
  2794. ut_a(copied_len < local_len + extern_len);
  2795. }
  2796. }
  2797. /***********************************************************************
  2798. Copies an externally stored field of a record to mem heap. */
  2799. byte*
  2800. btr_rec_copy_externally_stored_field(
  2801. /*=================================*/
  2802. /* out: the field copied to heap */
  2803. rec_t* rec, /* in: record */
  2804. ulint no, /* in: field number */
  2805. ulint* len, /* out: length of the field */
  2806. mem_heap_t* heap) /* in: mem heap */
  2807. {
  2808. ulint local_len;
  2809. byte* data;
  2810. ut_a(rec_get_nth_field_extern_bit(rec, no));
  2811. /* An externally stored field can contain some initial
  2812. data from the field, and in the last 20 bytes it has the
  2813. space id, page number, and offset where the rest of the
  2814. field data is stored, and the data length in addition to
  2815. the data stored locally. We may need to store some data
  2816. locally to get the local record length above the 128 byte
  2817. limit so that field offsets are stored in two bytes, and
  2818. the extern bit is available in those two bytes. */
  2819. data = rec_get_nth_field(rec, no, &local_len);
  2820. return(btr_copy_externally_stored_field(len, data, local_len, heap));
  2821. }