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

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