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

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. Gets the record pointed to by a directory slot. */
  330. UNIV_INLINE
  331. rec_t*
  332. page_dir_slot_get_rec(
  333. /*==================*/
  334. /* out: pointer to record */
  335. page_dir_slot_t* slot) /* in: directory slot */
  336. {
  337. return(buf_frame_align(slot) + mach_read_from_2(slot));
  338. }
  339. /*******************************************************************
  340. This is used to set the record offset in a directory slot. */
  341. UNIV_INLINE
  342. void
  343. page_dir_slot_set_rec(
  344. /*==================*/
  345. page_dir_slot_t* slot, /* in: directory slot */
  346. rec_t*  rec) /* in: record on the page */
  347. {
  348. ut_ad(page_rec_check(rec));
  349. mach_write_to_2(slot, rec - buf_frame_align(rec));
  350. }
  351. /*******************************************************************
  352. Gets the number of records owned by a directory slot. */
  353. UNIV_INLINE
  354. ulint
  355. page_dir_slot_get_n_owned(
  356. /*======================*/
  357. /* out: number of records */
  358. page_dir_slot_t*  slot) /* in: page directory slot */
  359. {
  360. return(rec_get_n_owned(page_dir_slot_get_rec(slot)));
  361. }
  362. /*******************************************************************
  363. This is used to set the owned records field of a directory slot. */
  364. UNIV_INLINE
  365. void
  366. page_dir_slot_set_n_owned(
  367. /*======================*/
  368. page_dir_slot_t* slot, /* in: directory slot */
  369. ulint n) /* in: number of records owned 
  370. by the slot */
  371. {
  372. rec_set_n_owned(page_dir_slot_get_rec(slot), n);
  373. }
  374. /****************************************************************
  375. Calculates the space reserved for directory slots of a given number of
  376. records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
  377. PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
  378. UNIV_INLINE
  379. ulint
  380. page_dir_calc_reserved_space(
  381. /*=========================*/
  382. ulint n_recs) /* in: number of records */
  383. {
  384. return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
  385. / PAGE_DIR_SLOT_MIN_N_OWNED);
  386. /****************************************************************
  387. Gets the pointer to the next record on the page. */
  388. UNIV_INLINE
  389. rec_t*
  390. page_rec_get_next(
  391. /*==============*/
  392. /* out: pointer to next record */
  393. rec_t* rec) /* in: pointer to record */
  394. {
  395. ulint offs;
  396. page_t* page;
  397. ut_ad(page_rec_check(rec));
  398. page = buf_frame_align(rec);
  399. offs = rec_get_next_offs(rec);
  400. if (offs >= UNIV_PAGE_SIZE) {
  401. fprintf(stderr,
  402. "InnoDB: Next record offset is nonsensical %lu in record at offset %lun",
  403. (ulong)offs, (ulong)(rec - page));
  404. fprintf(stderr,
  405. "nInnoDB: rec address %p, first buffer frame %pn"
  406. "InnoDB: buffer pool high end %p, buf fix count %lun",
  407. rec, buf_pool->frame_zero,
  408. buf_pool->high_end,
  409. (ulong)buf_block_align(rec)->buf_fix_count);
  410. buf_page_print(page);
  411. ut_a(0);
  412. }
  413. if (offs == 0) {
  414. return(NULL);
  415. }
  416. return(page + offs);
  417. }
  418. /****************************************************************
  419. Sets the pointer to the next record on the page. */ 
  420. UNIV_INLINE
  421. void
  422. page_rec_set_next(
  423. /*==============*/
  424. rec_t* rec, /* in: pointer to record, must not be page supremum */
  425. rec_t* next) /* in: pointer to next record, must not be page
  426. infimum */
  427. {
  428. page_t* page;
  429. ut_ad(page_rec_check(rec));
  430. ut_a((next == NULL)
  431.       || (buf_frame_align(rec) == buf_frame_align(next)));
  432. page = buf_frame_align(rec);
  433. ut_ad(rec != page_get_supremum_rec(page));
  434. ut_ad(next != page_get_infimum_rec(page));
  435. if (next == NULL) {
  436. rec_set_next_offs(rec, 0);
  437. } else {
  438. rec_set_next_offs(rec, (ulint)(next - page));
  439. }
  440. }
  441. /****************************************************************
  442. Gets the pointer to the previous record. */
  443. UNIV_INLINE
  444. rec_t*
  445. page_rec_get_prev(
  446. /*==============*/
  447. /* out: pointer to previous record */
  448. rec_t* rec) /* in: pointer to record, must not be page
  449. infimum */
  450. {
  451. page_dir_slot_t* slot;
  452. ulint slot_no;
  453. rec_t* rec2;
  454. rec_t* prev_rec = NULL;
  455. page_t* page;
  456. ut_ad(page_rec_check(rec));
  457. page = buf_frame_align(rec);
  458. ut_ad(rec != page_get_infimum_rec(page));
  459. slot_no = page_dir_find_owner_slot(rec);
  460. ut_a(slot_no != 0);
  461. slot = page_dir_get_nth_slot(page, slot_no - 1);
  462. rec2 = page_dir_slot_get_rec(slot);
  463. while (rec != rec2) {
  464. prev_rec = rec2;
  465. rec2 = page_rec_get_next(rec2);
  466. }
  467. ut_a(prev_rec);
  468. return(prev_rec);
  469. }
  470. /*******************************************************************
  471. Looks for the record which owns the given record. */
  472. UNIV_INLINE
  473. rec_t*
  474. page_rec_find_owner_rec(
  475. /*====================*/
  476. /* out: the owner record */
  477. rec_t* rec) /* in: the physical record */
  478. {
  479. ut_ad(page_rec_check(rec));
  480. while (rec_get_n_owned(rec) == 0) {
  481. rec = page_rec_get_next(rec);
  482. }
  483. return(rec);
  484. }
  485. /****************************************************************
  486. Returns the sum of the sizes of the records in the record list, excluding
  487. the infimum and supremum records. */
  488. UNIV_INLINE
  489. ulint
  490. page_get_data_size(
  491. /*===============*/
  492. /* out: data in bytes */
  493. page_t* page) /* in: index page */
  494. {
  495. ulint ret;
  496. ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
  497.       - PAGE_SUPREMUM_END
  498.       - page_header_get_field(page, PAGE_GARBAGE));
  499. ut_ad(ret < UNIV_PAGE_SIZE);
  500. return(ret);
  501. }
  502. /*****************************************************************
  503. Calculates free space if a page is emptied. */
  504. UNIV_INLINE
  505. ulint
  506. page_get_free_space_of_empty(void)
  507. /*==============================*/
  508. /* out: free space */
  509. {
  510. return((ulint)(UNIV_PAGE_SIZE
  511. - PAGE_SUPREMUM_END
  512. - PAGE_DIR
  513. - 2 * PAGE_DIR_SLOT_SIZE));
  514. }
  515. /****************************************************************
  516. Each user record on a page, and also the deleted user records in the heap
  517. takes its size plus the fraction of the dir cell size /
  518. PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
  519. value of page_get_free_space_of_empty, the insert is impossible, otherwise
  520. it is allowed. This function returns the maximum combined size of records
  521. which can be inserted on top of the record heap. */
  522. UNIV_INLINE
  523. ulint
  524. page_get_max_insert_size(
  525. /*=====================*/
  526. /* out: maximum combined size for inserted records */
  527. page_t* page, /* in: index page */
  528. ulint n_recs) /* in: number of records */
  529. {
  530. ulint occupied;
  531. ulint free_space;
  532. occupied = page_header_get_field(page, PAGE_HEAP_TOP)
  533. - PAGE_SUPREMUM_END
  534. + page_dir_calc_reserved_space(
  535.      n_recs + (page_header_get_field(page, PAGE_N_HEAP) - 2));
  536. free_space = page_get_free_space_of_empty();
  537.      
  538. /* Above the 'n_recs +' part reserves directory space for the new
  539. inserted records; the '- 2' excludes page infimum and supremum
  540. records */
  541. if (occupied > free_space) {
  542. return(0);
  543. }
  544. return(free_space - occupied);
  545. }
  546. /****************************************************************
  547. Returns the maximum combined size of records which can be inserted on top
  548. of the record heap if a page is first reorganized. */
  549. UNIV_INLINE
  550. ulint
  551. page_get_max_insert_size_after_reorganize(
  552. /*======================================*/
  553. /* out: maximum combined size for inserted records */
  554. page_t* page, /* in: index page */
  555. ulint n_recs) /* in: number of records */
  556. {
  557. ulint occupied;
  558. ulint free_space;
  559. occupied = page_get_data_size(page)
  560. + page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
  561. free_space = page_get_free_space_of_empty();
  562. if (occupied > free_space) {
  563. return(0);
  564. }
  565. return(free_space - occupied);
  566. }
  567. /****************************************************************
  568. Puts a record to free list. */
  569. UNIV_INLINE
  570. void
  571. page_mem_free(
  572. /*==========*/
  573. page_t* page, /* in: index page */
  574. rec_t* rec) /* in: pointer to the (origin of) record */
  575. {
  576. rec_t* free;
  577. ulint garbage;
  578. free = page_header_get_ptr(page, PAGE_FREE);
  579. page_rec_set_next(rec, free);
  580. page_header_set_ptr(page, PAGE_FREE, rec);
  581. garbage = page_header_get_field(page, PAGE_GARBAGE);
  582. page_header_set_field(page, PAGE_GARBAGE,
  583. garbage + rec_get_size(rec));
  584. }
  585. #ifdef UNIV_MATERIALIZE
  586. #undef UNIV_INLINE
  587. #define UNIV_INLINE UNIV_INLINE_ORIGINAL
  588. #endif