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

MySQL数据库

开发平台:

Visual C++

  1. /************************************************************************
  2. The page cursor
  3. (c) 1994-1996 Innobase Oy
  4. Created 10/4/1994 Heikki Tuuri
  5. *************************************************************************/
  6. #include "page0cur.h"
  7. #ifdef UNIV_NONINL
  8. #include "page0cur.ic"
  9. #endif
  10. #include "rem0cmp.h"
  11. #include "mtr0log.h"
  12. ulint page_cur_short_succ = 0;
  13. ulint page_rnd = 976722341;
  14. #ifdef PAGE_CUR_ADAPT
  15. /********************************************************************
  16. Tries a search shortcut based on the last insert. */
  17. UNIV_INLINE
  18. ibool
  19. page_cur_try_search_shortcut(
  20. /*=========================*/
  21. page_t* page, /* in: index page */
  22. dtuple_t* tuple, /* in: data tuple */
  23. ulint* iup_matched_fields,
  24. /* in/out: already matched fields in upper
  25. limit record */
  26. ulint* iup_matched_bytes,
  27. /* in/out: already matched bytes in a field
  28. not yet completely matched */
  29. ulint* ilow_matched_fields,
  30. /* in/out: already matched fields in lower
  31. limit record */
  32. ulint* ilow_matched_bytes,
  33. /* in/out: already matched bytes in a field
  34. not yet completely matched */
  35. page_cur_t* cursor) /* out: page cursor */ 
  36. {
  37. int cmp;
  38. rec_t* rec;
  39. rec_t* next_rec;
  40. ulint low_match;
  41. ulint low_bytes;
  42. ulint up_match;
  43. ulint up_bytes;
  44. #ifdef UNIV_SEARCH_DEBUG
  45. page_cur_t cursor2;
  46. #endif
  47. ut_ad(dtuple_check_typed(tuple));
  48. rec = page_header_get_ptr(page, PAGE_LAST_INSERT);
  49. ut_ad(rec);
  50. ut_ad(page_rec_is_user_rec(rec));
  51. ut_pair_min(&low_match, &low_bytes,
  52. *ilow_matched_fields, *ilow_matched_bytes,
  53. *iup_matched_fields, *iup_matched_bytes);
  54. up_match = low_match;
  55. up_bytes = low_bytes;
  56. cmp = page_cmp_dtuple_rec_with_match(tuple, rec, &low_match,
  57. &low_bytes);
  58. if (cmp == -1) {
  59. return(FALSE);
  60. }
  61. next_rec = page_rec_get_next(rec);
  62. cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, &up_match,
  63. &up_bytes);
  64. if (cmp != -1) {
  65. return(FALSE);
  66. }
  67. cursor->rec = rec;
  68. #ifdef UNIV_SEARCH_DEBUG
  69. page_cur_search_with_match(page, tuple, PAGE_CUR_DBG,
  70.      iup_matched_fields,
  71.      iup_matched_bytes,
  72.      ilow_matched_fields,
  73.      ilow_matched_bytes,
  74.      &cursor2);
  75. ut_a(cursor2.rec == cursor->rec);
  76. if (next_rec != page_get_supremum_rec(page)) {
  77. ut_a(*iup_matched_fields == up_match);
  78. ut_a(*iup_matched_bytes == up_bytes);
  79. }
  80. ut_a(*ilow_matched_fields == low_match);
  81. ut_a(*ilow_matched_bytes == low_bytes);
  82. #endif
  83. if (next_rec != page_get_supremum_rec(page)) {
  84. *iup_matched_fields = up_match;
  85. *iup_matched_bytes = up_bytes;
  86. }
  87. *ilow_matched_fields = low_match;
  88. *ilow_matched_bytes = low_bytes;
  89. #ifdef UNIV_SEARCH_PERF_STAT
  90. page_cur_short_succ++;
  91. #endif
  92. return(TRUE);
  93. }
  94. #endif
  95. /********************************************************************
  96. Searches the right position for a page cursor. */
  97. void
  98. page_cur_search_with_match(
  99. /*=======================*/
  100. page_t* page, /* in: index page */
  101. dtuple_t* tuple, /* in: data tuple */
  102. ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
  103. or PAGE_CUR_GE */
  104. ulint* iup_matched_fields,
  105. /* in/out: already matched fields in upper
  106. limit record */
  107. ulint* iup_matched_bytes,
  108. /* in/out: already matched bytes in a field
  109. not yet completely matched */
  110. ulint* ilow_matched_fields,
  111. /* in/out: already matched fields in lower
  112. limit record */
  113. ulint* ilow_matched_bytes,
  114. /* in/out: already matched bytes in a field
  115. not yet completely matched */
  116. page_cur_t* cursor) /* out: page cursor */ 
  117. {
  118. ulint up;
  119. ulint low;
  120. ulint mid;
  121. page_dir_slot_t* slot;
  122. rec_t* up_rec;
  123. rec_t* low_rec;
  124. rec_t* mid_rec;
  125. ulint up_matched_fields;
  126. ulint up_matched_bytes;
  127. ulint low_matched_fields;
  128. ulint low_matched_bytes;
  129. ulint cur_matched_fields;
  130. ulint cur_matched_bytes;
  131. int cmp;
  132. #ifdef UNIV_SEARCH_DEBUG
  133. int dbg_cmp;
  134. ulint dbg_matched_fields;
  135. ulint dbg_matched_bytes;
  136. #endif
  137. ut_ad(page && tuple && iup_matched_fields && iup_matched_bytes
  138.       && ilow_matched_fields && ilow_matched_bytes && cursor);
  139. ut_ad(dtuple_validate(tuple));
  140. ut_ad(dtuple_check_typed(tuple));
  141. ut_ad((mode == PAGE_CUR_L) || (mode == PAGE_CUR_LE)
  142.       || (mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)
  143.       || (mode == PAGE_CUR_DBG));
  144.       
  145. #ifdef PAGE_CUR_ADAPT
  146. if ((page_header_get_field(page, PAGE_LEVEL) == 0)
  147.     && (mode == PAGE_CUR_LE)
  148.     && (page_header_get_field(page, PAGE_N_DIRECTION) > 3)
  149.     && (page_header_get_ptr(page, PAGE_LAST_INSERT))
  150.     && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) {
  151. if (page_cur_try_search_shortcut(page, tuple,
  152.      iup_matched_fields,
  153.      iup_matched_bytes,
  154.      ilow_matched_fields,
  155.      ilow_matched_bytes,
  156.      cursor)) {
  157.      return;
  158.      }
  159. }
  160. /*#ifdef UNIV_SEARCH_DEBUG */
  161. if (mode == PAGE_CUR_DBG) {
  162. mode = PAGE_CUR_LE;
  163. }
  164. /*#endif */
  165. #endif
  166. /* If mode PAGE_CUR_G is specified, we are trying to position the
  167. cursor to answer a query of the form "tuple < X", where tuple is
  168. the input parameter, and X denotes an arbitrary physical record on
  169. the page. We want to position the cursor on the first X which
  170. satisfies the condition. */
  171. up_matched_fields  = *iup_matched_fields;
  172. up_matched_bytes   = *iup_matched_bytes;
  173. low_matched_fields = *ilow_matched_fields;
  174. low_matched_bytes  = *ilow_matched_bytes;
  175. /* Perform binary search. First the search is done through the page
  176. directory, after that as a linear search in the list of records
  177. owned by the upper limit directory slot. */
  178. low = 0;
  179. up = page_dir_get_n_slots(page) - 1;
  180. /* Perform binary search until the lower and upper limit directory
  181. slots come to the distance 1 of each other */
  182.     while (up - low > 1) {
  183. mid = (low + up) / 2;
  184. slot = page_dir_get_nth_slot(page, mid);
  185. mid_rec = page_dir_slot_get_rec(slot);
  186. ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
  187. low_matched_fields, low_matched_bytes,
  188. up_matched_fields, up_matched_bytes);
  189. cmp = cmp_dtuple_rec_with_match(tuple, mid_rec,
  190. &cur_matched_fields,
  191. &cur_matched_bytes);
  192. if (cmp == 1) {
  193. low = mid;
  194. low_matched_fields = cur_matched_fields;
  195. low_matched_bytes = cur_matched_bytes;
  196. } else if (cmp == -1) {
  197. up = mid;
  198. up_matched_fields = cur_matched_fields;
  199. up_matched_bytes = cur_matched_bytes; 
  200. } else if ((mode == PAGE_CUR_G) || (mode == PAGE_CUR_LE)) {
  201. low = mid;
  202. low_matched_fields = cur_matched_fields;
  203. low_matched_bytes = cur_matched_bytes;
  204. } else {
  205. up = mid;
  206. up_matched_fields = cur_matched_fields;
  207. up_matched_bytes = cur_matched_bytes;
  208. }
  209.     }
  210. slot = page_dir_get_nth_slot(page, low);
  211. low_rec = page_dir_slot_get_rec(slot);
  212. slot = page_dir_get_nth_slot(page, up);
  213. up_rec = page_dir_slot_get_rec(slot);
  214. /* Perform linear search until the upper and lower records
  215. come to distance 1 of each other. */
  216.     while (page_rec_get_next(low_rec) != up_rec) {
  217. mid_rec = page_rec_get_next(low_rec);
  218. ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
  219. low_matched_fields, low_matched_bytes,
  220. up_matched_fields, up_matched_bytes);
  221. cmp = cmp_dtuple_rec_with_match(tuple, mid_rec,
  222. &cur_matched_fields,
  223. &cur_matched_bytes);
  224. if (cmp == 1) {
  225. low_rec = mid_rec;
  226. low_matched_fields = cur_matched_fields;
  227. low_matched_bytes = cur_matched_bytes;
  228. } else if (cmp == -1) {
  229. up_rec = mid_rec;
  230. up_matched_fields = cur_matched_fields;
  231. up_matched_bytes = cur_matched_bytes; 
  232. } else if ((mode == PAGE_CUR_G) || (mode == PAGE_CUR_LE)) {
  233. low_rec = mid_rec;
  234. low_matched_fields = cur_matched_fields;
  235. low_matched_bytes = cur_matched_bytes;
  236. } else {
  237. up_rec = mid_rec;
  238. up_matched_fields = cur_matched_fields;
  239. up_matched_bytes = cur_matched_bytes;
  240. }
  241.     }
  242. #ifdef UNIV_SEARCH_DEBUG
  243. /* Check that the lower and upper limit records have the
  244. right alphabetical order compared to tuple. */
  245. dbg_matched_fields = 0;
  246. dbg_matched_bytes = 0;
  247. dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, low_rec,
  248. &dbg_matched_fields,
  249. &dbg_matched_bytes);
  250. if (mode == PAGE_CUR_G) {
  251. ut_a(dbg_cmp >= 0);
  252. } else if (mode == PAGE_CUR_GE) {
  253. ut_a(dbg_cmp == 1);
  254. } else if (mode == PAGE_CUR_L) {
  255. ut_a(dbg_cmp == 1);
  256. } else if (mode == PAGE_CUR_LE) {
  257. ut_a(dbg_cmp >= 0);
  258. }
  259. if (low_rec != page_get_infimum_rec(page)) {
  260. ut_a(low_matched_fields == dbg_matched_fields);
  261. ut_a(low_matched_bytes == dbg_matched_bytes);
  262. }
  263. dbg_matched_fields = 0;
  264. dbg_matched_bytes = 0;
  265. dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, up_rec,
  266. &dbg_matched_fields,
  267. &dbg_matched_bytes);
  268. if (mode == PAGE_CUR_G) {
  269. ut_a(dbg_cmp == -1);
  270. } else if (mode == PAGE_CUR_GE) {
  271. ut_a(dbg_cmp <= 0);
  272. } else if (mode == PAGE_CUR_L) {
  273. ut_a(dbg_cmp <= 0);
  274. } else if (mode == PAGE_CUR_LE) {
  275. ut_a(dbg_cmp == -1);
  276. }
  277. if (up_rec != page_get_supremum_rec(page)) {
  278. ut_a(up_matched_fields == dbg_matched_fields);
  279. ut_a(up_matched_bytes == dbg_matched_bytes);
  280. }
  281. #endif
  282. if (mode <= PAGE_CUR_GE) {
  283. cursor->rec = up_rec;
  284. } else {
  285. cursor->rec = low_rec;
  286. }
  287. *iup_matched_fields  = up_matched_fields;
  288. *iup_matched_bytes   = up_matched_bytes;
  289. *ilow_matched_fields = low_matched_fields;
  290. *ilow_matched_bytes  = low_matched_bytes;
  291. }
  292. /***************************************************************
  293. Positions a page cursor on a randomly chosen user record on a page. If there
  294. are no user records, sets the cursor on the infimum record. */
  295. void
  296. page_cur_open_on_rnd_user_rec(
  297. /*==========================*/
  298. page_t* page, /* in: page */
  299. page_cur_t* cursor) /* in/out: page cursor */
  300. {
  301. ulint rnd;
  302. rec_t* rec;
  303. if (page_get_n_recs(page) == 0) {
  304. page_cur_position(page_get_infimum_rec(page), cursor);
  305. return;
  306. }
  307. page_rnd += 87584577;
  308. rnd = page_rnd % page_get_n_recs(page);
  309. rec = page_get_infimum_rec(page);
  310. rec = page_rec_get_next(rec);
  311. while (rnd > 0) {
  312. rec = page_rec_get_next(rec);
  313. rnd--;
  314. }
  315. page_cur_position(rec, cursor);
  316. }
  317. /***************************************************************
  318. Writes the log record of a record insert on a page. */
  319. static
  320. void
  321. page_cur_insert_rec_write_log(
  322. /*==========================*/
  323. rec_t* insert_rec, /* in: inserted physical record */
  324. ulint rec_size, /* in: insert_rec size */
  325. rec_t* cursor_rec, /* in: record the cursor is pointing to */
  326. mtr_t* mtr) /* in: mini-transaction handle */
  327. {
  328. ulint cur_rec_size;
  329. ulint extra_size;
  330. ulint cur_extra_size;
  331. ulint min_rec_size;
  332. byte* ins_ptr;
  333. byte* cur_ptr;
  334. ulint extra_info_yes;
  335. byte* log_ptr;
  336. ulint i;
  337. log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN);
  338. if (log_ptr == NULL) {
  339. return;
  340. }
  341. extra_size = rec_get_extra_size(insert_rec);
  342. cur_extra_size = rec_get_extra_size(cursor_rec);
  343. cur_rec_size = rec_get_size(cursor_rec);
  344. ins_ptr = insert_rec - extra_size;
  345. i = 0;
  346. if (cur_extra_size == extra_size) {
  347. min_rec_size = ut_min(cur_rec_size, rec_size);
  348. cur_ptr = cursor_rec - cur_extra_size;
  349. /* Find out the first byte in insert_rec which differs from
  350. cursor_rec; skip the bytes in the record info */
  351. for (;;) {
  352. if (i >= min_rec_size) {
  353. break;
  354. } else if (*ins_ptr == *cur_ptr) {
  355. i++;
  356. ins_ptr++;
  357. cur_ptr++;
  358. } else if ((i < extra_size)
  359.    && (i >= extra_size - REC_N_EXTRA_BYTES)) {
  360. i = extra_size;
  361. ins_ptr = insert_rec;
  362. cur_ptr = cursor_rec;
  363. } else {
  364. break;
  365. }
  366. }
  367. }
  368. if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
  369. log_ptr = mlog_write_initial_log_record_fast(insert_rec,
  370. MLOG_REC_INSERT, log_ptr, mtr);
  371. /* Write the cursor rec offset as a 2-byte ulint */
  372. mach_write_to_2(log_ptr, cursor_rec
  373. - buf_frame_align(cursor_rec));
  374. log_ptr += 2;
  375. }
  376. if ((rec_get_info_bits(insert_rec) != rec_get_info_bits(cursor_rec))
  377.     || (extra_size != cur_extra_size)
  378.     || (rec_size != cur_rec_size)) {
  379. extra_info_yes = 1;
  380. } else {
  381. extra_info_yes = 0;
  382. }
  383. /* Write the record end segment length and the extra info storage
  384. flag */
  385. log_ptr += mach_write_compressed(log_ptr, 2 * (rec_size - i)
  386. + extra_info_yes);
  387. if (extra_info_yes) {
  388. /* Write the info bits */
  389. mach_write_to_1(log_ptr, rec_get_info_bits(insert_rec));
  390. log_ptr++;
  391. /* Write the record origin offset */
  392. log_ptr += mach_write_compressed(log_ptr, extra_size);
  393. /* Write the mismatch index */
  394. log_ptr += mach_write_compressed(log_ptr, i);
  395. }
  396. /* Write to the log the inserted index record end segment which
  397. differs from the cursor record */
  398. if (rec_size - i < MLOG_BUF_MARGIN) {
  399. ut_memcpy(log_ptr, ins_ptr, rec_size - i);
  400. log_ptr += rec_size - i;
  401. }
  402. mlog_close(mtr, log_ptr);
  403. if (rec_size - i >= MLOG_BUF_MARGIN) {
  404. mlog_catenate_string(mtr, ins_ptr, rec_size - i);
  405. }
  406. }
  407. /***************************************************************
  408. Parses a log record of a record insert on a page. */
  409. byte*
  410. page_cur_parse_insert_rec(
  411. /*======================*/
  412. /* out: end of log record or NULL */
  413. ibool is_short,/* in: TRUE if short inserts */
  414. byte* ptr, /* in: buffer */
  415. byte* end_ptr,/* in: buffer end */
  416. page_t* page, /* in: page or NULL */
  417. mtr_t* mtr) /* in: mtr or NULL */
  418. {
  419. ulint extra_info_yes;
  420. ulint offset;
  421. ulint origin_offset;
  422. ulint end_seg_len;
  423. ulint mismatch_index;
  424. rec_t* cursor_rec;
  425. byte buf1[1024];
  426. byte* buf;
  427. ulint info_bits;
  428. page_cur_t cursor;
  429. if (!is_short) {
  430. /* Read the cursor rec offset as a 2-byte ulint */
  431. if (end_ptr < ptr + 2) {
  432. return(NULL);
  433. }
  434. offset = mach_read_from_2(ptr);
  435. ptr += 2;
  436. }
  437. ptr = mach_parse_compressed(ptr, end_ptr, &end_seg_len);
  438. if (ptr == NULL) {
  439. return(NULL);
  440. }
  441. extra_info_yes = end_seg_len & 0x1;
  442. end_seg_len = end_seg_len / 2;
  443. if (extra_info_yes) {
  444. /* Read the info bits */
  445. if (end_ptr < ptr + 1) {
  446. return(NULL);
  447. }
  448. info_bits = mach_read_from_1(ptr);
  449. ptr++;
  450. ptr = mach_parse_compressed(ptr, end_ptr, &origin_offset);
  451. if (ptr == NULL) {
  452. return(NULL);
  453. }
  454. ptr = mach_parse_compressed(ptr, end_ptr, &mismatch_index);
  455. if (ptr == NULL) {
  456. return(NULL);
  457. }
  458. }
  459. if (end_ptr < ptr + end_seg_len) {
  460. return(NULL);
  461. }
  462. if (page == NULL) {
  463. return(ptr + end_seg_len);
  464. }
  465. /* Read from the log the inserted index record end segment which
  466. differs from the cursor record */
  467. if (is_short) {
  468. cursor_rec = page_rec_get_prev(page_get_supremum_rec(page));
  469. } else {
  470. cursor_rec = page + offset;
  471. }
  472. if (extra_info_yes == 0) {
  473. info_bits = rec_get_info_bits(cursor_rec);
  474. origin_offset = rec_get_extra_size(cursor_rec);
  475. mismatch_index = rec_get_size(cursor_rec) - end_seg_len;
  476. if (mismatch_index + end_seg_len < 1024) {
  477. buf = buf1;
  478. } else {
  479. buf = mem_alloc(mismatch_index + end_seg_len);
  480. }
  481. /* Build the inserted record to buf */
  482. ut_memcpy(buf, rec_get_start(cursor_rec), mismatch_index);
  483. ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
  484. rec_set_info_bits(buf + origin_offset, info_bits);
  485. page_cur_position(cursor_rec, &cursor);
  486. page_cur_rec_insert(&cursor, buf + origin_offset, mtr);
  487. if (mismatch_index + end_seg_len >= 1024) {
  488. mem_free(buf);
  489. }
  490. return(ptr + end_seg_len);
  491. }
  492. /***************************************************************
  493. Inserts a record next to page cursor. Returns pointer to inserted record if
  494. succeed, i.e., enough space available, NULL otherwise. The record to be
  495. inserted can be in a data tuple or as a physical record. The other parameter
  496. must then be NULL. The cursor stays at the same position. */
  497. rec_t*
  498. page_cur_insert_rec_low(
  499. /*====================*/
  500. /* out: pointer to record if succeed, NULL
  501. otherwise */
  502. page_cur_t* cursor, /* in: a page cursor */
  503. dtuple_t*       tuple,  /* in: pointer to a data tuple or NULL */
  504. ulint data_size,/* in: data size of tuple */
  505. rec_t*       rec,   /* in: pointer to a physical record or NULL */
  506. mtr_t* mtr) /* in: mini-transaction handle */
  507. {
  508. byte* insert_buf = NULL;
  509. ulint rec_size;
  510. byte* page; /* the relevant page */
  511. rec_t* last_insert; /* cursor position at previous insert */
  512. rec_t* insert_rec; /* inserted record */
  513. ulint heap_no; /* heap number of the inserted record */
  514. rec_t* current_rec; /* current record after which the
  515. new record is inserted */
  516. rec_t* next_rec; /* next record after current before
  517. the insertion */
  518. ulint owner_slot; /* the slot which owns the inserted record */
  519. rec_t* owner_rec;
  520. ulint n_owned;
  521. ut_ad(cursor && mtr);
  522. ut_ad(tuple || rec);
  523. ut_ad(!(tuple && rec));
  524. ut_ad(rec || dtuple_check_typed(tuple));
  525. ut_ad(rec || (dtuple_get_data_size(tuple) == data_size));
  526. page = page_cur_get_page(cursor);
  527. ut_ad(cursor->rec != page_get_supremum_rec(page));
  528. /* 1. Get the size of the physical record in the page */
  529. if (tuple != NULL) {
  530. rec_size = data_size + rec_get_converted_extra_size(
  531. data_size,
  532. dtuple_get_n_fields(tuple));
  533. } else {
  534. rec_size = rec_get_size(rec);
  535. }
  536. /* 2. Try to find suitable space from page memory management */
  537. insert_buf = page_mem_alloc(page, rec_size, &heap_no);
  538. if (insert_buf == NULL) {
  539. return(NULL);
  540. }
  541. /* 3. Create the record */
  542. if (tuple != NULL) {
  543. insert_rec = rec_convert_dtuple_to_rec_low(insert_buf, tuple,
  544. data_size);
  545. } else {
  546. insert_rec = rec_copy(insert_buf, rec);
  547. }
  548. ut_ad(insert_rec);
  549. ut_ad(rec_size == rec_get_size(insert_rec));
  550. /* 4. Insert the record in the linked list of records */
  551. current_rec = cursor->rec;
  552. next_rec = page_rec_get_next(current_rec);
  553. page_rec_set_next(insert_rec, next_rec);
  554. page_rec_set_next(current_rec, insert_rec);
  555. page_header_set_field(page, PAGE_N_RECS, 1 + page_get_n_recs(page));
  556. /* 5. Set the n_owned field in the inserted record to zero,
  557. and set the heap_no field */
  558. rec_set_n_owned(insert_rec, 0);
  559. rec_set_heap_no(insert_rec, heap_no);
  560. /* 6. Update the last insertion info in page header */
  561. last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
  562. if (last_insert == NULL) {
  563.      page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
  564.      page_header_set_field(page, PAGE_N_DIRECTION, 0);
  565. } else if ((last_insert == current_rec)
  566.     && (page_header_get_field(page, PAGE_DIRECTION) != PAGE_LEFT)) {
  567.      page_header_set_field(page, PAGE_DIRECTION, PAGE_RIGHT);
  568.      page_header_set_field(page, PAGE_N_DIRECTION,
  569. page_header_get_field(page, PAGE_N_DIRECTION) + 1);
  570. } else if ((page_rec_get_next(insert_rec) == last_insert)
  571.     && (page_header_get_field(page, PAGE_DIRECTION) != PAGE_RIGHT)) {
  572.      page_header_set_field(page, PAGE_DIRECTION, PAGE_LEFT);
  573.      page_header_set_field(page, PAGE_N_DIRECTION,
  574. page_header_get_field(page, PAGE_N_DIRECTION) + 1);
  575. } else {
  576.      page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
  577.      page_header_set_field(page, PAGE_N_DIRECTION, 0);
  578. }
  579. page_header_set_ptr(page, PAGE_LAST_INSERT, insert_rec);
  580. /* 7. It remains to update the owner record. */
  581. owner_rec = page_rec_find_owner_rec(insert_rec);
  582. n_owned = rec_get_n_owned(owner_rec);
  583. rec_set_n_owned(owner_rec, n_owned + 1);
  584. /* 8. Now we have incremented the n_owned field of the owner
  585. record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
  586. we have to split the corresponding directory slot in two. */
  587. if (n_owned == PAGE_DIR_SLOT_MAX_N_OWNED) {
  588. owner_slot = page_dir_find_owner_slot(owner_rec);
  589. page_dir_split_slot(page, owner_slot);
  590. }
  591. /* 9. Write log record of the insert */
  592.   page_cur_insert_rec_write_log(insert_rec, rec_size, current_rec, mtr);
  593. return(insert_rec);
  594. }
  595. /**************************************************************
  596. Writes a log record of copying a record list end to a new created page. */
  597. UNIV_INLINE
  598. byte*
  599. page_copy_rec_list_to_created_page_write_log(
  600. /*=========================================*/
  601. /* out: 4-byte field where to write the log data
  602. length */
  603. page_t* page, /* in: index page */
  604. mtr_t* mtr) /* in: mtr */
  605. {
  606. byte* log_ptr;
  607. mlog_write_initial_log_record(page, MLOG_LIST_END_COPY_CREATED, mtr);
  608. log_ptr = mlog_open(mtr, 4);
  609. mlog_close(mtr, log_ptr + 4);
  610. return(log_ptr);
  611. }
  612. /**************************************************************
  613. Parses a log record of copying a record list end to a new created page. */
  614. byte*
  615. page_parse_copy_rec_list_to_created_page(
  616. /*=====================================*/
  617. /* out: end of log record or NULL */
  618. byte* ptr, /* in: buffer */
  619. byte* end_ptr,/* in: buffer end */
  620. page_t* page, /* in: page or NULL */
  621. mtr_t* mtr) /* in: mtr or NULL */
  622. {
  623. byte* rec_end;
  624. ulint log_data_len;
  625. if (ptr + 4 > end_ptr) {
  626. return(NULL);
  627. }
  628. log_data_len = mach_read_from_4(ptr);
  629. ptr += 4;
  630. rec_end = ptr + log_data_len;
  631. if (rec_end > end_ptr) {
  632. return(NULL);
  633. }
  634. if (!page) {
  635. return(rec_end);
  636. }
  637. while (ptr < rec_end) {
  638. ptr = page_cur_parse_insert_rec(TRUE, ptr, end_ptr, page, mtr);
  639. }
  640. ut_a(ptr == rec_end);
  641. page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
  642. page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
  643. page_header_set_field(page, PAGE_N_DIRECTION, 0);
  644. return(rec_end);
  645. }
  646. /*****************************************************************
  647. Copies records from page to a newly created page, from a given record onward,
  648. including that record. Infimum and supremum records are not copied. */
  649. void
  650. page_copy_rec_list_end_to_created_page(
  651. /*===================================*/
  652. page_t* new_page, /* in: index page to copy to */
  653. page_t* page, /* in: index page */
  654. rec_t* rec, /* in: first record to copy */
  655. mtr_t* mtr) /* in: mtr */
  656. {
  657. page_dir_slot_t* slot;
  658. byte* heap_top;
  659. rec_t* insert_rec;
  660. rec_t* prev_rec;
  661. ulint count;
  662. ulint n_recs;
  663. ulint slot_index;
  664. ulint rec_size;
  665. ulint log_mode;
  666. byte* log_ptr;
  667. ulint log_data_len;
  668. ut_ad(page_header_get_field(new_page, PAGE_N_HEAP) == 2);
  669. ut_ad(page != new_page);
  670. if (rec == page_get_infimum_rec(page)) {
  671. rec = page_rec_get_next(rec);
  672. }
  673. if (rec == page_get_supremum_rec(page)) {
  674. return;
  675. }
  676. #ifdef UNIV_DEBUG
  677. /* To pass the debug tests we have to set these dummy values
  678. in the debug version */
  679. page_header_set_field(new_page, PAGE_N_DIR_SLOTS, UNIV_PAGE_SIZE / 2);
  680. page_header_set_ptr(new_page, PAGE_HEAP_TOP,
  681. new_page + UNIV_PAGE_SIZE - 1);
  682. #endif
  683. log_ptr = page_copy_rec_list_to_created_page_write_log(new_page, mtr);
  684. log_data_len = dyn_array_get_data_size(&(mtr->log));
  685. /* Individual inserts are logged in a shorter form */
  686. log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
  687. prev_rec = page_get_infimum_rec(new_page);
  688. heap_top = new_page + PAGE_SUPREMUM_END;
  689. count = 0;
  690. slot_index = 0;
  691. n_recs = 0;
  692. while (rec != page_get_supremum_rec(page)) {
  693. insert_rec = rec_copy(heap_top, rec);
  694. rec_set_next_offs(prev_rec, insert_rec - new_page);
  695. rec_set_n_owned(insert_rec, 0);
  696. rec_set_heap_no(insert_rec, 2 + n_recs);
  697. rec_size = rec_get_size(insert_rec);
  698. heap_top = heap_top + rec_size;
  699. ut_ad(heap_top < new_page + UNIV_PAGE_SIZE);
  700. count++;
  701. n_recs++;
  702. if (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2) {
  703. slot_index++;
  704. slot = page_dir_get_nth_slot(new_page, slot_index);
  705. page_dir_slot_set_rec(slot, insert_rec);
  706. page_dir_slot_set_n_owned(slot, count);
  707. count = 0;
  708. }
  709.   page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec,
  710. mtr);
  711. prev_rec = insert_rec;
  712. rec = page_rec_get_next(rec);
  713. }
  714. if ((slot_index > 0) && (count + 1
  715. + (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2
  716.        <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
  717. /* We can merge the two last dir slots. This operation is
  718. here to make this function imitate exactly the equivalent
  719. task made using page_cur_insert_rec, which we use in database
  720. recovery to reproduce the task performed by this function.
  721. To be able to check the correctness of recovery, it is good
  722. that it imitates exactly. */
  723. count += (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2;
  724. page_dir_slot_set_n_owned(slot, 0);
  725. slot_index--;
  726. }
  727. log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len;
  728. mach_write_to_4(log_ptr, log_data_len);
  729. rec_set_next_offs(insert_rec, PAGE_SUPREMUM);
  730. slot = page_dir_get_nth_slot(new_page, 1 + slot_index);
  731. page_dir_slot_set_rec(slot, page_get_supremum_rec(new_page));
  732. page_dir_slot_set_n_owned(slot, count + 1);
  733. page_header_set_field(new_page, PAGE_N_DIR_SLOTS, 2 + slot_index);
  734. page_header_set_ptr(new_page, PAGE_HEAP_TOP, heap_top);
  735. page_header_set_field(new_page, PAGE_N_HEAP, 2 + n_recs);
  736. page_header_set_field(new_page, PAGE_N_RECS, n_recs);
  737. page_header_set_ptr(new_page, PAGE_LAST_INSERT, NULL);
  738. page_header_set_field(new_page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
  739. page_header_set_field(new_page, PAGE_N_DIRECTION, 0);
  740. /* Restore the log mode */
  741. mtr_set_log_mode(mtr, log_mode);
  742. }
  743. /***************************************************************
  744. Writes log record of a record delete on a page. */
  745. UNIV_INLINE
  746. void
  747. page_cur_delete_rec_write_log(
  748. /*==========================*/
  749. rec_t* cursor_rec, /* in: record to be deleted */
  750. mtr_t* mtr) /* in: mini-transaction handle */
  751. {
  752. mlog_write_initial_log_record(cursor_rec, MLOG_REC_DELETE, mtr);
  753. /* Write the cursor rec offset as a 2-byte ulint */
  754. mlog_catenate_ulint(mtr, cursor_rec - buf_frame_align(cursor_rec),
  755. MLOG_2BYTES);
  756. }
  757. /***************************************************************
  758. Parses log record of a record delete on a page. */
  759. byte*
  760. page_cur_parse_delete_rec(
  761. /*======================*/
  762. /* out: pointer to record end or NULL */
  763. byte* ptr, /* in: buffer */
  764. byte* end_ptr,/* in: buffer end */
  765. page_t* page, /* in: page or NULL */
  766. mtr_t* mtr) /* in: mtr or NULL */
  767. {
  768. ulint offset;
  769. page_cur_t cursor;
  770. if (end_ptr < ptr + 2) {
  771. return(NULL);
  772. }
  773. /* Read the cursor rec offset as a 2-byte ulint */
  774. offset = mach_read_from_2(ptr);
  775. ptr += 2;
  776. if (page) {
  777. page_cur_position(page + offset, &cursor);
  778. page_cur_delete_rec(&cursor, mtr);
  779. }
  780. return(ptr);
  781. }
  782. /***************************************************************
  783. Deletes a record at the page cursor. The cursor is moved to the next
  784. record after the deleted one. */
  785. void
  786. page_cur_delete_rec(
  787. /*================*/
  788. page_cur_t*   cursor, /* in: a page cursor */
  789. mtr_t* mtr) /* in: mini-transaction handle */
  790. {
  791. page_t* page;
  792. rec_t* current_rec;
  793. rec_t* prev_rec = NULL;
  794. rec_t* next_rec;
  795. ulint cur_slot_no;
  796. page_dir_slot_t* cur_dir_slot;
  797. page_dir_slot_t* prev_slot;
  798. ulint cur_n_owned;
  799. rec_t* rec;
  800. ut_ad(cursor && mtr);
  801. page = page_cur_get_page(cursor);
  802. current_rec = cursor->rec;
  803. /* The record must not be the supremum or infimum record. */
  804. ut_ad(current_rec != page_get_supremum_rec(page));
  805. ut_ad(current_rec != page_get_infimum_rec(page));
  806. /* Save to local variables some data associated with current_rec */
  807. cur_slot_no = page_dir_find_owner_slot(current_rec);
  808. cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no);
  809. cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
  810. /* 0. Write the log record */
  811. page_cur_delete_rec_write_log(current_rec, mtr);
  812. /* 1. Reset the last insert info in the page header and increment
  813. the modify clock for the frame */
  814. page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
  815. /* The page gets invalid for optimistic searches: increment the
  816. frame modify clock */
  817. buf_frame_modify_clock_inc(page);
  818. /* 2. Find the next and the previous record. Note that the cursor is
  819. left at the next record. */
  820. ut_ad(cur_slot_no > 0);
  821. prev_slot = page_dir_get_nth_slot(page, cur_slot_no - 1);
  822. rec = page_dir_slot_get_rec(prev_slot);
  823. /* rec now points to the record of the previous directory slot. Look
  824. for the immediate predecessor of current_rec in a loop. */
  825. while(current_rec != rec) {
  826. prev_rec = rec;
  827. rec = page_rec_get_next(rec);
  828. }
  829. page_cur_move_to_next(cursor);
  830. next_rec = cursor->rec;
  831. /* 3. Remove the record from the linked list of records */
  832. page_rec_set_next(prev_rec, next_rec);
  833. page_header_set_field(page, PAGE_N_RECS,
  834. (ulint)(page_get_n_recs(page) - 1));
  835. /* 4. If the deleted record is pointed to by a dir slot, update the
  836. record pointer in slot. In the following if-clause we assume that
  837. prev_rec is owned by the same slot, i.e., PAGE_DIR_SLOT_MIN_N_OWNED
  838. >= 2. */
  839. ut_ad(PAGE_DIR_SLOT_MIN_N_OWNED >= 2);
  840. ut_ad(cur_n_owned > 1);
  841. if (current_rec == page_dir_slot_get_rec(cur_dir_slot)) {
  842. page_dir_slot_set_rec(cur_dir_slot, prev_rec);
  843. }
  844. /* 5. Update the number of owned records of the slot */
  845. page_dir_slot_set_n_owned(cur_dir_slot, cur_n_owned - 1);
  846. /* 6. Free the memory occupied by the record */
  847. page_mem_free(page, current_rec);
  848. /* 7. Now we have decremented the number of owned records of the slot.
  849. If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
  850. slots. */
  851. if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) {
  852. page_dir_balance_slot(page, cur_slot_no);
  853. }
  854. }