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

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Index page routines
  3. (c) 1994-1996 Innobase Oy
  4. Created 2/2/1994 Heikki Tuuri
  5. *******************************************************/
  6. #include "mach0data.h"
  7. #include "rem0cmp.h"
  8. #include "mtr0log.h"
  9. #ifdef UNIV_MATERIALIZE
  10. #undef UNIV_INLINE
  11. #define UNIV_INLINE
  12. #endif
  13. /*****************************************************************
  14. Returns the max trx id field value. */
  15. UNIV_INLINE
  16. dulint
  17. page_get_max_trx_id(
  18. /*================*/
  19. page_t* page) /* in: page */
  20. {
  21. ut_ad(page);
  22. return(mach_read_from_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID));
  23. }
  24. /*****************************************************************
  25. Sets the max trx id field value if trx_id is bigger than the previous
  26. value. */
  27. UNIV_INLINE
  28. void
  29. page_update_max_trx_id(
  30. /*===================*/
  31. page_t* page, /* in: page */
  32. dulint trx_id) /* in: transaction id */
  33. {
  34. ut_ad(page);
  35. if (ut_dulint_cmp(page_get_max_trx_id(page), trx_id) < 0) {
  36. page_set_max_trx_id(page, trx_id);
  37. }
  38. }
  39. /*****************************************************************
  40. Reads the given header field. */
  41. UNIV_INLINE
  42. ulint
  43. page_header_get_field(
  44. /*==================*/
  45. page_t* page, /* in: page */
  46. ulint field) /* in: PAGE_LEVEL, ... */
  47. {
  48. ut_ad(page);
  49. ut_ad(field <= PAGE_INDEX_ID);
  50. return(mach_read_from_2(page + PAGE_HEADER + field));
  51. }
  52. /*****************************************************************
  53. Sets the given header field. */
  54. UNIV_INLINE
  55. void
  56. page_header_set_field(
  57. /*==================*/
  58. page_t* page, /* in: page */
  59. ulint field, /* in: PAGE_LEVEL, ... */
  60. ulint val) /* in: value */
  61. {
  62. ut_ad(page);
  63. ut_ad(field <= PAGE_N_RECS);
  64. ut_ad(val < UNIV_PAGE_SIZE);
  65. mach_write_to_2(page + PAGE_HEADER + field, val);
  66. }
  67. /*****************************************************************
  68. Returns the pointer stored in the given header field. */
  69. UNIV_INLINE
  70. byte*
  71. page_header_get_ptr(
  72. /*================*/
  73. /* out: pointer or NULL */
  74. page_t* page, /* in: page */
  75. ulint field) /* in: PAGE_FREE, ... */
  76. {
  77. ulint offs;
  78. ut_ad(page);
  79. ut_ad((field == PAGE_FREE)
  80.       || (field == PAGE_LAST_INSERT)
  81.       || (field == PAGE_HEAP_TOP));
  82. offs = page_header_get_field(page, field);
  83. ut_ad((field != PAGE_HEAP_TOP) || offs);
  84. if (offs == 0) {
  85. return(NULL);
  86. }
  87. return(page + offs);
  88. }
  89. /*****************************************************************
  90. Sets the pointer stored in the given header field. */
  91. UNIV_INLINE
  92. void
  93. page_header_set_ptr(
  94. /*================*/
  95. page_t* page, /* in: page */
  96. ulint field, /* in: PAGE_FREE, ... */
  97. byte* ptr) /* in: pointer or NULL*/
  98. {
  99. ulint offs;
  100. ut_ad(page);
  101. ut_ad((field == PAGE_FREE)
  102.       || (field == PAGE_LAST_INSERT)
  103.       || (field == PAGE_HEAP_TOP));
  104. if (ptr == NULL) {
  105. offs = 0;
  106. } else {
  107. offs = ptr - page;
  108. }
  109. ut_ad((field != PAGE_HEAP_TOP) || offs);
  110. page_header_set_field(page, field, offs);
  111. }
  112. /*****************************************************************
  113. Resets the last insert info field in the page header. Writes to mlog
  114. about this operation. */
  115. UNIV_INLINE
  116. void
  117. page_header_reset_last_insert(
  118. /*==========================*/
  119. page_t* page, /* in: page */
  120. mtr_t* mtr) /* in: mtr */
  121. {
  122. ut_ad(page && mtr);
  123. mlog_write_ulint(page + PAGE_HEADER + PAGE_LAST_INSERT, 0,
  124. MLOG_2BYTES, mtr);
  125. }
  126. /****************************************************************
  127. Gets the first record on the page. */
  128. UNIV_INLINE
  129. rec_t*
  130. page_get_infimum_rec(
  131. /*=================*/
  132. /* out: the first record in record list */
  133. page_t* page) /* in: page which must have record(s) */
  134. {
  135. ut_ad(page);
  136. return(page + PAGE_INFIMUM);
  137. }
  138. /****************************************************************
  139. Gets the last record on the page. */
  140. UNIV_INLINE
  141. rec_t*
  142. page_get_supremum_rec(
  143. /*==================*/
  144. /* out: the last record in record list */
  145. page_t* page) /* in: page which must have record(s) */
  146. {
  147. ut_ad(page);
  148. return(page + PAGE_SUPREMUM);
  149. }
  150. /****************************************************************
  151. TRUE if the record is a user record on the page. */
  152. UNIV_INLINE
  153. ibool
  154. page_rec_is_user_rec(
  155. /*=================*/
  156. /* out: TRUE if a user record */
  157. rec_t* rec) /* in: record */
  158. {
  159. ut_ad(rec);
  160. if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
  161. return(FALSE);
  162. }
  163. if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
  164.       return(FALSE);
  165. }
  166. return(TRUE);
  167. }
  168. /****************************************************************
  169. TRUE if the record is the supremum record on a page. */
  170. UNIV_INLINE
  171. ibool
  172. page_rec_is_supremum(
  173. /*=================*/
  174. /* out: TRUE if the supremum record */
  175. rec_t* rec) /* in: record */
  176. {
  177. ut_ad(rec);
  178. if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
  179. return(TRUE);
  180. }
  181. return(FALSE);
  182. }
  183. /****************************************************************
  184. TRUE if the record is the infimum record on a page. */
  185. UNIV_INLINE
  186. ibool
  187. page_rec_is_infimum(
  188. /*================*/
  189. /* out: TRUE if the infimum record */
  190. rec_t* rec) /* in: record */
  191. {
  192. ut_ad(rec);
  193. if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
  194. return(TRUE);
  195. }
  196. return(FALSE);
  197. }
  198. /****************************************************************
  199. TRUE if the record is the first user record on the page. */
  200. UNIV_INLINE
  201. ibool
  202. page_rec_is_first_user_rec(
  203. /*=======================*/
  204. /* out: TRUE if first user record */
  205. rec_t* rec) /* in: record */
  206. {
  207. ut_ad(rec);
  208. if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
  209. return(FALSE);
  210. }
  211. if (rec == page_rec_get_next(
  212.       page_get_infimum_rec(buf_frame_align(rec)))) {
  213.       return(TRUE);
  214. }
  215. return(FALSE);
  216. }
  217. /****************************************************************
  218. TRUE if the record is the last user record on the page. */
  219. UNIV_INLINE
  220. ibool
  221. page_rec_is_last_user_rec(
  222. /*======================*/
  223. /* out: TRUE if last user record */
  224. rec_t* rec) /* in: record */
  225. {
  226. ut_ad(rec);
  227. if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
  228. return(FALSE);
  229. }
  230. if (page_rec_get_next(rec)
  231. == page_get_supremum_rec(buf_frame_align(rec))) {
  232.       return(TRUE);
  233. }
  234. return(FALSE);
  235. }
  236. /*****************************************************************
  237. Compares a data tuple to a physical record. Differs from the function
  238. cmp_dtuple_rec_with_match in the way that the record must reside on an
  239. index page, and also page infimum and supremum records can be given in
  240. the parameter rec. These are considered as the negative infinity and
  241. the positive infinity in the alphabetical order. */
  242. UNIV_INLINE
  243. int
  244. page_cmp_dtuple_rec_with_match(
  245. /*===========================*/
  246. /* out: 1, 0, -1, if dtuple is greater, equal, 
  247. less than rec, respectively, when only the 
  248. common first fields are compared */
  249. dtuple_t* dtuple, /* in: data tuple */
  250. rec_t* rec, /* in: physical record on a page; may also 
  251. be page infimum or supremum, in which case 
  252. matched-parameter values below are not 
  253. affected */
  254. ulint*   matched_fields, /* in/out: number of already completely 
  255. matched fields; when function returns
  256. contains the value for current comparison */
  257. ulint*    matched_bytes) /* in/out: number of already matched 
  258. bytes within the first field not completely
  259. matched; when function returns contains the
  260. value for current comparison */
  261. {
  262. page_t* page;
  263. ut_ad(dtuple_check_typed(dtuple));
  264. page = buf_frame_align(rec);
  265. if (rec == page_get_infimum_rec(page)) {
  266. return(1);
  267. } else if (rec == page_get_supremum_rec(page)) {
  268. return(-1);
  269. } else {
  270. return(cmp_dtuple_rec_with_match(dtuple, rec,
  271. matched_fields,
  272. matched_bytes));
  273. }
  274. }
  275. /*****************************************************************
  276. Gets the number of user records on page (infimum and supremum records
  277. are not user records). */
  278. UNIV_INLINE
  279. ulint
  280. page_get_n_recs(
  281. /*============*/
  282. /* out: number of user records */
  283. page_t* page) /* in: index page */
  284. {
  285. return(page_header_get_field(page, PAGE_N_RECS));
  286. }
  287. /*****************************************************************
  288. Gets the number of dir slots in directory. */
  289. UNIV_INLINE
  290. ulint
  291. page_dir_get_n_slots(
  292. /*=================*/
  293. /* out: number of slots */
  294. page_t* page) /* in: index page */
  295. {
  296. return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
  297. }
  298. /*****************************************************************
  299. Gets pointer to nth directory slot. */
  300. UNIV_INLINE
  301. page_dir_slot_t*
  302. page_dir_get_nth_slot(
  303. /*==================*/
  304. /* out: pointer to dir slot */
  305. page_t* page, /* in: index page */
  306. ulint n) /* in: position */
  307. {
  308. ut_ad(page_header_get_field(page, PAGE_N_DIR_SLOTS) > n);
  309. return(page + UNIV_PAGE_SIZE - PAGE_DIR
  310. - (n + 1) * PAGE_DIR_SLOT_SIZE);
  311. }
  312. /******************************************************************
  313. Used to check the consistency of a record on a page. */
  314. UNIV_INLINE
  315. ibool
  316. page_rec_check(
  317. /*===========*/
  318. /* out: TRUE if succeed */
  319. rec_t* rec) /* in: record */
  320. {
  321. page_t* page;
  322. ut_a(rec);
  323. page = buf_frame_align(rec);
  324. ut_a(rec <= page_header_get_ptr(page, PAGE_HEAP_TOP));
  325. ut_a(rec >= page + PAGE_DATA);
  326. return(TRUE);
  327. }
  328. /******************************************************************
  329. Used to check the consistency of a directory slot. */
  330. UNIV_INLINE
  331. ibool
  332. page_dir_slot_check(
  333. /*================*/
  334. /* out: TRUE if succeed */
  335. page_dir_slot_t* slot) /* in: slot */
  336. {
  337. page_t* page;
  338. ulint n_slots;
  339. ulint n_owned;
  340. ut_a(slot);
  341. page = buf_frame_align(slot);
  342. n_slots = page_header_get_field(page, PAGE_N_DIR_SLOTS);
  343. ut_a(slot <= page_dir_get_nth_slot(page, 0));
  344. ut_a(slot >= page_dir_get_nth_slot(page, n_slots - 1));
  345. ut_a(page_rec_check(page + mach_read_from_2(slot)));
  346. n_owned = rec_get_n_owned(page + mach_read_from_2(slot));
  347. if (slot == page_dir_get_nth_slot(page, 0)) {
  348. ut_a(n_owned == 1);
  349. } else if (slot == page_dir_get_nth_slot(page, n_slots - 1)) {
  350. ut_a(n_owned >= 1);
  351. ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
  352. } else {
  353. ut_a(n_owned >= PAGE_DIR_SLOT_MIN_N_OWNED);
  354. ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
  355. }
  356. return(TRUE);
  357. }
  358. /*******************************************************************
  359. Gets the record pointed to by a directory slot. */
  360. UNIV_INLINE
  361. rec_t*
  362. page_dir_slot_get_rec(
  363. /*==================*/
  364. /* out: pointer to record */
  365. page_dir_slot_t* slot) /* in: directory slot */
  366. {
  367. return(buf_frame_align(slot) + mach_read_from_2(slot));
  368. }
  369. /*******************************************************************
  370. This is used to set the record offset in a directory slot. */
  371. UNIV_INLINE
  372. void
  373. page_dir_slot_set_rec(
  374. /*==================*/
  375. page_dir_slot_t* slot, /* in: directory slot */
  376. rec_t*  rec) /* in: record on the page */
  377. {
  378. ut_ad(page_rec_check(rec));
  379. mach_write_to_2(slot, rec - buf_frame_align(rec));
  380. }
  381. /*******************************************************************
  382. Gets the number of records owned by a directory slot. */
  383. UNIV_INLINE
  384. ulint
  385. page_dir_slot_get_n_owned(
  386. /*======================*/
  387. /* out: number of records */
  388. page_dir_slot_t*  slot) /* in: page directory slot */
  389. {
  390. return(rec_get_n_owned(page_dir_slot_get_rec(slot)));
  391. }
  392. /*******************************************************************
  393. This is used to set the owned records field of a directory slot. */
  394. UNIV_INLINE
  395. void
  396. page_dir_slot_set_n_owned(
  397. /*======================*/
  398. page_dir_slot_t* slot, /* in: directory slot */
  399. ulint n) /* in: number of records owned 
  400. by the slot */
  401. {
  402. rec_set_n_owned(page_dir_slot_get_rec(slot), n);
  403. }
  404. /****************************************************************
  405. Calculates the space reserved for directory slots of a given number of
  406. records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
  407. PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
  408. UNIV_INLINE
  409. ulint
  410. page_dir_calc_reserved_space(
  411. /*=========================*/
  412. ulint n_recs) /* in: number of records */
  413. {
  414. return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
  415. / PAGE_DIR_SLOT_MIN_N_OWNED);
  416. /****************************************************************
  417. Gets the pointer to the next record on the page. */
  418. UNIV_INLINE
  419. rec_t*
  420. page_rec_get_next(
  421. /*==============*/
  422. /* out: pointer to next record */
  423. rec_t* rec) /* in: pointer to record */
  424. {
  425. ulint offs;
  426. page_t* page;
  427. ut_ad(page_rec_check(rec));
  428. page = buf_frame_align(rec);
  429. offs = rec_get_next_offs(rec);
  430. if (offs == 0) {
  431. return(NULL);
  432. }
  433. return(page + offs);
  434. }
  435. /*******************************************************************
  436. Looks for the directory slot which owns the given record. */
  437. UNIV_INLINE
  438. ulint
  439. page_dir_find_owner_slot(
  440. /*=====================*/
  441. /* out: the directory slot number */
  442. rec_t* rec) /* in: the physical record */
  443. {
  444. ulint i;
  445. page_t* page;
  446. page_dir_slot_t* slot;
  447. ut_ad(page_rec_check(rec));
  448. while (rec_get_n_owned(rec) == 0) {
  449. rec = page_rec_get_next(rec);
  450. }
  451. page = buf_frame_align(rec);
  452. i = page_dir_get_n_slots(page) - 1;
  453. slot = page_dir_get_nth_slot(page, i); 
  454. while (page_dir_slot_get_rec(slot) != rec) {
  455. i--;
  456. slot = page_dir_get_nth_slot(page, i); 
  457. }
  458. return(i);
  459. }
  460. /****************************************************************
  461. Sets the pointer to the next record on the page. */ 
  462. UNIV_INLINE
  463. void
  464. page_rec_set_next(
  465. /*==============*/
  466. rec_t* rec, /* in: pointer to record, must not be page supremum */
  467. rec_t* next) /* in: pointer to next record, must not be page
  468. infimum */
  469. {
  470. page_t* page;
  471. ut_ad(page_rec_check(rec));
  472. ut_ad((next == NULL)
  473.       || (buf_frame_align(rec) == buf_frame_align(next)));
  474. page = buf_frame_align(rec);
  475. ut_ad(rec != page_get_supremum_rec(page));
  476. ut_ad(next != page_get_infimum_rec(page));
  477. if (next == NULL) {
  478. rec_set_next_offs(rec, 0);
  479. } else {
  480. rec_set_next_offs(rec, (ulint)(next - page));
  481. }
  482. }
  483. /****************************************************************
  484. Gets the pointer to the previous record. */
  485. UNIV_INLINE
  486. rec_t*
  487. page_rec_get_prev(
  488. /*==============*/
  489. /* out: pointer to previous record */
  490. rec_t* rec) /* in: pointer to record, must not be page
  491. infimum */
  492. {
  493. page_dir_slot_t* slot;
  494. ulint slot_no;
  495. rec_t* rec2;
  496. rec_t* prev_rec = NULL;
  497. page_t* page;
  498. ut_ad(page_rec_check(rec));
  499. page = buf_frame_align(rec);
  500. ut_ad(rec != page_get_infimum_rec(page));
  501. slot_no = page_dir_find_owner_slot(rec);
  502. ut_ad(slot_no != 0);
  503. slot = page_dir_get_nth_slot(page, slot_no - 1);
  504. rec2 = page_dir_slot_get_rec(slot);
  505. while (rec != rec2) {
  506. prev_rec = rec2;
  507. rec2 = page_rec_get_next(rec2);
  508. }
  509. ut_ad(prev_rec);
  510. return(prev_rec);
  511. }
  512. /*******************************************************************
  513. Looks for the record which owns the given record. */
  514. UNIV_INLINE
  515. rec_t*
  516. page_rec_find_owner_rec(
  517. /*====================*/
  518. /* out: the owner record */
  519. rec_t* rec) /* in: the physical record */
  520. {
  521. ut_ad(page_rec_check(rec));
  522. while (rec_get_n_owned(rec) == 0) {
  523. rec = page_rec_get_next(rec);
  524. }
  525. return(rec);
  526. }
  527. /****************************************************************
  528. Returns the sum of the sizes of the records in the record list, excluding
  529. the infimum and supremum records. */
  530. UNIV_INLINE
  531. ulint
  532. page_get_data_size(
  533. /*===============*/
  534. /* out: data in bytes */
  535. page_t* page) /* in: index page */
  536. {
  537. ulint ret;
  538. ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
  539.       - PAGE_SUPREMUM_END
  540.       - page_header_get_field(page, PAGE_GARBAGE));
  541. ut_ad(ret < UNIV_PAGE_SIZE);
  542. return(ret);
  543. }
  544. /*****************************************************************
  545. Calculates free space if a page is emptied. */
  546. UNIV_INLINE
  547. ulint
  548. page_get_free_space_of_empty(void)
  549. /*==============================*/
  550. /* out: free space */
  551. {
  552. return((ulint)(UNIV_PAGE_SIZE
  553. - PAGE_SUPREMUM_END
  554. - PAGE_DIR
  555. - 2 * PAGE_DIR_SLOT_SIZE));
  556. }
  557. /****************************************************************
  558. Each user record on a page, and also the deleted user records in the heap
  559. takes its size plus the fraction of the dir cell size /
  560. PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
  561. value of page_get_free_space_of_empty, the insert is impossible, otherwise
  562. it is allowed. This function returns the maximum combined size of records
  563. which can be inserted on top of the record heap. */
  564. UNIV_INLINE
  565. ulint
  566. page_get_max_insert_size(
  567. /*=====================*/
  568. /* out: maximum combined size for inserted records */
  569. page_t* page, /* in: index page */
  570. ulint n_recs) /* in: number of records */
  571. {
  572. ulint occupied;
  573. ulint free_space;
  574. occupied = page_header_get_field(page, PAGE_HEAP_TOP)
  575. - PAGE_SUPREMUM_END
  576. + page_dir_calc_reserved_space(
  577.      n_recs + (page_header_get_field(page, PAGE_N_HEAP) - 2));
  578. free_space = page_get_free_space_of_empty();
  579.      
  580. /* Above the 'n_recs +' part reserves directory space for the new
  581. inserted records; the '- 2' excludes page infimum and supremum
  582. records */
  583. if (occupied > free_space) {
  584. return(0);
  585. }
  586. return(free_space - occupied);
  587. }
  588. /****************************************************************
  589. Returns the maximum combined size of records which can be inserted on top
  590. of the record heap if a page is first reorganized. */
  591. UNIV_INLINE
  592. ulint
  593. page_get_max_insert_size_after_reorganize(
  594. /*======================================*/
  595. /* out: maximum combined size for inserted records */
  596. page_t* page, /* in: index page */
  597. ulint n_recs) /* in: number of records */
  598. {
  599. ulint occupied;
  600. ulint free_space;
  601. occupied = page_get_data_size(page)
  602. + page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
  603. free_space = page_get_free_space_of_empty();
  604. if (occupied > free_space) {
  605. return(0);
  606. }
  607. return(free_space - occupied);
  608. }
  609. /****************************************************************
  610. Puts a record to free list. */
  611. UNIV_INLINE
  612. void
  613. page_mem_free(
  614. /*==========*/
  615. page_t* page, /* in: index page */
  616. rec_t* rec) /* in: pointer to the (origin of) record */
  617. {
  618. rec_t* free;
  619. ulint garbage;
  620. free = page_header_get_ptr(page, PAGE_FREE);
  621. page_rec_set_next(rec, free);
  622. page_header_set_ptr(page, PAGE_FREE, rec);
  623. garbage = page_header_get_field(page, PAGE_GARBAGE);
  624. page_header_set_field(page, PAGE_GARBAGE,
  625. garbage + rec_get_size(rec));
  626. }
  627. #ifdef UNIV_MATERIALIZE
  628. #undef UNIV_INLINE
  629. #define UNIV_INLINE UNIV_INLINE_ORIGINAL
  630. #endif