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

MySQL数据库

开发平台:

Visual C++

  1. /**********************************************************************
  2. File space management
  3. (c) 1995 Innobase Oy
  4. Created 11/29/1995 Heikki Tuuri
  5. ***********************************************************************/
  6. #include "fsp0fsp.h"
  7. #ifdef UNIV_NONINL
  8. #include "fsp0fsp.ic"
  9. #endif
  10. #include "buf0buf.h"
  11. #include "fil0fil.h"
  12. #include "sync0sync.h"
  13. #include "mtr0log.h"
  14. #include "fut0fut.h"
  15. #include "ut0byte.h"
  16. #include "srv0srv.h"
  17. #include "page0types.h"
  18. #include "ibuf0ibuf.h"
  19. #include "btr0btr.h"
  20. #include "btr0sea.h"
  21. #include "dict0boot.h"
  22. #include "dict0mem.h"
  23. #include "log0log.h"
  24. /* The data structures in files are defined just as byte strings in C */
  25. typedef byte fsp_header_t;
  26. typedef byte xdes_t;
  27. /* SPACE HEADER
  28. ============
  29. File space header data structure: this data structure is contained in the
  30. first page of a space. The space for this header is reserved in every extent
  31. descriptor page, but used only in the first. */
  32. #define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
  33. within a file page */
  34. /*-------------------------------------*/
  35. #define FSP_NOT_USED 0 /* this field contained a value up to
  36. which we know that the modifications
  37. in the database have been flushed to
  38. the file space; not used now */
  39. #define FSP_SIZE 8 /* Current size of the space in
  40. pages */
  41. #define FSP_FREE_LIMIT 12 /* Minimum page number for which the
  42. free list has not been initialized:
  43. the pages >= this limit are, by
  44. definition free */
  45. #define FSP_LOWEST_NO_WRITE 16 /* The lowest page offset for which
  46. the page has not been written to disk
  47. (if it has been written, we know that
  48. the OS has really reserved the
  49. physical space for the page) */
  50. #define FSP_FRAG_N_USED 20 /* number of used pages in the
  51. FSP_FREE_FRAG list */
  52. #define FSP_FREE 24 /* list of free extents */
  53. #define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
  54. /* list of partially free extents not
  55. belonging to any segment */
  56. #define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
  57. /* list of full extents not belonging
  58. to any segment */
  59. #define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
  60. /* 8 bytes which give the first unused
  61. segment id */
  62. #define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
  63. /* list of pages containing segment
  64. headers, where all the segment inode
  65. slots are reserved */
  66. #define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
  67. /* list of pages containing segment
  68. headers, where not all the segment
  69. header slots are reserved */
  70. /*-------------------------------------*/
  71. /* File space header size */
  72. #define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
  73. #define FSP_FREE_ADD 4 /* this many free extents are added
  74. to the free list from above
  75. FSP_FREE_LIMIT at a time */
  76. /* FILE SEGMENT INODE
  77. ==================
  78. Segment inode which is created for each segment in a tablespace. NOTE: in
  79. purge we assume that a segment having only one currently used page can be
  80. freed in a few steps, so that the freeing cannot fill the file buffer with
  81. bufferfixed file pages. */
  82. typedef byte fseg_inode_t;
  83. #define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
  84. /* the list node for linking
  85. segment inode pages */
  86. #define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
  87. /*-------------------------------------*/
  88. #define FSEG_ID 0 /* 8 bytes of segment id: if this is
  89. ut_dulint_zero, it means that the
  90. header is unused */
  91. #define FSEG_NOT_FULL_N_USED 8
  92. /* number of used segment pages in
  93. the FSEG_NOT_FULL list */
  94. #define FSEG_FREE 12
  95. /* list of free extents of this
  96. segment */
  97. #define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
  98. /* list of partially free extents */
  99. #define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
  100. /* list of full extents */
  101. #define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
  102. /* magic number used in debugging */
  103. #define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
  104. /* array of individual pages
  105. belonging to this segment in fsp
  106. fragment extent lists */
  107. #define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
  108. /* number of slots in the array for
  109. the fragment pages */
  110. #define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
  111. page number within space, FIL_NULL
  112. means that the slot is not in use */
  113. /*-------------------------------------*/
  114. #define FSEG_INODE_SIZE (16 + 3 * FLST_BASE_NODE_SIZE +
  115. FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
  116. #define FSP_SEG_INODES_PER_PAGE ((UNIV_PAGE_SIZE - FSEG_ARR_OFFSET - 10)
  117.  / FSEG_INODE_SIZE)
  118. /* Number of segment inodes which fit on a
  119. single page */
  120. #define FSEG_MAGIC_N_VALUE 97937874
  121. #define FSEG_FILLFACTOR 8 /* If this value is x, then if
  122. the number of unused but reserved
  123. pages in a segment is less than
  124. reserved pages * 1/x, and there are
  125. at least FSEG_FRAG_LIMIT used pages,
  126. then we allow a new empty extent to
  127. be added to the segment in
  128. fseg_alloc_free_page. Otherwise, we
  129. use unused pages of the segment. */
  130. #define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
  131. /* If the segment has >= this many
  132. used pages, it may be expanded by
  133. allocating extents to the segment;
  134. until that only individual fragment
  135. pages are allocated from the space */
  136. #define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
  137. is at least this many extents, we
  138. allow extents to be put to the free
  139. list of the extent: at most
  140. FSEG_FREE_LIST_MAX_LEN many */
  141. #define FSEG_FREE_LIST_MAX_LEN 4
  142. /* EXTENT DESCRIPTOR
  143. =================
  144. File extent descriptor data structure: contains bits to tell which pages in
  145. the extent are free and which contain old tuple version to clean. */
  146. /*-------------------------------------*/
  147. #define XDES_ID 0 /* The identifier of the segment
  148. to which this extent belongs */
  149. #define XDES_FLST_NODE 8 /* The list node data structure
  150. for the descriptors */
  151. #define XDES_STATE (FLST_NODE_SIZE + 8)
  152. /* contains state information
  153. of the extent */
  154. #define XDES_BITMAP (FLST_NODE_SIZE + 12)
  155. /* Descriptor bitmap of the pages
  156. in the extent */
  157. /*-------------------------------------*/
  158. #define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
  159. #define XDES_FREE_BIT 0 /* Index of the bit which tells if
  160. the page is free */
  161. #define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
  162. Index of the bit which tells if
  163. there are old versions of tuples
  164. on the page */
  165. /* States of a descriptor */
  166. #define XDES_FREE 1 /* extent is in free list of space */
  167. #define XDES_FREE_FRAG 2 /* extent is in free fragment list of
  168. space */
  169. #define XDES_FULL_FRAG 3 /* extent is in full fragment list of
  170. space */
  171. #define XDES_FSEG 4 /* extent belongs to a segment */
  172. /* File extent data structure size in bytes. The "+ 7 ) / 8" part in the
  173. definition rounds the number of bytes upward. */
  174. #define XDES_SIZE (XDES_BITMAP +
  175.  (FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE + 7) / 8)
  176. /* Offset of the descriptor array on a descriptor page */
  177. #define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
  178. /**************************************************************************
  179. Returns an extent to the free list of a space. */
  180. static
  181. void
  182. fsp_free_extent(
  183. /*============*/
  184. ulint space, /* in: space id */
  185. ulint page, /* in: page offset in the extent */
  186. mtr_t* mtr); /* in: mtr */
  187. /**************************************************************************
  188. Frees an extent of a segment to the space free list. */
  189. static
  190. void
  191. fseg_free_extent(
  192. /*=============*/
  193. fseg_inode_t* seg_inode, /* in: segment inode */
  194. ulint space, /* in: space id */
  195. ulint page, /* in: page offset in the extent */
  196. mtr_t* mtr); /* in: mtr handle */
  197. /**************************************************************************
  198. Calculates the number of pages reserved by a segment, and how
  199. many pages are currently used. */
  200. static
  201. ulint
  202. fseg_n_reserved_pages_low(
  203. /*======================*/
  204. /* out: number of reserved pages */
  205. fseg_inode_t*  header, /* in: segment inode */
  206. ulint* used, /* out: number of pages used (<= reserved) */
  207. mtr_t* mtr); /* in: mtr handle */
  208. /************************************************************************
  209. Marks a page used. The page must reside within the extents of the given
  210. segment. */
  211. static
  212. void
  213. fseg_mark_page_used(
  214. /*================*/
  215. fseg_inode_t* seg_inode,/* in: segment inode */
  216. ulint space, /* in: space id */
  217. ulint page, /* in: page offset */
  218. mtr_t* mtr); /* in: mtr */
  219. /**************************************************************************
  220. Returns the first extent descriptor for a segment. We think of the extent
  221. lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
  222. -> FSEG_FREE. */
  223. static
  224. xdes_t*
  225. fseg_get_first_extent(
  226. /*==================*/
  227. /* out: the first extent descriptor, or NULL if
  228. none */
  229. fseg_inode_t* inode, /* in: segment inode */
  230. mtr_t* mtr); /* in: mtr */
  231. /**************************************************************************
  232. Puts new extents to the free list if
  233. there are free extents above the free limit. If an extent happens
  234. to contain an extent descriptor page, the extent is put to
  235. the FSP_FREE_FRAG list with the page marked as used. */
  236. static
  237. void
  238. fsp_fill_free_list(
  239. /*===============*/
  240. ulint space, /* in: space */
  241. fsp_header_t* header, /* in: space header */
  242. mtr_t* mtr); /* in: mtr */
  243. /**************************************************************************
  244. Allocates a single free page from a segment. This function implements
  245. the intelligent allocation strategy which tries to minimize file space
  246. fragmentation. */
  247. static
  248. ulint
  249. fseg_alloc_free_page_low(
  250. /*=====================*/
  251. /* out: the allocated page number, FIL_NULL
  252. if no page could be allocated */
  253. ulint space, /* in: space */
  254. fseg_inode_t*  seg_inode, /* in: segment inode */
  255. ulint hint, /* in: hint of which page would be desirable */
  256. byte direction, /* in: if the new page is needed because
  257. of an index page split, and records are
  258. inserted there in order, into which
  259. direction they go alphabetically: FSP_DOWN,
  260. FSP_UP, FSP_NO_DIR */
  261. mtr_t* mtr); /* in: mtr handle */
  262. /**************************************************************************
  263. Gets a pointer to the space header and x-locks its page. */
  264. UNIV_INLINE
  265. fsp_header_t*
  266. fsp_get_space_header(
  267. /*=================*/
  268. /* out: pointer to the space header, page x-locked */
  269. ulint id, /* in: space id */
  270. mtr_t* mtr) /* in: mtr */
  271. {
  272. fsp_header_t* header;
  273. ut_ad(mtr);
  274. header = FSP_HEADER_OFFSET + buf_page_get(id, 0, RW_X_LATCH, mtr);
  275. buf_page_dbg_add_level(header, SYNC_FSP_PAGE);
  276. return(header);
  277. }
  278. /**************************************************************************
  279. Gets a descriptor bit of a page. */
  280. UNIV_INLINE
  281. ibool
  282. xdes_get_bit(
  283. /*=========*/
  284. /* out: TRUE if free */
  285. xdes_t* descr, /* in: descriptor */
  286. ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
  287. ulint offset, /* in: page offset within extent:
  288. 0 ... FSP_EXTENT_SIZE - 1 */
  289. mtr_t* mtr) /* in: mtr */
  290. {
  291. ulint index;
  292. ulint byte_index;
  293. ulint bit_index;
  294. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  295. MTR_MEMO_PAGE_X_FIX));
  296. ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
  297. ut_ad(offset < FSP_EXTENT_SIZE);
  298. index = bit + XDES_BITS_PER_PAGE * offset;
  299. byte_index = index / 8;
  300. bit_index = index % 8;
  301. return(ut_bit_get_nth(
  302.    mtr_read_ulint(descr + XDES_BITMAP + byte_index,
  303. MLOG_1BYTE, mtr),
  304.    bit_index));   
  305. }
  306. /**************************************************************************
  307. Sets a descriptor bit of a page. */
  308. UNIV_INLINE
  309. void
  310. xdes_set_bit(
  311. /*=========*/
  312. xdes_t* descr, /* in: descriptor */
  313. ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
  314. ulint offset, /* in: page offset within extent:
  315. 0 ... FSP_EXTENT_SIZE - 1 */
  316. ibool val, /* in: bit value */
  317. mtr_t* mtr) /* in: mtr */
  318. {
  319. ulint index;
  320. ulint byte_index;
  321. ulint bit_index;
  322. ulint descr_byte;
  323. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  324. MTR_MEMO_PAGE_X_FIX));
  325. ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
  326. ut_ad(offset < FSP_EXTENT_SIZE);
  327. index = bit + XDES_BITS_PER_PAGE * offset;
  328. byte_index = index / 8;
  329. bit_index = index % 8;
  330. descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
  331. MLOG_1BYTE, mtr);
  332. descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
  333. mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
  334. MLOG_1BYTE, mtr);
  335. }
  336. /**************************************************************************
  337. Looks for a descriptor bit having the desired value. Starts from hint
  338. and scans upward; at the end of the extent the search is wrapped to
  339. the start of the extent. */
  340. UNIV_INLINE
  341. ulint
  342. xdes_find_bit(
  343. /*==========*/
  344. /* out: bit index of the bit, ULINT_UNDEFINED if not
  345. found */
  346. xdes_t* descr, /* in: descriptor */
  347. ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
  348. ibool val, /* in: desired bit value */
  349. ulint hint, /* in: hint of which bit position would be desirable */
  350. mtr_t* mtr) /* in: mtr */
  351. {
  352. ulint i;
  353. ut_ad(descr && mtr);
  354. ut_ad(val <= TRUE);
  355. ut_ad(hint < FSP_EXTENT_SIZE);
  356. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  357. MTR_MEMO_PAGE_X_FIX));
  358. for (i = hint; i < FSP_EXTENT_SIZE; i++) {
  359. if (val == xdes_get_bit(descr, bit, i, mtr)) {
  360. return(i);
  361. }
  362. }
  363. for (i = 0; i < hint; i++) {
  364. if (val == xdes_get_bit(descr, bit, i, mtr)) {
  365. return(i);
  366. }
  367. }
  368. return(ULINT_UNDEFINED);
  369. }
  370. /**************************************************************************
  371. Looks for a descriptor bit having the desired value. Scans the extent in
  372. a direction opposite to xdes_find_bit. */
  373. UNIV_INLINE
  374. ulint
  375. xdes_find_bit_downward(
  376. /*===================*/
  377. /* out: bit index of the bit, ULINT_UNDEFINED if not
  378. found */
  379. xdes_t* descr, /* in: descriptor */
  380. ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
  381. ibool val, /* in: desired bit value */
  382. ulint hint, /* in: hint of which bit position would be desirable */
  383. mtr_t* mtr) /* in: mtr */
  384. {
  385. ulint i;
  386. ut_ad(descr && mtr);
  387. ut_ad(val <= TRUE);
  388. ut_ad(hint < FSP_EXTENT_SIZE);
  389. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  390. MTR_MEMO_PAGE_X_FIX));
  391. for (i = hint + 1; i > 0; i--) {
  392. if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
  393. return(i - 1);
  394. }
  395. }
  396. for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
  397. if (val == xdes_get_bit(descr, bit, i, mtr)) {
  398. return(i);
  399. }
  400. }
  401. return(ULINT_UNDEFINED);
  402. }
  403. /**************************************************************************
  404. Returns the number of used pages in a descriptor. */
  405. UNIV_INLINE
  406. ulint
  407. xdes_get_n_used(
  408. /*============*/
  409. /* out: number of pages used */
  410. xdes_t* descr, /* in: descriptor */
  411. mtr_t* mtr) /* in: mtr */
  412. {
  413. ulint i;
  414. ulint count = 0;
  415. ut_ad(descr && mtr);
  416. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  417. MTR_MEMO_PAGE_X_FIX));
  418. for (i = 0; i < FSP_EXTENT_SIZE; i++) {
  419. if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
  420. count++;
  421. }
  422. }
  423. return(count);
  424. }
  425. /**************************************************************************
  426. Returns true if extent contains no used pages. */
  427. UNIV_INLINE
  428. ibool
  429. xdes_is_free(
  430. /*=========*/
  431. /* out: TRUE if totally free */
  432. xdes_t* descr, /* in: descriptor */
  433. mtr_t* mtr) /* in: mtr */
  434. {
  435. if (0 == xdes_get_n_used(descr, mtr)) {
  436. return(TRUE);
  437. }
  438. return(FALSE);
  439. }
  440. /**************************************************************************
  441. Returns true if extent contains no free pages. */
  442. UNIV_INLINE
  443. ibool
  444. xdes_is_full(
  445. /*=========*/
  446. /* out: TRUE if full */
  447. xdes_t* descr, /* in: descriptor */
  448. mtr_t* mtr) /* in: mtr */
  449. {
  450. if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
  451. return(TRUE);
  452. }
  453. return(FALSE);
  454. }
  455. /**************************************************************************
  456. Sets the state of an xdes. */
  457. UNIV_INLINE
  458. void
  459. xdes_set_state(
  460. /*===========*/
  461. xdes_t* descr, /* in: descriptor */
  462. ulint state, /* in: state to set */
  463. mtr_t* mtr) /* in: mtr handle */
  464. {
  465. ut_ad(descr && mtr);
  466. ut_ad(state >= XDES_FREE);
  467. ut_ad(state <= XDES_FSEG);
  468. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  469. MTR_MEMO_PAGE_X_FIX));
  470. mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr); 
  471. }
  472. /**************************************************************************
  473. Gets the state of an xdes. */
  474. UNIV_INLINE
  475. ulint
  476. xdes_get_state(
  477. /*===========*/
  478. /* out: state */
  479. xdes_t* descr, /* in: descriptor */
  480. mtr_t* mtr) /* in: mtr handle */
  481. {
  482. ut_ad(descr && mtr);
  483. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  484. MTR_MEMO_PAGE_X_FIX));
  485. return(mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr)); 
  486. }
  487. /**************************************************************************
  488. Inits an extent descriptor to the free and clean state. */
  489. UNIV_INLINE
  490. void
  491. xdes_init(
  492. /*======*/
  493. xdes_t* descr, /* in: descriptor */
  494. mtr_t* mtr) /* in: mtr */
  495. {
  496. ulint i;
  497. ut_ad(descr && mtr);
  498. ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
  499. MTR_MEMO_PAGE_X_FIX));
  500. ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
  501. for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
  502. mlog_write_ulint(descr + i, 0xFFFFFFFF, MLOG_4BYTES, mtr);
  503. }
  504. xdes_set_state(descr, XDES_FREE, mtr);
  505. }
  506. /************************************************************************
  507. Calculates the page where the descriptor of a page resides. */
  508. UNIV_INLINE
  509. ulint
  510. xdes_calc_descriptor_page(
  511. /*======================*/
  512. /* out: descriptor page offset */
  513. ulint offset) /* in: page offset */
  514. {
  515. ut_ad(UNIV_PAGE_SIZE > XDES_ARR_OFFSET
  516. + (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE) * XDES_SIZE);
  517. return(ut_2pow_round(offset, XDES_DESCRIBED_PER_PAGE));
  518. }
  519. /************************************************************************
  520. Calculates the descriptor index within a descriptor page. */
  521. UNIV_INLINE
  522. ulint
  523. xdes_calc_descriptor_index(
  524. /*=======================*/
  525. /* out: descriptor index */
  526. ulint offset) /* in: page offset */
  527. {
  528. return(ut_2pow_remainder(offset, XDES_DESCRIBED_PER_PAGE) /
  529. FSP_EXTENT_SIZE);
  530. }
  531. /************************************************************************
  532. Gets pointer to a the extent descriptor of a page. The page where the extent
  533. descriptor resides is x-locked. If the page offset is equal to the free limit
  534. of the space, adds new extents from above the free limit to the space free
  535. list, if not free limit == space size. This adding is necessary to make the
  536. descriptor defined, as they are uninitialized above the free limit. */
  537. UNIV_INLINE
  538. xdes_t*
  539. xdes_get_descriptor_with_space_hdr(
  540. /*===============================*/
  541. /* out: pointer to the extent descriptor,
  542. NULL if the page does not exist in the
  543. space or if offset > free limit */
  544. fsp_header_t* sp_header,/* in: space header, x-latched */
  545. ulint space, /* in: space id */
  546. ulint offset, /* in: page offset; 
  547. if equal to the free limit,
  548. we try to add new extents to
  549. the space free list */
  550. mtr_t* mtr) /* in: mtr handle */
  551. {
  552. ulint limit;
  553. ulint size;
  554. ulint descr_page_no;
  555. page_t* descr_page;
  556. ut_ad(mtr);
  557. ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK));
  558. /* Read free limit and space size */
  559. limit = mtr_read_ulint(sp_header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
  560. size  = mtr_read_ulint(sp_header + FSP_SIZE, MLOG_4BYTES, mtr);
  561. /* If offset is >= size or > limit, return NULL */
  562. if ((offset >= size) || (offset > limit)) {
  563. return(NULL);
  564. }
  565. /* If offset is == limit, fill free list of the space. */
  566. if (offset == limit) {
  567. fsp_fill_free_list(space, sp_header, mtr);
  568. }
  569. descr_page_no = xdes_calc_descriptor_page(offset);
  570. if (descr_page_no == 0) {
  571. /* It is on the space header page */
  572. descr_page = buf_frame_align(sp_header);
  573. } else {
  574. descr_page = buf_page_get(space, descr_page_no, RW_X_LATCH,
  575. mtr);
  576. buf_page_dbg_add_level(descr_page, SYNC_FSP_PAGE);
  577. }
  578. return(descr_page + XDES_ARR_OFFSET
  579.        + XDES_SIZE * xdes_calc_descriptor_index(offset));
  580. }
  581. /************************************************************************
  582. Gets pointer to a the extent descriptor of a page. The page where the
  583. extent descriptor resides is x-locked. If the page offset is equal to
  584. the free limit of the space, adds new extents from above the free limit
  585. to the space free list, if not free limit == space size. This adding
  586. is necessary to make the descriptor defined, as they are uninitialized
  587. above the free limit. */
  588. static
  589. xdes_t*
  590. xdes_get_descriptor(
  591. /*================*/
  592. /* out: pointer to the extent descriptor, NULL if the
  593. page does not exist in the space or if offset > free
  594. limit */
  595. ulint space, /* in: space id */
  596. ulint offset, /* in: page offset; if equal to the free limit,
  597. we try to add new extents to the space free list */
  598. mtr_t* mtr) /* in: mtr handle */
  599. {
  600. fsp_header_t* sp_header;
  601. sp_header = FSP_HEADER_OFFSET
  602. + buf_page_get(space, 0, RW_X_LATCH, mtr);
  603. buf_page_dbg_add_level(sp_header, SYNC_FSP_PAGE);
  604. return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
  605. mtr));
  606. }
  607. /************************************************************************
  608. Gets pointer to a the extent descriptor if the file address
  609. of the descriptor list node is known. The page where the
  610. extent descriptor resides is x-locked. */
  611. UNIV_INLINE
  612. xdes_t*
  613. xdes_lst_get_descriptor(
  614. /*====================*/
  615. /* out: pointer to the extent descriptor */
  616. ulint space, /* in: space id */
  617. fil_addr_t lst_node,/* in: file address of the list node
  618. contained in the descriptor */
  619. mtr_t* mtr) /* in: mtr handle */
  620. {
  621. xdes_t* descr;
  622. ut_ad(mtr);
  623. ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK));
  624. descr = fut_get_ptr(space, lst_node, RW_X_LATCH, mtr) - XDES_FLST_NODE;
  625. return(descr);
  626. }
  627. /************************************************************************
  628. Gets pointer to the next descriptor in a descriptor list and x-locks its
  629. page. */
  630. UNIV_INLINE
  631. xdes_t*
  632. xdes_lst_get_next(
  633. /*==============*/
  634. xdes_t* descr, /* in: pointer to a descriptor */
  635. mtr_t* mtr) /* in: mtr handle */
  636. {
  637. ulint space;
  638. ut_ad(mtr && descr);
  639. space = buf_frame_get_space_id(descr);
  640. return(xdes_lst_get_descriptor(space,
  641. flst_get_next_addr(descr + XDES_FLST_NODE, mtr), mtr));
  642. }
  643. /************************************************************************
  644. Returns page offset of the first page in extent described by a descriptor. */
  645. UNIV_INLINE
  646. ulint
  647. xdes_get_offset(
  648. /*============*/
  649. /* out: offset of the first page in extent */
  650. xdes_t* descr) /* in: extent descriptor */
  651. {
  652. ut_ad(descr);
  653. return(buf_frame_get_page_no(descr)
  654. + ((descr - buf_frame_align(descr) - XDES_ARR_OFFSET)
  655.    / XDES_SIZE)
  656.   * FSP_EXTENT_SIZE);
  657. }
  658. /***************************************************************
  659. Inits a file page whose prior contents should be ignored. */
  660. static
  661. void
  662. fsp_init_file_page_low(
  663. /*=====================*/
  664. byte* ptr) /* in: pointer to a page */
  665. {
  666. page_t* page;
  667. #ifdef UNIV_BASIC_LOG_DEBUG
  668. ulint i;
  669. #endif
  670. page = buf_frame_align(ptr);
  671. #ifdef UNIV_BASIC_LOG_DEBUG
  672. /* printf("In log debug version: Erase the contents of the file pagen");
  673. */
  674. for (i = 0; i < UNIV_PAGE_SIZE; i++) {
  675. page[i] = 0xFF;
  676. }
  677. #endif
  678. mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN,
  679. ut_dulint_zero);
  680. mach_write_to_8(page + FIL_PAGE_LSN, ut_dulint_zero);
  681. }
  682. /***************************************************************
  683. Inits a file page whose prior contents should be ignored. */
  684. void
  685. fsp_init_file_page(
  686. /*===============*/
  687. page_t* page, /* in: page */
  688. mtr_t* mtr) /* in: mtr */
  689. {
  690. fsp_init_file_page_low(page);
  691. mlog_write_initial_log_record(page, MLOG_INIT_FILE_PAGE, mtr);
  692. }
  693. /***************************************************************
  694. Parses a redo log record of a file page init. */
  695. byte*
  696. fsp_parse_init_file_page(
  697. /*=====================*/
  698. /* out: end of log record or NULL */
  699. byte* ptr, /* in: buffer */
  700. byte* end_ptr,/* in: buffer end */
  701. page_t* page) /* in: page or NULL */
  702. {
  703. ut_ad(ptr && end_ptr);
  704. if (page) {
  705. fsp_init_file_page_low(page);
  706. }
  707. return(ptr);
  708. }
  709. /**************************************************************************
  710. Initializes the fsp system. */
  711. void
  712. fsp_init(void)
  713. /*==========*/
  714. {
  715. /* Does nothing at the moment */
  716. }
  717. /**************************************************************************
  718. Initializes the space header of a new created space and creates also the
  719. insert buffer tree root. */
  720. void
  721. fsp_header_init(
  722. /*============*/
  723. ulint space, /* in: space id */
  724. ulint size, /* in: current size in blocks */
  725. mtr_t* mtr) /* in: mini-transaction handle */
  726. {
  727. fsp_header_t* header;
  728. page_t* page;
  729. ut_ad(mtr);
  730. mtr_x_lock(fil_space_get_latch(space), mtr);
  731. page = buf_page_create(space, 0, mtr);
  732. buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
  733. buf_page_get(space, 0, RW_X_LATCH, mtr);
  734. buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
  735. /* The prior contents of the file page should be ignored */
  736. fsp_init_file_page(page, mtr);
  737. header = FSP_HEADER_OFFSET + page;
  738. mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr); 
  739. mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr); 
  740. mlog_write_ulint(header + FSP_LOWEST_NO_WRITE, 0, MLOG_4BYTES, mtr); 
  741. mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr); 
  742. flst_init(header + FSP_FREE, mtr);
  743. flst_init(header + FSP_FREE_FRAG, mtr);
  744. flst_init(header + FSP_FULL_FRAG, mtr);
  745. flst_init(header + FSP_SEG_INODES_FULL, mtr);
  746. flst_init(header + FSP_SEG_INODES_FREE, mtr);
  747. mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1),
  748. MLOG_8BYTES, mtr); 
  749. fsp_fill_free_list(space, header, mtr);
  750. btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, space,
  751. ut_dulint_add(DICT_IBUF_ID_MIN, space), mtr);
  752. }
  753. /**************************************************************************
  754. Increases the space size field of a space. */
  755. void
  756. fsp_header_inc_size(
  757. /*================*/
  758. ulint space, /* in: space id */
  759. ulint size_inc,/* in: size increment in pages */
  760. mtr_t* mtr) /* in: mini-transaction handle */
  761. {
  762. fsp_header_t* header;
  763. ulint size;
  764. ut_ad(mtr);
  765. mtr_x_lock(fil_space_get_latch(space), mtr);
  766. header = fsp_get_space_header(space, mtr);
  767. size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
  768. mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES, mtr); 
  769. }
  770. /**************************************************************************
  771. Puts new extents to the free list if there are free extents above the free
  772. limit. If an extent happens to contain an extent descriptor page, the extent
  773. is put to the FSP_FREE_FRAG list with the page marked as used. */
  774. static
  775. void
  776. fsp_fill_free_list(
  777. /*===============*/
  778. ulint space, /* in: space */
  779. fsp_header_t* header, /* in: space header */
  780. mtr_t* mtr) /* in: mtr */
  781. {
  782. ulint limit;
  783. ulint size;
  784. xdes_t* descr;
  785. ulint count  = 0;
  786. ulint frag_n_used;
  787. page_t* descr_page;
  788. page_t* ibuf_page;
  789. mtr_t ibuf_mtr;
  790. ulint i;
  791. ut_ad(header && mtr);
  792. /* Check if we can fill free list from above the free list limit */
  793. size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
  794. limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
  795. i = limit;
  796. while ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD)) {
  797. mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
  798. MLOG_4BYTES, mtr); 
  799. if (0 == i % XDES_DESCRIBED_PER_PAGE) {
  800. /* We are going to initialize a new descriptor page
  801. and a new ibuf bitmap page: the prior contents of the
  802. pages should be ignored. */
  803. if (i > 0) {
  804. descr_page = buf_page_create(space, i, mtr);
  805. buf_page_dbg_add_level(descr_page,
  806. SYNC_FSP_PAGE);
  807. buf_page_get(space, i, RW_X_LATCH, mtr);
  808. buf_page_dbg_add_level(descr_page,
  809. SYNC_FSP_PAGE);
  810. fsp_init_file_page(descr_page, mtr);
  811. }
  812. /* Initialize the ibuf page in a separate
  813. mini-transaction because it is low in the latching
  814. order, and we must be able to release the its latch
  815. before returning from the fsp routine */
  816. mtr_start(&ibuf_mtr);
  817. ibuf_page = buf_page_create(space,
  818. i + FSP_IBUF_BITMAP_OFFSET, &ibuf_mtr);
  819. buf_page_dbg_add_level(ibuf_page, SYNC_IBUF_BITMAP);
  820. buf_page_get(space, i + FSP_IBUF_BITMAP_OFFSET,
  821. RW_X_LATCH, &ibuf_mtr);
  822. buf_page_dbg_add_level(ibuf_page, SYNC_FSP_PAGE);
  823. fsp_init_file_page(ibuf_page, &ibuf_mtr);
  824. ibuf_bitmap_page_init(ibuf_page, &ibuf_mtr);
  825. mtr_commit(&ibuf_mtr);
  826. }
  827. descr = xdes_get_descriptor_with_space_hdr(header, space, i,
  828. mtr);
  829. xdes_init(descr, mtr);
  830. ut_ad(XDES_DESCRIBED_PER_PAGE % FSP_EXTENT_SIZE == 0);
  831. if (0 == i % XDES_DESCRIBED_PER_PAGE) {
  832. /* The first page in the extent is a descriptor page
  833. and the second is an ibuf bitmap page: mark them
  834. used */
  835. xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
  836. xdes_set_bit(descr, XDES_FREE_BIT,
  837. FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
  838. xdes_set_state(descr, XDES_FREE_FRAG, mtr);
  839. flst_add_last(header + FSP_FREE_FRAG,
  840. descr + XDES_FLST_NODE, mtr);
  841. frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
  842.      MLOG_4BYTES, mtr);
  843. mlog_write_ulint(header + FSP_FRAG_N_USED,
  844. frag_n_used + 2, MLOG_4BYTES, mtr);
  845. } else {
  846. flst_add_last(header + FSP_FREE,
  847. descr + XDES_FLST_NODE, mtr);
  848. count++;
  849. }
  850. i += FSP_EXTENT_SIZE;
  851. }
  852. }
  853. /**************************************************************************
  854. Allocates a new free extent. */
  855. static
  856. xdes_t*
  857. fsp_alloc_free_extent(
  858. /*==================*/
  859. /* out: extent descriptor, NULL if cannot be
  860. allocated */
  861. ulint space, /* in: space id */
  862. ulint hint, /* in: hint of which extent would be desirable: any
  863. page offset in the extent goes; the hint must not
  864. be > FSP_FREE_LIMIT */
  865. mtr_t* mtr) /* in: mtr */
  866. {
  867. fsp_header_t* header;
  868. fil_addr_t first;
  869. xdes_t* descr;
  870. ut_ad(mtr);
  871. header = fsp_get_space_header(space, mtr);
  872. descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
  873. if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
  874. /* Ok, we can take this extent */
  875. } else {
  876. /* Take the first extent in the free list */
  877. first = flst_get_first(header + FSP_FREE, mtr);
  878. if (fil_addr_is_null(first)) {
  879. fsp_fill_free_list(space, header, mtr);
  880. first = flst_get_first(header + FSP_FREE, mtr);
  881. }
  882. if (fil_addr_is_null(first)) {
  883. return(NULL); /* No free extents left */
  884. }
  885. descr = xdes_lst_get_descriptor(space, first, mtr);
  886. }
  887. flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
  888. return(descr);
  889. }
  890. /**************************************************************************
  891. Allocates a single free page from a space. The page is marked as used. */
  892. static
  893. ulint
  894. fsp_alloc_free_page(
  895. /*================*/
  896. /* out: the page offset, FIL_NULL if no page could
  897. be allocated */
  898. ulint space, /* in: space id */
  899. ulint hint, /* in: hint of which page would be desirable */
  900. mtr_t* mtr) /* in: mtr handle */
  901. {
  902. fsp_header_t* header;
  903. fil_addr_t first;
  904. xdes_t* descr;
  905. page_t* page;
  906. ulint free;
  907. ulint frag_n_used;
  908. ulint page_no;
  909. ut_ad(mtr);
  910. header = fsp_get_space_header(space, mtr);
  911. /* Get the hinted descriptor */
  912. descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
  913. if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
  914. /* Ok, we can take this extent */
  915. } else {
  916. /* Else take the first extent in free_frag list */
  917. first = flst_get_first(header + FSP_FREE_FRAG, mtr);
  918. if (fil_addr_is_null(first)) {
  919. /* There are no partially full fragments: allocate
  920. a free extent and add it to the FREE_FRAG list. NOTE
  921. that the allocation may have as a side-effect that an
  922. extent containing a descriptor page is added to the
  923. FREE_FRAG list. But we will allocate our page from the
  924. the free extent anyway. */
  925. descr = fsp_alloc_free_extent(space, hint, mtr);
  926. if (descr == NULL) {
  927. /* No free space left */
  928. return(FIL_NULL);
  929. }
  930. xdes_set_state(descr, XDES_FREE_FRAG, mtr);
  931. flst_add_last(header + FSP_FREE_FRAG,
  932. descr + XDES_FLST_NODE, mtr);
  933. } else {
  934. descr = xdes_lst_get_descriptor(space, first, mtr);
  935. }
  936. /* Reset the hint */
  937. hint = 0;
  938. }
  939. /* Now we have in descr an extent with at least one free page. Look
  940. for a free page in the extent. */
  941. free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
  942. hint % FSP_EXTENT_SIZE, mtr);
  943. ut_a(free != ULINT_UNDEFINED);
  944. xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
  945. /* Update the FRAG_N_USED field */
  946. frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
  947. mtr);
  948. frag_n_used++;
  949. mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
  950. mtr);
  951. if (xdes_is_full(descr, mtr)) {
  952. /* The fragment is full: move it to another list */
  953. flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
  954. mtr);
  955. xdes_set_state(descr, XDES_FULL_FRAG, mtr);
  956. flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
  957. mtr);
  958. mlog_write_ulint(header + FSP_FRAG_N_USED,
  959. frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
  960. mtr);
  961. }
  962. page_no = xdes_get_offset(descr) + free;
  963. /* Initialize the allocated page to the buffer pool, so that it can
  964. be obtained immediately with buf_page_get without need for a disk
  965. read. */
  966. buf_page_create(space, page_no, mtr);
  967. page = buf_page_get(space, page_no, RW_X_LATCH, mtr);
  968. buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
  969. /* Prior contents of the page should be ignored */
  970. fsp_init_file_page(page, mtr);
  971. return(page_no);
  972. }
  973. /**************************************************************************
  974. Frees a single page of a space. The page is marked as free and clean. */
  975. static
  976. void
  977. fsp_free_page(
  978. /*==========*/
  979. ulint space, /* in: space id */
  980. ulint page, /* in: page offset */
  981. mtr_t* mtr) /* in: mtr handle */
  982. {
  983. fsp_header_t* header;
  984. xdes_t* descr;
  985. ulint state;
  986. ulint frag_n_used;
  987. ut_ad(mtr);
  988. /* printf("Freeing page %lu in space %lun", page, space); */
  989. header = fsp_get_space_header(space, mtr);
  990. descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
  991. state = xdes_get_state(descr, mtr);
  992. ut_a((state == XDES_FREE_FRAG) || (state == XDES_FULL_FRAG));
  993. ut_a(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
  994. == FALSE);
  995. xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
  996. xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
  997. frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
  998. mtr);
  999. if (state == XDES_FULL_FRAG) {
  1000. /* The fragment was full: move it to another list */
  1001. flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
  1002. mtr);
  1003. xdes_set_state(descr, XDES_FREE_FRAG, mtr);
  1004. flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
  1005. mtr);
  1006. mlog_write_ulint(header + FSP_FRAG_N_USED,
  1007. frag_n_used + FSP_EXTENT_SIZE - 1,
  1008. MLOG_4BYTES, mtr);
  1009. } else {
  1010. ut_a(frag_n_used > 0);
  1011. mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
  1012. MLOG_4BYTES, mtr);
  1013. }
  1014. if (xdes_is_free(descr, mtr)) {
  1015.      /* The extent has become free: move it to another list */
  1016. flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
  1017. mtr);
  1018. fsp_free_extent(space, page, mtr);
  1019. }
  1020. }
  1021. /**************************************************************************
  1022. Returns an extent to the free list of a space. */
  1023. static
  1024. void
  1025. fsp_free_extent(
  1026. /*============*/
  1027. ulint space, /* in: space id */
  1028. ulint page, /* in: page offset in the extent */
  1029. mtr_t* mtr) /* in: mtr */
  1030. {
  1031. fsp_header_t* header;
  1032. xdes_t* descr;
  1033. ut_ad(mtr);
  1034. header = fsp_get_space_header(space, mtr);
  1035. descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
  1036. ut_a(xdes_get_state(descr, mtr) != XDES_FREE);
  1037. xdes_init(descr, mtr);
  1038. flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
  1039. }
  1040. /**************************************************************************
  1041. Returns the nth inode slot on an inode page. */
  1042. UNIV_INLINE
  1043. fseg_inode_t*
  1044. fsp_seg_inode_page_get_nth_inode(
  1045. /*=============================*/
  1046. /* out: segment inode */
  1047. page_t* page, /* in: segment inode page */
  1048. ulint i, /* in: inode index on page */
  1049. mtr_t* mtr) /* in: mini-transaction handle */
  1050. {
  1051. ut_ad(i < FSP_SEG_INODES_PER_PAGE);
  1052. ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
  1053. MTR_MEMO_PAGE_X_FIX));
  1054. return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
  1055. }
  1056. /**************************************************************************
  1057. Looks for a used segment inode on a segment inode page. */ 
  1058. static
  1059. ulint
  1060. fsp_seg_inode_page_find_used(
  1061. /*=========================*/
  1062. /* out: segment inode index, or ULINT_UNDEFINED
  1063. if not found */
  1064. page_t* page, /* in: segment inode page */
  1065. mtr_t* mtr) /* in: mini-transaction handle */
  1066. {
  1067. ulint i;
  1068. fseg_inode_t* inode;
  1069. for (i = 0; i < FSP_SEG_INODES_PER_PAGE; i++) {
  1070. inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
  1071. if (ut_dulint_cmp(mach_read_from_8(inode + FSEG_ID),
  1072. ut_dulint_zero) != 0) {
  1073. /* This is used */
  1074. return(i);
  1075. }
  1076. }
  1077. return(ULINT_UNDEFINED);
  1078. }
  1079. /**************************************************************************
  1080. Looks for an unused segment inode on a segment inode page. */ 
  1081. static
  1082. ulint
  1083. fsp_seg_inode_page_find_free(
  1084. /*=========================*/
  1085. /* out: segment inode index, or ULINT_UNDEFINED
  1086. if not found */
  1087. page_t* page, /* in: segment inode page */
  1088. ulint j, /* in: search forward starting from this index */
  1089. mtr_t* mtr) /* in: mini-transaction handle */
  1090. {
  1091. ulint i;
  1092. fseg_inode_t* inode;
  1093. for (i = j; i < FSP_SEG_INODES_PER_PAGE; i++) {
  1094. inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
  1095. if (ut_dulint_cmp(mach_read_from_8(inode + FSEG_ID),
  1096. ut_dulint_zero) == 0) {
  1097. /* This is unused */
  1098. return(i);
  1099. }
  1100. }
  1101. return(ULINT_UNDEFINED);
  1102. }
  1103. /**************************************************************************
  1104. Allocates a new file segment inode page. */
  1105. static
  1106. ibool
  1107. fsp_alloc_seg_inode_page(
  1108. /*=====================*/
  1109. /* out: TRUE if could be allocated */
  1110. fsp_header_t* space_header, /* in: space header */
  1111. mtr_t* mtr) /* in: mini-transaction handle */
  1112. {
  1113. fseg_inode_t* inode;
  1114. page_t* page;
  1115. ulint page_no;
  1116. ulint space;
  1117. ulint i;
  1118. space = buf_frame_get_space_id(space_header);
  1119. page_no = fsp_alloc_free_page(space, 0, mtr);
  1120. if (page_no == FIL_NULL) {
  1121. return(FALSE);
  1122. }
  1123. page = buf_page_get(space, page_no, RW_X_LATCH, mtr);
  1124. buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
  1125. for (i = 0; i < FSP_SEG_INODES_PER_PAGE; i++) {
  1126. inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
  1127. mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero,
  1128. MLOG_8BYTES, mtr);
  1129. }
  1130. flst_add_last(space_header + FSP_SEG_INODES_FREE,
  1131. page + FSEG_INODE_PAGE_NODE, mtr);
  1132. return(TRUE);
  1133. }
  1134. /**************************************************************************
  1135. Allocates a new file segment inode. */
  1136. static
  1137. fseg_inode_t*
  1138. fsp_alloc_seg_inode(
  1139. /*================*/
  1140. /* out: segment inode, or NULL if
  1141. not enough space */
  1142. fsp_header_t* space_header, /* in: space header */
  1143. mtr_t* mtr) /* in: mini-transaction handle */
  1144. {
  1145. ulint page_no;
  1146. page_t* page;
  1147. fseg_inode_t* inode;
  1148. ibool success;
  1149. ulint n;
  1150. if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
  1151. /* Allocate a new segment inode page */
  1152. success = fsp_alloc_seg_inode_page(space_header, mtr);
  1153. if (!success) {
  1154. return(NULL);
  1155. }
  1156. }
  1157. page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
  1158. page = buf_page_get(buf_frame_get_space_id(space_header), page_no,
  1159. RW_X_LATCH, mtr);
  1160. buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
  1161. n = fsp_seg_inode_page_find_free(page, 0, mtr);
  1162. ut_a(n != ULINT_UNDEFINED);
  1163. inode = fsp_seg_inode_page_get_nth_inode(page, n, mtr);
  1164. if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1, mtr)) {
  1165. /* There are no other unused headers left on the page: move it
  1166. to another list */
  1167. flst_remove(space_header + FSP_SEG_INODES_FREE,
  1168. page + FSEG_INODE_PAGE_NODE, mtr);
  1169. flst_add_last(space_header + FSP_SEG_INODES_FULL,
  1170. page + FSEG_INODE_PAGE_NODE, mtr);
  1171. }
  1172. return(inode);
  1173. }
  1174. /**************************************************************************
  1175. Frees a file segment inode. */
  1176. static
  1177. void
  1178. fsp_free_seg_inode(
  1179. /*===============*/
  1180. ulint space, /* in: space id */
  1181. fseg_inode_t* inode, /* in: segment inode */
  1182. mtr_t* mtr) /* in: mini-transaction handle */
  1183. {
  1184. page_t* page;
  1185. fsp_header_t* space_header;
  1186. page = buf_frame_align(inode);
  1187. space_header = fsp_get_space_header(space, mtr);
  1188. ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
  1189. if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, 0, mtr)) {
  1190. /* Move the page to another list */
  1191. flst_remove(space_header + FSP_SEG_INODES_FULL,
  1192. page + FSEG_INODE_PAGE_NODE, mtr);
  1193. flst_add_last(space_header + FSP_SEG_INODES_FREE,
  1194. page + FSEG_INODE_PAGE_NODE, mtr);
  1195. }
  1196. mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, MLOG_8BYTES, mtr); 
  1197. mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr); 
  1198. if (ULINT_UNDEFINED == fsp_seg_inode_page_find_used(page, mtr)) {
  1199. /* There are no other used headers left on the page: free it */
  1200. flst_remove(space_header + FSP_SEG_INODES_FREE,
  1201. page + FSEG_INODE_PAGE_NODE, mtr);
  1202. fsp_free_page(space, buf_frame_get_page_no(page), mtr);
  1203. }
  1204. }
  1205. /**************************************************************************
  1206. Returns the file segment inode, page x-latched. */
  1207. static
  1208. fseg_inode_t*
  1209. fseg_inode_get(
  1210. /*===========*/
  1211. /* out: segment inode, page x-latched */
  1212. fseg_header_t* header, /* in: segment header */
  1213. mtr_t* mtr) /* in: mtr handle */
  1214. {
  1215. fil_addr_t inode_addr;
  1216. fseg_inode_t* inode;
  1217. inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
  1218. inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
  1219. inode = fut_get_ptr(mach_read_from_4(header + FSEG_HDR_SPACE),
  1220. inode_addr, RW_X_LATCH, mtr);
  1221. ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
  1222. return(inode);
  1223. }
  1224. /**************************************************************************
  1225. Gets the page number from the nth fragment page slot. */
  1226. UNIV_INLINE
  1227. ulint
  1228. fseg_get_nth_frag_page_no(
  1229. /*======================*/
  1230. /* out: page number, FIL_NULL if not in use */
  1231. fseg_inode_t*  inode, /* in: segment inode */
  1232. ulint n, /* in: slot index */
  1233. mtr_t* mtr) /* in: mtr handle */
  1234. {
  1235. ut_ad(inode && mtr);
  1236. ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
  1237. ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
  1238. MTR_MEMO_PAGE_X_FIX));
  1239. return(mach_read_from_4(inode + FSEG_FRAG_ARR
  1240. + n * FSEG_FRAG_SLOT_SIZE));
  1241. }
  1242. /**************************************************************************
  1243. Sets the page number in the nth fragment page slot. */
  1244. UNIV_INLINE
  1245. void
  1246. fseg_set_nth_frag_page_no(
  1247. /*======================*/
  1248. fseg_inode_t*  inode, /* in: segment inode */
  1249. ulint n, /* in: slot index */
  1250. ulint page_no,/* in: page number to set */
  1251. mtr_t* mtr) /* in: mtr handle */
  1252. {
  1253. ut_ad(inode && mtr);
  1254. ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
  1255. ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
  1256. MTR_MEMO_PAGE_X_FIX));
  1257. mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
  1258. page_no, MLOG_4BYTES, mtr);
  1259. }
  1260. /**************************************************************************
  1261. Finds a fragment page slot which is free. */
  1262. static
  1263. ulint
  1264. fseg_find_free_frag_page_slot(
  1265. /*==========================*/
  1266. /* out: slot index; ULINT_UNDEFINED if none
  1267. found */
  1268. fseg_inode_t*  inode, /* in: segment inode */
  1269. mtr_t* mtr) /* in: mtr handle */
  1270. {
  1271. ulint i;
  1272. ulint page_no;
  1273. ut_ad(inode && mtr);
  1274. for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
  1275. page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
  1276. if (page_no == FIL_NULL) {
  1277. return(i);
  1278. }
  1279. }
  1280. return(ULINT_UNDEFINED);
  1281. }
  1282. /**************************************************************************
  1283. Finds a fragment page slot which is used and last in the array. */
  1284. static
  1285. ulint
  1286. fseg_find_last_used_frag_page_slot(
  1287. /*===============================*/
  1288. /* out: slot index; ULINT_UNDEFINED if none
  1289. found */
  1290. fseg_inode_t*  inode, /* in: segment inode */
  1291. mtr_t* mtr) /* in: mtr handle */
  1292. {
  1293. ulint i;
  1294. ulint page_no;
  1295. ut_ad(inode && mtr);
  1296. for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
  1297. page_no = fseg_get_nth_frag_page_no(inode,
  1298. FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
  1299. if (page_no != FIL_NULL) {
  1300. return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
  1301. }
  1302. }
  1303. return(ULINT_UNDEFINED);
  1304. }
  1305. /**************************************************************************
  1306. Calculates reserved fragment page slots. */
  1307. static
  1308. ulint
  1309. fseg_get_n_frag_pages(
  1310. /*==================*/
  1311. /* out: number of fragment pages */
  1312. fseg_inode_t*  inode, /* in: segment inode */
  1313. mtr_t* mtr) /* in: mtr handle */
  1314. {
  1315. ulint i;
  1316. ulint count = 0;
  1317. ut_ad(inode && mtr);
  1318. for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
  1319. if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
  1320. count++;
  1321. }
  1322. }
  1323. return(count);
  1324. }
  1325. /**************************************************************************
  1326. Creates a new segment. */
  1327. page_t*
  1328. fseg_create_general(
  1329. /*================*/
  1330. /* out: the page where the segment header is placed,
  1331. x-latched, NULL if could not create segment
  1332. because of lack of space */
  1333. ulint space, /* in: space id */
  1334. ulint page, /* in: page where the segment header is placed: if
  1335. this is != 0, the page must belong to another segment,
  1336. if this is 0, a new page will be allocated and it
  1337. will belong to the created segment */
  1338. ulint byte_offset, /* in: byte offset of the created segment header
  1339. on the page */
  1340. ibool has_done_reservation, /* in: TRUE if the caller has
  1341. already done the reservation for the pages
  1342. with fsp_reserve_free_extents (at least 2 extents:
  1343. one for the inode and, then there other for the
  1344. segment) is no need to do the check for this
  1345. individual operation */
  1346. mtr_t* mtr) /* in: mtr */
  1347. {
  1348. fsp_header_t* space_header;
  1349. fseg_inode_t* inode;
  1350. dulint seg_id;
  1351. fseg_header_t* header;
  1352. rw_lock_t* latch;
  1353. ibool success;
  1354. page_t* ret = NULL;
  1355. ulint i;
  1356. ut_ad(mtr);
  1357. if (page != 0) {
  1358. header = byte_offset + buf_page_get(space, page, RW_X_LATCH,
  1359. mtr);
  1360. }
  1361. ut_ad(!mutex_own(&kernel_mutex)
  1362.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  1363. MTR_MEMO_X_LOCK));
  1364. latch = fil_space_get_latch(space);
  1365. mtr_x_lock(latch, mtr);
  1366. if (rw_lock_get_x_lock_count(latch) == 1) {
  1367. /* This thread did not own the latch before this call: free
  1368. excess pages from the insert buffer free list */
  1369. ibuf_free_excess_pages(space);
  1370. }
  1371. if (!has_done_reservation) { 
  1372. success = fsp_reserve_free_extents(space, 2, FSP_NORMAL, mtr);
  1373. if (!success) {
  1374. return(NULL);
  1375. }
  1376. }
  1377. space_header = fsp_get_space_header(space, mtr);
  1378. inode = fsp_alloc_seg_inode(space_header, mtr);
  1379. if (inode == NULL) {
  1380. goto funct_exit;
  1381. }
  1382. /* Read the next segment id from space header and increment the
  1383. value in space header */
  1384. seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, MLOG_8BYTES, mtr);
  1385. mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1),
  1386. MLOG_8BYTES, mtr);
  1387. mlog_write_dulint(inode + FSEG_ID, seg_id, MLOG_8BYTES, mtr); 
  1388. mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr); 
  1389. flst_init(inode + FSEG_FREE, mtr);
  1390. flst_init(inode + FSEG_NOT_FULL, mtr);
  1391. flst_init(inode + FSEG_FULL, mtr);
  1392. mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
  1393. MLOG_4BYTES, mtr); 
  1394. for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
  1395. fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
  1396. }
  1397. if (page == 0) {
  1398. page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr);
  1399. if (page == FIL_NULL) {
  1400. fsp_free_seg_inode(space, inode, mtr);
  1401. goto funct_exit;
  1402. }
  1403. header = byte_offset
  1404.  + buf_page_get(space, page, RW_X_LATCH, mtr);
  1405. }
  1406. mlog_write_ulint(header + FSEG_HDR_OFFSET,
  1407. inode - buf_frame_align(inode), MLOG_2BYTES, mtr);
  1408. mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
  1409. buf_frame_get_page_no(inode), MLOG_4BYTES, mtr);
  1410. mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
  1411. ret = buf_frame_align(header);
  1412. funct_exit:
  1413. if (!has_done_reservation) { 
  1414. fil_space_release_free_extents(space, 2);
  1415. }
  1416. return(ret);
  1417. }
  1418. /**************************************************************************
  1419. Creates a new segment. */
  1420. page_t*
  1421. fseg_create(
  1422. /*========*/
  1423. /* out: the page where the segment header is placed,
  1424. x-latched, NULL if could not create segment
  1425. because of lack of space */
  1426. ulint space, /* in: space id */
  1427. ulint page, /* in: page where the segment header is placed: if
  1428. this is != 0, the page must belong to another segment,
  1429. if this is 0, a new page will be allocated and it
  1430. will belong to the created segment */
  1431. ulint byte_offset, /* in: byte offset of the created segment header
  1432. on the page */
  1433. mtr_t* mtr) /* in: mtr */
  1434. {
  1435. return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
  1436. }
  1437. /**************************************************************************
  1438. Calculates the number of pages reserved by a segment, and how many pages are
  1439. currently used. */
  1440. static
  1441. ulint
  1442. fseg_n_reserved_pages_low(
  1443. /*======================*/
  1444. /* out: number of reserved pages */
  1445. fseg_inode_t*  inode, /* in: segment inode */
  1446. ulint* used, /* out: number of pages used (<= reserved) */
  1447. mtr_t* mtr) /* in: mtr handle */
  1448. {
  1449. ulint ret;
  1450. ut_ad(inode && used && mtr);
  1451. ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
  1452. MTR_MEMO_PAGE_X_FIX));
  1453. *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
  1454. + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
  1455. + fseg_get_n_frag_pages(inode, mtr);
  1456. ret = fseg_get_n_frag_pages(inode, mtr)
  1457. + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
  1458. + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
  1459. + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
  1460. return(ret);
  1461. }
  1462. /**************************************************************************
  1463. Calculates the number of pages reserved by a segment, and how many pages are
  1464. currently used. */
  1465. ulint
  1466. fseg_n_reserved_pages(
  1467. /*==================*/
  1468. /* out: number of reserved pages */
  1469. fseg_header_t*  header, /* in: segment header */
  1470. ulint* used, /* out: number of pages used (<= reserved) */
  1471. mtr_t* mtr) /* in: mtr handle */
  1472. {
  1473. ulint ret;
  1474. fseg_inode_t* inode;
  1475. ulint space;
  1476. space = buf_frame_get_space_id(header);
  1477. ut_ad(!mutex_own(&kernel_mutex)
  1478.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  1479. MTR_MEMO_X_LOCK));
  1480. mtr_x_lock(fil_space_get_latch(space), mtr);
  1481. inode = fseg_inode_get(header, mtr);
  1482. ret = fseg_n_reserved_pages_low(inode, used, mtr);
  1483. return(ret);
  1484. }
  1485. /*************************************************************************
  1486. Tries to fill the free list of a segment with consecutive free extents.
  1487. This happens if the segment is big enough to allow extents in the free list,
  1488. the free list is empty, and the extents can be allocated consecutively from
  1489. the hint onward. */
  1490. static
  1491. void
  1492. fseg_fill_free_list(
  1493. /*================*/
  1494. fseg_inode_t* inode, /* in: segment inode */
  1495. ulint space, /* in: space id */
  1496. ulint hint, /* in: hint which extent would be good as
  1497. the first extent */
  1498. mtr_t* mtr) /* in: mtr */
  1499. {
  1500. xdes_t* descr;
  1501. ulint i;
  1502. dulint seg_id;
  1503. ulint reserved;
  1504. ulint used;
  1505. ut_ad(inode && mtr);
  1506. reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
  1507. if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
  1508. /* The segment is too small to allow extents in free list */
  1509. return;
  1510. }
  1511. if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
  1512. /* Free list is not empty */
  1513. return;
  1514. }
  1515. for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
  1516. descr = xdes_get_descriptor(space, hint, mtr);
  1517. if ((descr == NULL) ||
  1518.     (XDES_FREE != xdes_get_state(descr, mtr))) {
  1519. /* We cannot allocate the desired extent: stop */
  1520.      return;
  1521. }
  1522. descr = fsp_alloc_free_extent(space, hint, mtr);
  1523. xdes_set_state(descr, XDES_FSEG, mtr);
  1524. seg_id = mtr_read_dulint(inode + FSEG_ID, MLOG_8BYTES, mtr);
  1525. mlog_write_dulint(descr + XDES_ID, seg_id, MLOG_8BYTES, mtr);
  1526. flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
  1527. hint += FSP_EXTENT_SIZE;
  1528. }
  1529. }
  1530. /*************************************************************************
  1531. Allocates a free extent for the segment: looks first in the free list of the
  1532. segment, then tries to allocate from the space free list. NOTE that the extent
  1533. returned still resides in the segment free list, it is not yet taken off it! */
  1534. static
  1535. xdes_t*
  1536. fseg_alloc_free_extent(
  1537. /*===================*/
  1538. /* out: allocated extent, still placed in the
  1539. segment free list, NULL if could
  1540. not be allocated */
  1541. fseg_inode_t* inode, /* in: segment inode */
  1542. ulint space, /* in: space id */
  1543. mtr_t* mtr) /* in: mtr */
  1544. {
  1545. xdes_t* descr;
  1546. dulint seg_id;
  1547. fil_addr_t  first;
  1548. if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
  1549. /* Segment free list is not empty, allocate from it */
  1550. first = flst_get_first(inode + FSEG_FREE, mtr);
  1551. descr = xdes_lst_get_descriptor(space, first, mtr);
  1552. } else {
  1553. /* Segment free list was empty, allocate from space */
  1554. descr = fsp_alloc_free_extent(space, 0, mtr);
  1555. if (descr == NULL) {
  1556. return(NULL);
  1557. }
  1558. seg_id = mtr_read_dulint(inode + FSEG_ID, MLOG_8BYTES, mtr);
  1559. xdes_set_state(descr, XDES_FSEG, mtr);
  1560. mlog_write_dulint(descr + XDES_ID, seg_id, MLOG_8BYTES, mtr);
  1561. flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
  1562. /* Try to fill the segment free list */
  1563. fseg_fill_free_list(inode, space,
  1564. xdes_get_offset(descr) + FSP_EXTENT_SIZE, mtr);
  1565. }
  1566. return(descr);
  1567. }
  1568. /**************************************************************************
  1569. Allocates a single free page from a segment. This function implements
  1570. the intelligent allocation strategy which tries to minimize file space
  1571. fragmentation. */
  1572. static
  1573. ulint
  1574. fseg_alloc_free_page_low(
  1575. /*=====================*/
  1576. /* out: the allocated page number, FIL_NULL
  1577. if no page could be allocated */
  1578. ulint space, /* in: space */
  1579. fseg_inode_t*  seg_inode, /* in: segment inode */
  1580. ulint hint, /* in: hint of which page would be desirable */
  1581. byte direction, /* in: if the new page is needed because
  1582. of an index page split, and records are
  1583. inserted there in order, into which
  1584. direction they go alphabetically: FSP_DOWN,
  1585. FSP_UP, FSP_NO_DIR */
  1586. mtr_t* mtr) /* in: mtr handle */
  1587. {
  1588. dulint seg_id;
  1589. ulint used;
  1590. ulint reserved;
  1591. fil_addr_t first;
  1592. xdes_t* descr; /* extent of the hinted page */
  1593. ulint ret_page; /* the allocated page offset, FIL_NULL
  1594. if could not be allocated */
  1595. xdes_t* ret_descr; /* the extent of the allocated page */
  1596. page_t* page;
  1597. ibool frag_page_allocated = FALSE;
  1598. ulint n;
  1599. ut_ad(mtr);
  1600. ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
  1601. ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) ==
  1602. FSEG_MAGIC_N_VALUE);
  1603. seg_id = mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr);
  1604. ut_ad(ut_dulint_cmp(seg_id, ut_dulint_zero) > 0);
  1605. reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
  1606. descr = xdes_get_descriptor(space, hint, mtr);
  1607. if (descr == NULL) {
  1608. /* Hint outside space or too high above free limit: reset
  1609. hint */
  1610. hint = 0;
  1611. descr = xdes_get_descriptor(space, hint, mtr);
  1612. }
  1613.  
  1614. /* In the big if-else below we look for ret_page and ret_descr */
  1615. /*-------------------------------------------------------------*/ 
  1616. if ((xdes_get_state(descr, mtr) == XDES_FSEG)
  1617.            && (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
  1618. MLOG_8BYTES, mtr),
  1619. seg_id))
  1620.            && (xdes_get_bit(descr, XDES_FREE_BIT,
  1621. hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
  1622. /* 1. We can take the hinted page
  1623. =================================*/
  1624. ret_descr = descr;
  1625. ret_page = hint;
  1626. /*-------------------------------------------------------------*/ 
  1627. } else if ((xdes_get_state(descr, mtr) == XDES_FREE)
  1628.    && ((reserved - used) < reserved / FSEG_FILLFACTOR)
  1629.    && (used >= FSEG_FRAG_LIMIT)) {
  1630. /* 2. We allocate the free extent from space and can take
  1631. =========================================================
  1632. the hinted page
  1633. ===============*/
  1634. ret_descr = fsp_alloc_free_extent(space, hint, mtr);
  1635. ut_a(ret_descr == descr);
  1636. xdes_set_state(ret_descr, XDES_FSEG, mtr);
  1637. mlog_write_dulint(ret_descr + XDES_ID, seg_id, MLOG_8BYTES,
  1638. mtr);
  1639. flst_add_last(seg_inode + FSEG_FREE,
  1640. ret_descr + XDES_FLST_NODE, mtr);
  1641. /* Try to fill the segment free list */
  1642. fseg_fill_free_list(seg_inode, space,
  1643. hint + FSP_EXTENT_SIZE, mtr);
  1644. ret_page = hint;
  1645. /*-------------------------------------------------------------*/ 
  1646. } else if ((direction != FSP_NO_DIR)
  1647.    && ((reserved - used) < reserved / FSEG_FILLFACTOR)
  1648.    && (used >= FSEG_FRAG_LIMIT)
  1649.    && (NULL != (ret_descr =
  1650. fseg_alloc_free_extent(seg_inode, space, mtr)))) {
  1651. /* 3. We take any free extent (which was already assigned above
  1652. ===============================================================
  1653. in the if-condition to ret_descr) and take the lowest or
  1654. ========================================================
  1655. highest page in it, depending on the direction
  1656. ==============================================*/
  1657. ret_page = xdes_get_offset(ret_descr);
  1658. if (direction == FSP_DOWN) {
  1659. ret_page += FSP_EXTENT_SIZE - 1;
  1660. }
  1661. /*-------------------------------------------------------------*/ 
  1662. } else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
  1663.            && (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
  1664. MLOG_8BYTES, mtr),
  1665. seg_id))
  1666.            && (!xdes_is_full(descr, mtr))) {
  1667. /* 4. We can take the page from the same extent as the
  1668. ======================================================
  1669. hinted page (and the extent already belongs to the
  1670. ==================================================
  1671. segment)
  1672. ========*/
  1673. ret_descr = descr;
  1674. ret_page = xdes_get_offset(ret_descr) +
  1675. xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
  1676. hint % FSP_EXTENT_SIZE, mtr);
  1677. /*-------------------------------------------------------------*/ 
  1678. } else if (reserved - used > 0) {
  1679. /* 5. We take any unused page from the segment
  1680. ==============================================*/
  1681. if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
  1682. first = flst_get_first(seg_inode + FSEG_NOT_FULL,
  1683. mtr);
  1684. } else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
  1685. first = flst_get_first(seg_inode + FSEG_FREE, mtr);
  1686. } else {
  1687. ut_error;
  1688. }
  1689. ret_descr = xdes_lst_get_descriptor(space, first, mtr);
  1690. ret_page = xdes_get_offset(ret_descr) +
  1691. xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
  1692. 0, mtr);
  1693. /*-------------------------------------------------------------*/ 
  1694. } else if (used < FSEG_FRAG_LIMIT) {
  1695. /* 6. We allocate an individual page from the space
  1696. ===================================================*/
  1697. ret_page = fsp_alloc_free_page(space, hint, mtr);
  1698. ret_descr = NULL;
  1699. frag_page_allocated = TRUE;
  1700. if (ret_page != FIL_NULL) {
  1701. /* Put the page in the fragment page array of the
  1702. segment */
  1703. n = fseg_find_free_frag_page_slot(seg_inode, mtr);
  1704. ut_a(n != FIL_NULL);
  1705. fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
  1706. mtr);
  1707. }
  1708. /*-------------------------------------------------------------*/ 
  1709. } else {
  1710. /* 7. We allocate a new extent and take its first page
  1711. ======================================================*/
  1712. ret_descr = fseg_alloc_free_extent(seg_inode, space, mtr);
  1713. if (ret_descr == NULL) {
  1714. ret_page = FIL_NULL;
  1715. } else {
  1716. ret_page = xdes_get_offset(ret_descr);
  1717. }
  1718. }
  1719. if (ret_page == FIL_NULL) {
  1720. /* Page could not be allocated */
  1721. return(FIL_NULL);
  1722. }
  1723. if (!frag_page_allocated) {
  1724. /* Initialize the allocated page to buffer pool, so that it
  1725. can be obtained immediately with buf_page_get without need
  1726. for a disk read */
  1727. page = buf_page_create(space, ret_page, mtr);
  1728. ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr));
  1729. buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
  1730. /* The prior contents of the page should be ignored */
  1731. fsp_init_file_page(page, mtr);
  1732. /* At this point we know the extent and the page offset.
  1733. The extent is still in the appropriate list (FSEG_NOT_FULL
  1734. or FSEG_FREE), and the page is not yet marked as used. */
  1735. ut_ad(xdes_get_descriptor(space, ret_page, mtr) == ret_descr);
  1736. ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
  1737. ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
  1738. fseg_mark_page_used(seg_inode, space, ret_page, mtr);
  1739. }
  1740. return(ret_page);
  1741. }
  1742. /**************************************************************************
  1743. Allocates a single free page from a segment. This function implements
  1744. the intelligent allocation strategy which tries to minimize file space
  1745. fragmentation. */
  1746. ulint
  1747. fseg_alloc_free_page_general(
  1748. /*=========================*/
  1749. /* out: allocated page offset, FIL_NULL if no
  1750. page could be allocated */
  1751. fseg_header_t* seg_header,/* in: segment header */
  1752. ulint hint, /* in: hint of which page would be desirable */
  1753. byte direction,/* in: if the new page is needed because
  1754. of an index page split, and records are
  1755. inserted there in order, into which
  1756. direction they go alphabetically: FSP_DOWN,
  1757. FSP_UP, FSP_NO_DIR */
  1758. ibool has_done_reservation, /* in: TRUE if the caller has
  1759. already done the reservation for the page
  1760. with fsp_reserve_free_extents, then there
  1761. is no need to do the check for this individual
  1762. page */
  1763. mtr_t* mtr) /* in: mtr handle */
  1764. {
  1765. fseg_inode_t* inode;
  1766. ulint space;
  1767. rw_lock_t* latch;
  1768. ibool success;
  1769. ulint page_no;
  1770. space = buf_frame_get_space_id(seg_header);
  1771. ut_ad(!mutex_own(&kernel_mutex)
  1772.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  1773. MTR_MEMO_X_LOCK));
  1774. latch = fil_space_get_latch(space);
  1775. mtr_x_lock(latch, mtr);
  1776. if (rw_lock_get_x_lock_count(latch) == 1) {
  1777. /* This thread did not own the latch before this call: free
  1778. excess pages from the insert buffer free list */
  1779. ibuf_free_excess_pages(space);
  1780. }
  1781. inode = fseg_inode_get(seg_header, mtr);
  1782. if (!has_done_reservation) {
  1783. success = fsp_reserve_free_extents(space, 2, FSP_NORMAL, mtr);
  1784. if (!success) {
  1785. return(FIL_NULL);
  1786. }
  1787. }
  1788. page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode),
  1789. inode, hint, direction, mtr);
  1790. if (!has_done_reservation) {
  1791. fil_space_release_free_extents(space, 2);
  1792. }
  1793. return(page_no);
  1794. }
  1795. /**************************************************************************
  1796. Allocates a single free page from a segment. This function implements
  1797. the intelligent allocation strategy which tries to minimize file space
  1798. fragmentation. */
  1799. ulint
  1800. fseg_alloc_free_page(
  1801. /*=================*/
  1802. /* out: allocated page offset, FIL_NULL if no
  1803. page could be allocated */
  1804. fseg_header_t* seg_header,/* in: segment header */
  1805. ulint hint, /* in: hint of which page would be desirable */
  1806. byte direction,/* in: if the new page is needed because
  1807. of an index page split, and records are
  1808. inserted there in order, into which
  1809. direction they go alphabetically: FSP_DOWN,
  1810. FSP_UP, FSP_NO_DIR */
  1811. mtr_t* mtr) /* in: mtr handle */
  1812. {
  1813. return(fseg_alloc_free_page_general(seg_header, hint, direction,
  1814. FALSE, mtr));
  1815. }
  1816. /**************************************************************************
  1817. Reserves free pages from a tablespace. All mini-transactions which may
  1818. use several pages from the tablespace should call this function beforehand
  1819. and reserve enough free extents so that they certainly will be able
  1820. to do their operation, like a B-tree page split, fully. Reservations
  1821. must be released with function fil_space_release_free_extents!
  1822. The alloc_type below has the following meaning: FSP_NORMAL means an
  1823. operation which will probably result in more space usage, like an
  1824. insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
  1825. deleting rows, then this allocation will in the long run result in
  1826. less space usage (after a purge); FSP_CLEANING means allocation done
  1827. in a physical record delete (like in a purge) or other cleaning operation
  1828. which will result in less space usage in the long run. We prefer the latter
  1829. two types of allocation: when space is scarce, FSP_NORMAL allocations
  1830. will not succeed, but the latter two allocations will succeed, if possible.
  1831. The purpose is to avoid dead end where the database is full but the
  1832. user cannot free any space because these freeing operations temporarily
  1833. reserve some space. */ 
  1834. ibool
  1835. fsp_reserve_free_extents(
  1836. /*=====================*/
  1837. /* out: TRUE if we were able to make the reservation */
  1838. ulint space, /* in: space id */
  1839. ulint n_ext, /* in: number of extents to reserve */
  1840. ulint alloc_type,/* in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
  1841. mtr_t* mtr) /* in: mtr */
  1842. {
  1843. fsp_header_t* space_header;
  1844. ulint n_free_list_ext;
  1845. ulint free_limit;
  1846. ulint size;
  1847. ulint n_free;
  1848. ulint n_free_up;
  1849. ulint reserve;
  1850. rw_lock_t* latch;
  1851. ut_ad(mtr);
  1852. ut_ad(!mutex_own(&kernel_mutex)
  1853.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  1854. MTR_MEMO_X_LOCK));
  1855. latch = fil_space_get_latch(space);
  1856. mtr_x_lock(latch, mtr);
  1857. space_header = fsp_get_space_header(space, mtr);
  1858. size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
  1859. n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
  1860. free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
  1861. MLOG_4BYTES, mtr);
  1862. /* Below we play safe when counting free extents above the free limit:
  1863. some of them will contain extent descriptor pages, and therefore
  1864. will not be free extents */
  1865. n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
  1866. if (n_free_up > 0) {
  1867. n_free_up--;
  1868. n_free_up = n_free_up - n_free_up
  1869. / (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE);
  1870. }
  1871. n_free = n_free_list_ext + n_free_up;
  1872. if (alloc_type == FSP_NORMAL) {
  1873. /* We reserve 1 extent + 4 % of the space size to undo logs
  1874. and 1 extent + 1 % to cleaning operations; NOTE: this source
  1875. code is duplicated in the function below! */
  1876. reserve = 2 + ((size / FSP_EXTENT_SIZE) * 5) / 100;
  1877. if (n_free <= reserve + n_ext) {
  1878. return(FALSE);
  1879. }
  1880. } else if (alloc_type == FSP_UNDO) {
  1881. /* We reserve 1 % of the space size to cleaning operations */
  1882. reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 100;
  1883. if (n_free <= reserve + n_ext) {
  1884. return(FALSE);
  1885. }
  1886. } else {
  1887. ut_a(alloc_type == FSP_CLEANING);
  1888. }
  1889. return(fil_space_reserve_free_extents(space, n_free, n_ext));
  1890. }
  1891. /**************************************************************************
  1892. This function should be used to get information on how much we still
  1893. will be able to insert new data to the database without running out the
  1894. tablespace. Only free extents are taken into account and we also subtract
  1895. the safety margin required by the above function fsp_reserve_free_extents. */
  1896. ulint
  1897. fsp_get_available_space_in_free_extents(
  1898. /*====================================*/
  1899. /* out: available space in kB */
  1900. ulint space) /* in: space id */
  1901. {
  1902. fsp_header_t* space_header;
  1903. ulint n_free_list_ext;
  1904. ulint free_limit;
  1905. ulint size;
  1906. ulint n_free;
  1907. ulint n_free_up;
  1908. ulint reserve;
  1909. rw_lock_t* latch;
  1910. mtr_t mtr;
  1911. ut_ad(!mutex_own(&kernel_mutex));
  1912. mtr_start(&mtr);
  1913. latch = fil_space_get_latch(space);
  1914. mtr_x_lock(latch, &mtr);
  1915. space_header = fsp_get_space_header(space, &mtr);
  1916. size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
  1917. n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
  1918. free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
  1919. MLOG_4BYTES, &mtr);
  1920. mtr_commit(&mtr);
  1921. /* Below we play safe when counting free extents above the free limit:
  1922. some of them will contain extent descriptor pages, and therefore
  1923. will not be free extents */
  1924. n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
  1925. if (n_free_up > 0) {
  1926. n_free_up--;
  1927. n_free_up = n_free_up - n_free_up
  1928. / (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE);
  1929. }
  1930. n_free = n_free_list_ext + n_free_up;
  1931. /* We reserve 1 extent + 4 % of the space size to undo logs
  1932. and 1 extent + 1 % to cleaning operations; NOTE: this source
  1933. code is duplicated in the function above! */
  1934. reserve = 2 + ((size / FSP_EXTENT_SIZE) * 5) / 100;
  1935. if (reserve > n_free) {
  1936. return(0);
  1937. }
  1938. return(((n_free - reserve) * FSP_EXTENT_SIZE)
  1939. * (UNIV_PAGE_SIZE / 1024));
  1940. }
  1941. /************************************************************************
  1942. Marks a page used. The page must reside within the extents of the given
  1943. segment. */
  1944. static
  1945. void
  1946. fseg_mark_page_used(
  1947. /*================*/
  1948. fseg_inode_t* seg_inode,/* in: segment inode */
  1949. ulint space, /* in: space id */
  1950. ulint page, /* in: page offset */
  1951. mtr_t* mtr) /* in: mtr */
  1952. {
  1953. xdes_t* descr;
  1954. ulint not_full_n_used;
  1955. ut_ad(seg_inode && mtr);
  1956. descr = xdes_get_descriptor(space, page, mtr);
  1957. ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr) ==
  1958. mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
  1959. if (xdes_is_free(descr, mtr)) {
  1960. /* We move the extent from the free list to the
  1961. NOT_FULL list */
  1962. flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
  1963. mtr);
  1964. flst_add_last(seg_inode + FSEG_NOT_FULL,
  1965. descr + XDES_FLST_NODE, mtr);
  1966. }
  1967. ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
  1968. == TRUE);
  1969. /* We mark the page as used */
  1970. xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
  1971. not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
  1972. MLOG_4BYTES, mtr);
  1973. not_full_n_used++;
  1974. mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
  1975. MLOG_4BYTES, mtr);
  1976. if (xdes_is_full(descr, mtr)) {
  1977. /* We move the extent from the NOT_FULL list to the
  1978. FULL list */
  1979. flst_remove(seg_inode + FSEG_NOT_FULL,
  1980. descr + XDES_FLST_NODE, mtr);
  1981. flst_add_last(seg_inode + FSEG_FULL,
  1982. descr + XDES_FLST_NODE, mtr);
  1983. mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
  1984. not_full_n_used - FSP_EXTENT_SIZE,
  1985. MLOG_4BYTES, mtr);
  1986. }
  1987. }
  1988. /**************************************************************************
  1989. Frees a single page of a segment. */
  1990. static
  1991. void
  1992. fseg_free_page_low(
  1993. /*===============*/
  1994. fseg_inode_t* seg_inode, /* in: segment inode */
  1995. ulint space, /* in: space id */
  1996. ulint page, /* in: page offset */
  1997. mtr_t* mtr) /* in: mtr handle */
  1998. {
  1999. xdes_t* descr;
  2000. ulint not_full_n_used;
  2001. ulint state;
  2002. ulint i;
  2003. ut_ad(seg_inode && mtr);
  2004. ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) ==
  2005. FSEG_MAGIC_N_VALUE);
  2006. /* Drop search system page hash index if the page is found in
  2007. the pool and is hashed */
  2008. btr_search_drop_page_hash_when_freed(space, page);
  2009. descr = xdes_get_descriptor(space, page, mtr);
  2010. ut_a(descr);
  2011. ut_a(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
  2012. == FALSE);
  2013. state = xdes_get_state(descr, mtr);
  2014. if (state != XDES_FSEG) {
  2015. /* The page is in the fragment pages of the segment */
  2016. for (i = 0;; i++) {
  2017. if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
  2018.     == page) {
  2019. fseg_set_nth_frag_page_no(seg_inode, i,
  2020. FIL_NULL, mtr);
  2021. break;
  2022. }
  2023. }
  2024. fsp_free_page(space, page, mtr);
  2025. return;
  2026. }
  2027. /* If we get here, the page is in some extent of the segment */
  2028. ut_a(0 == ut_dulint_cmp(
  2029. mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr),
  2030. mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr)));
  2031. not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
  2032. MLOG_4BYTES, mtr);
  2033. if (xdes_is_full(descr, mtr)) {
  2034. /* The fragment is full: move it to another list */
  2035. flst_remove(seg_inode + FSEG_FULL,
  2036. descr + XDES_FLST_NODE, mtr);
  2037. flst_add_last(seg_inode + FSEG_NOT_FULL,
  2038. descr + XDES_FLST_NODE, mtr);
  2039. mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
  2040. not_full_n_used + FSP_EXTENT_SIZE - 1,
  2041. MLOG_4BYTES, mtr);
  2042. } else {
  2043. ut_a(not_full_n_used > 0);
  2044. mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
  2045. not_full_n_used - 1, MLOG_4BYTES, mtr);
  2046. }
  2047. xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
  2048. xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
  2049. if (xdes_is_free(descr, mtr)) {
  2050.      /* The extent has become free: free it to space */
  2051. flst_remove(seg_inode + FSEG_NOT_FULL,
  2052. descr + XDES_FLST_NODE, mtr);
  2053. fsp_free_extent(space, page, mtr);
  2054. }
  2055. }
  2056. /**************************************************************************
  2057. Frees a single page of a segment. */
  2058. void
  2059. fseg_free_page(
  2060. /*===========*/
  2061. fseg_header_t* seg_header, /* in: segment header */
  2062. ulint space, /* in: space id */
  2063. ulint page, /* in: page offset */
  2064. mtr_t* mtr) /* in: mtr handle */
  2065. {
  2066. fseg_inode_t* seg_inode;
  2067. ut_ad(!mutex_own(&kernel_mutex)
  2068.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  2069. MTR_MEMO_X_LOCK));
  2070. mtr_x_lock(fil_space_get_latch(space), mtr);
  2071. seg_inode = fseg_inode_get(seg_header, mtr);
  2072. fseg_free_page_low(seg_inode, space, page, mtr);
  2073. }
  2074. /**************************************************************************
  2075. Frees an extent of a segment to the space free list. */
  2076. static
  2077. void
  2078. fseg_free_extent(
  2079. /*=============*/
  2080. fseg_inode_t* seg_inode, /* in: segment inode */
  2081. ulint space, /* in: space id */
  2082. ulint page, /* in: a page in the extent */
  2083. mtr_t* mtr) /* in: mtr handle */
  2084. {
  2085. ulint first_page_in_extent;
  2086. xdes_t* descr;
  2087. ulint not_full_n_used;
  2088. ulint descr_n_used;
  2089. ulint i;
  2090. ut_ad(seg_inode && mtr);
  2091. descr = xdes_get_descriptor(space, page, mtr);
  2092. ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
  2093. ut_a(0 == ut_dulint_cmp(
  2094. mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr),
  2095.       mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr)));
  2096. first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
  2097.      
  2098. for (i = 0; i < FSP_EXTENT_SIZE; i++) {
  2099. if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
  2100. /* Drop search system page hash index if the page is
  2101. found in the pool and is hashed */
  2102. btr_search_drop_page_hash_when_freed(space,
  2103. first_page_in_extent + i);
  2104. }
  2105. }
  2106. if (xdes_is_full(descr, mtr)) {
  2107. flst_remove(seg_inode + FSEG_FULL,
  2108. descr + XDES_FLST_NODE, mtr);
  2109. } else if (xdes_is_free(descr, mtr)) {
  2110. flst_remove(seg_inode + FSEG_FREE,
  2111. descr + XDES_FLST_NODE, mtr);
  2112. } else {
  2113. flst_remove(seg_inode + FSEG_NOT_FULL,
  2114. descr + XDES_FLST_NODE, mtr);
  2115. not_full_n_used = mtr_read_ulint(
  2116. seg_inode + FSEG_NOT_FULL_N_USED,
  2117. MLOG_4BYTES, mtr);
  2118. descr_n_used = xdes_get_n_used(descr, mtr);
  2119. ut_a(not_full_n_used >= descr_n_used);
  2120. mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
  2121. not_full_n_used - descr_n_used,
  2122. MLOG_4BYTES, mtr);
  2123. }
  2124. fsp_free_extent(space, page, mtr);
  2125. }
  2126. /**************************************************************************
  2127. Frees part of a segment. This function can be used to free a segment by
  2128. repeatedly calling this function in different mini-transactions. Doing
  2129. the freeing in a single mini-transaction might result in too big a
  2130. mini-transaction. */
  2131. ibool
  2132. fseg_free_step(
  2133. /*===========*/
  2134. /* out: TRUE if freeing completed */
  2135. fseg_header_t* header, /* in, own: segment header; NOTE: if the header
  2136. resides on the first page of the frag list
  2137. of the segment, this pointer becomes obsolete
  2138. after the last freeing step */
  2139. mtr_t* mtr) /* in: mtr */
  2140. {
  2141. ulint n;
  2142. ulint page;
  2143. xdes_t* descr;
  2144. fseg_inode_t* inode;
  2145. ulint space;
  2146. space = buf_frame_get_space_id(header);
  2147. ut_ad(!mutex_own(&kernel_mutex)
  2148.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  2149. MTR_MEMO_X_LOCK));
  2150. mtr_x_lock(fil_space_get_latch(space), mtr);
  2151. inode = fseg_inode_get(header, mtr);
  2152. descr = fseg_get_first_extent(inode, mtr);
  2153. if (descr != NULL) {
  2154. /* Free the extent held by the segment */
  2155. page = xdes_get_offset(descr);
  2156. fseg_free_extent(inode, space, page, mtr);
  2157. return(FALSE);
  2158. }
  2159. /* Free a frag page */
  2160. n = fseg_find_last_used_frag_page_slot(inode, mtr);
  2161. if (n == ULINT_UNDEFINED) {
  2162. /* Freeing completed: free the segment inode */
  2163. fsp_free_seg_inode(space, inode, mtr);
  2164. return(TRUE);
  2165. }
  2166. fseg_free_page_low(inode, space,
  2167. fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
  2168. return(FALSE);
  2169. }
  2170. /**************************************************************************
  2171. Frees part of a segment. Differs from fseg_free_step because this function
  2172. leaves the header page unfreed. */
  2173. ibool
  2174. fseg_free_step_not_header(
  2175. /*======================*/
  2176. /* out: TRUE if freeing completed, except the
  2177. header page */
  2178. fseg_header_t* header, /* in: segment header which must reside on
  2179. the first fragment page of the segment */
  2180. mtr_t* mtr) /* in: mtr */
  2181. {
  2182. ulint n;
  2183. ulint page;
  2184. xdes_t* descr;
  2185. fseg_inode_t* inode;
  2186. ulint space;
  2187. ulint page_no;
  2188. space = buf_frame_get_space_id(header);
  2189. ut_ad(!mutex_own(&kernel_mutex)
  2190.       || mtr_memo_contains(mtr, fil_space_get_latch(space),
  2191. MTR_MEMO_X_LOCK));
  2192. mtr_x_lock(fil_space_get_latch(space), mtr);
  2193. inode = fseg_inode_get(header, mtr);
  2194. descr = fseg_get_first_extent(inode, mtr);
  2195. if (descr != NULL) {
  2196. /* Free the extent held by the segment */
  2197. page = xdes_get_offset(descr);
  2198. fseg_free_extent(inode, space, page, mtr);
  2199. return(FALSE);
  2200. }
  2201. /* Free a frag page */
  2202. n = fseg_find_last_used_frag_page_slot(inode, mtr);
  2203. if (n == ULINT_UNDEFINED) {
  2204. ut_error;
  2205. }
  2206. page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
  2207. if (page_no == buf_frame_get_page_no(header)) {
  2208. return(TRUE);
  2209. }
  2210. fseg_free_page_low(inode, space, page_no, mtr);
  2211. return(FALSE);
  2212. }
  2213. /***********************************************************************
  2214. Frees a segment. The freeing is performed in several mini-transactions,
  2215. so that there is no danger of bufferfixing too many buffer pages. */
  2216. void
  2217. fseg_free(
  2218. /*======*/
  2219. ulint space, /* in: space id */
  2220. ulint page_no,/* in: page number where the segment header is
  2221. placed */
  2222. ulint offset) /* in: byte offset of the segment header on that
  2223. page */
  2224. {
  2225. mtr_t mtr;
  2226. ibool finished;
  2227. fseg_header_t* header;
  2228. fil_addr_t addr;
  2229. addr.page = page_no;
  2230. addr.boffset = offset;
  2231. for (;;) {
  2232. mtr_start(&mtr);
  2233. header = fut_get_ptr(space, addr, RW_X_LATCH, &mtr);
  2234. finished = fseg_free_step(header, &mtr);
  2235. mtr_commit(&mtr);
  2236. if (finished) {
  2237. return;
  2238. }
  2239. }
  2240. }
  2241. /**************************************************************************
  2242. Returns the first extent descriptor for a segment. We think of the extent
  2243. lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
  2244. -> FSEG_FREE. */
  2245. static
  2246. xdes_t*
  2247. fseg_get_first_extent(
  2248. /*==================*/
  2249. /* out: the first extent descriptor, or NULL if
  2250. none */
  2251. fseg_inode_t* inode, /* in: segment inode */
  2252. mtr_t* mtr) /* in: mtr */
  2253. {
  2254. fil_addr_t first;
  2255. ulint space;
  2256. xdes_t* descr;
  2257. ut_ad(inode && mtr);
  2258. space = buf_frame_get_space_id(inode);
  2259. first = fil_addr_null;
  2260. if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
  2261. first = flst_get_first(inode + FSEG_FULL, mtr);
  2262. } else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
  2263. first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
  2264. } else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
  2265. first = flst_get_first(inode + FSEG_FREE, mtr);
  2266. }
  2267. if (first.page == FIL_NULL) {
  2268. return(NULL);
  2269. }
  2270. descr = xdes_lst_get_descriptor(space, first, mtr);
  2271. return(descr);
  2272. }
  2273. /***********************************************************************
  2274. Validates a segment. */
  2275. static
  2276. ibool
  2277. fseg_validate_low(
  2278. /*==============*/
  2279. /* out: TRUE if ok */
  2280. fseg_inode_t* inode, /* in: segment inode */
  2281. mtr_t* mtr2) /* in: mtr */
  2282. {
  2283. ulint space;
  2284. dulint seg_id;
  2285. mtr_t mtr;
  2286. xdes_t* descr;
  2287. fil_addr_t node_addr;
  2288. ulint n_used = 0;
  2289. ulint n_used2 = 0;
  2290. ut_ad(mtr_memo_contains(mtr2, buf_block_align(inode),
  2291. MTR_MEMO_PAGE_X_FIX));
  2292. ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
  2293. space = buf_frame_get_space_id(inode);
  2294. seg_id = mtr_read_dulint(inode + FSEG_ID, MLOG_8BYTES, mtr2); 
  2295. n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
  2296. MLOG_4BYTES, mtr2); 
  2297. flst_validate(inode + FSEG_FREE, mtr2);
  2298. flst_validate(inode + FSEG_NOT_FULL, mtr2);
  2299. flst_validate(inode + FSEG_FULL, mtr2);
  2300. /* Validate FSEG_FREE list */
  2301. node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
  2302. while (!fil_addr_is_null(node_addr)) {
  2303. mtr_start(&mtr);
  2304. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2305. descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
  2306. ut_a(xdes_get_n_used(descr, &mtr) == 0);
  2307. ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
  2308. ut_a(0 == ut_dulint_cmp(
  2309. mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES,
  2310. &mtr), seg_id));
  2311. node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
  2312. mtr_commit(&mtr);
  2313. }
  2314. /* Validate FSEG_NOT_FULL list */
  2315. node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
  2316. while (!fil_addr_is_null(node_addr)) {
  2317. mtr_start(&mtr);
  2318. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2319. descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
  2320. ut_a(xdes_get_n_used(descr, &mtr) > 0);
  2321. ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
  2322. ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
  2323. ut_a(0 == ut_dulint_cmp(
  2324. mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES,
  2325. &mtr), seg_id));
  2326. n_used2 += xdes_get_n_used(descr, &mtr);
  2327. node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
  2328. mtr_commit(&mtr);
  2329. }
  2330. /* Validate FSEG_FULL list */
  2331. node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
  2332. while (!fil_addr_is_null(node_addr)) {
  2333. mtr_start(&mtr);
  2334. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2335. descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
  2336. ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
  2337. ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
  2338. ut_a(0 == ut_dulint_cmp(
  2339. mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES,
  2340. &mtr), seg_id));
  2341. node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
  2342. mtr_commit(&mtr);
  2343. }
  2344. ut_a(n_used == n_used2);
  2345. return(TRUE);
  2346. }
  2347. /***********************************************************************
  2348. Validates a segment. */
  2349. ibool
  2350. fseg_validate(
  2351. /*==========*/
  2352. /* out: TRUE if ok */
  2353. fseg_header_t* header, /* in: segment header */
  2354. mtr_t* mtr2) /* in: mtr */
  2355. {
  2356. fseg_inode_t* inode;
  2357. ibool ret;
  2358. ulint space;
  2359. space = buf_frame_get_space_id(header);
  2360. mtr_x_lock(fil_space_get_latch(space), mtr2);
  2361. inode = fseg_inode_get(header, mtr2);
  2362. ret = fseg_validate_low(inode, mtr2);
  2363. return(ret);
  2364. }
  2365. /***********************************************************************
  2366. Writes info of a segment. */
  2367. static
  2368. void
  2369. fseg_print_low(
  2370. /*===========*/
  2371. fseg_inode_t* inode, /* in: segment inode */
  2372. mtr_t* mtr) /* in: mtr */
  2373. {
  2374. ulint space;
  2375. ulint seg_id_low;
  2376. ulint seg_id_high;
  2377. ulint n_used;
  2378. ulint n_frag;
  2379. ulint n_free;
  2380. ulint n_not_full;
  2381. ulint n_full;
  2382. ulint reserved;
  2383. ulint used;
  2384. ulint page_no;
  2385. dulint   d_var;
  2386. ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
  2387. MTR_MEMO_PAGE_X_FIX));
  2388. space = buf_frame_get_space_id(inode);
  2389. page_no = buf_frame_get_page_no(inode);
  2390. reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
  2391. d_var = mtr_read_dulint(inode + FSEG_ID, MLOG_8BYTES, mtr);
  2392. seg_id_low = ut_dulint_get_low(d_var);
  2393. seg_id_high = ut_dulint_get_high(d_var);
  2394. n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
  2395. MLOG_4BYTES, mtr); 
  2396. n_frag = fseg_get_n_frag_pages(inode, mtr);
  2397. n_free = flst_get_len(inode + FSEG_FREE, mtr);
  2398. n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
  2399. n_full = flst_get_len(inode + FSEG_FULL, mtr);
  2400. printf(
  2401.     "SEGMENT id %lu %lu space %lu; page %lu; res %lu used %lu; full ext %lun",
  2402. seg_id_high, seg_id_low, space, page_no, reserved, used,
  2403. n_full);
  2404. printf(
  2405.     "fragm pages %lu; free extents %lu; not full extents %lu: pages %lun",
  2406. n_frag, n_free, n_not_full, n_used);
  2407. }
  2408. /***********************************************************************
  2409. Writes info of a segment. */
  2410. void
  2411. fseg_print(
  2412. /*=======*/
  2413. fseg_header_t* header, /* in: segment header */
  2414. mtr_t* mtr) /* in: mtr */
  2415. {
  2416. fseg_inode_t* inode;
  2417. ulint space;
  2418. space = buf_frame_get_space_id(header);
  2419. mtr_x_lock(fil_space_get_latch(space), mtr);
  2420. inode = fseg_inode_get(header, mtr);
  2421. fseg_print_low(inode, mtr);
  2422. }
  2423. /***********************************************************************
  2424. Validates the file space system and its segments. */
  2425. ibool
  2426. fsp_validate(
  2427. /*=========*/
  2428. /* out: TRUE if ok */
  2429. ulint space) /* in: space id */
  2430. {
  2431. fsp_header_t* header;
  2432. fseg_inode_t* seg_inode;
  2433. page_t* seg_inode_page;
  2434. ulint size;
  2435. ulint free_limit;
  2436. ulint frag_n_used;
  2437. mtr_t mtr;
  2438. mtr_t mtr2;
  2439. xdes_t* descr;
  2440. fil_addr_t node_addr;
  2441. fil_addr_t next_node_addr;
  2442. ulint descr_count = 0;
  2443. ulint n_used = 0;
  2444. ulint n_used2 = 0;
  2445. ulint n_full_frag_pages;
  2446. ulint n;
  2447. ulint seg_inode_len_free;
  2448. ulint seg_inode_len_full;
  2449. /* Start first a mini-transaction mtr2 to lock out all other threads
  2450. from the fsp system */
  2451. mtr_start(&mtr2);
  2452. mtr_x_lock(fil_space_get_latch(space), &mtr2);
  2453. mtr_start(&mtr);
  2454. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2455. header = fsp_get_space_header(space, &mtr);
  2456. size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr); 
  2457. free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
  2458. MLOG_4BYTES, &mtr); 
  2459. frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
  2460. MLOG_4BYTES, &mtr); 
  2461. n_full_frag_pages = FSP_EXTENT_SIZE *
  2462. flst_get_len(header + FSP_FULL_FRAG, &mtr);
  2463. ut_a(free_limit <= size);
  2464. flst_validate(header + FSP_FREE, &mtr);
  2465. flst_validate(header + FSP_FREE_FRAG, &mtr);
  2466. flst_validate(header + FSP_FULL_FRAG, &mtr);
  2467. mtr_commit(&mtr);
  2468. /* Validate FSP_FREE list */
  2469. mtr_start(&mtr);
  2470. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2471. header = fsp_get_space_header(space, &mtr);
  2472. node_addr = flst_get_first(header + FSP_FREE, &mtr);
  2473. mtr_commit(&mtr);
  2474. while (!fil_addr_is_null(node_addr)) {
  2475. mtr_start(&mtr);
  2476. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2477. descr_count++;
  2478. descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
  2479. ut_a(xdes_get_n_used(descr, &mtr) == 0);
  2480. ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
  2481. node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
  2482. mtr_commit(&mtr);
  2483. }
  2484. /* Validate FSP_FREE_FRAG list */
  2485. mtr_start(&mtr);
  2486. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2487. header = fsp_get_space_header(space, &mtr);
  2488. node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
  2489. mtr_commit(&mtr);
  2490. while (!fil_addr_is_null(node_addr)) {
  2491. mtr_start(&mtr);
  2492. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2493. descr_count++;
  2494. descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
  2495. ut_a(xdes_get_n_used(descr, &mtr) > 0);
  2496. ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
  2497. ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
  2498. n_used += xdes_get_n_used(descr, &mtr);
  2499. node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
  2500. mtr_commit(&mtr);
  2501. }
  2502. /* Validate FSP_FULL_FRAG list */
  2503. mtr_start(&mtr);
  2504. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2505. header = fsp_get_space_header(space, &mtr);
  2506. node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
  2507. mtr_commit(&mtr);
  2508. while (!fil_addr_is_null(node_addr)) {
  2509. mtr_start(&mtr);
  2510. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2511. descr_count++;
  2512. descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
  2513. ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
  2514. ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
  2515. node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
  2516. mtr_commit(&mtr);
  2517. }
  2518. /* Validate segments */
  2519. mtr_start(&mtr);
  2520. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2521. header = fsp_get_space_header(space, &mtr);
  2522. node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
  2523. seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
  2524. mtr_commit(&mtr);
  2525. while (!fil_addr_is_null(node_addr)) {
  2526.     for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
  2527. mtr_start(&mtr);
  2528. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2529. seg_inode_page = fut_get_ptr(space, node_addr, RW_X_LATCH,
  2530. &mtr) - FSEG_INODE_PAGE_NODE;
  2531. seg_inode = fsp_seg_inode_page_get_nth_inode(seg_inode_page,
  2532. n, &mtr);
  2533. ut_a(ut_dulint_cmp(mach_read_from_8(seg_inode + FSEG_ID),
  2534. ut_dulint_zero) != 0);
  2535. fseg_validate_low(seg_inode, &mtr);
  2536. descr_count += flst_get_len(seg_inode + FSEG_FREE, &mtr);
  2537. descr_count += flst_get_len(seg_inode + FSEG_FULL, &mtr);
  2538. descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL, &mtr);
  2539. n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
  2540.      next_node_addr = flst_get_next_addr(seg_inode_page
  2541. + FSEG_INODE_PAGE_NODE, &mtr);
  2542. mtr_commit(&mtr);
  2543.     }
  2544.     node_addr = next_node_addr;
  2545. }
  2546. mtr_start(&mtr);
  2547. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2548. header = fsp_get_space_header(space, &mtr);
  2549. node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
  2550. seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
  2551. mtr_commit(&mtr);
  2552. while (!fil_addr_is_null(node_addr)) {
  2553.     for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
  2554. mtr_start(&mtr);
  2555. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2556. seg_inode_page = fut_get_ptr(space, node_addr, RW_X_LATCH,
  2557. &mtr) - FSEG_INODE_PAGE_NODE;
  2558. seg_inode = fsp_seg_inode_page_get_nth_inode(seg_inode_page,
  2559. n, &mtr);
  2560. if (ut_dulint_cmp(mach_read_from_8(seg_inode + FSEG_ID),
  2561. ut_dulint_zero) != 0) {
  2562. fseg_validate_low(seg_inode, &mtr);
  2563. descr_count += flst_get_len(seg_inode + FSEG_FREE,
  2564. &mtr);
  2565. descr_count += flst_get_len(seg_inode + FSEG_FULL,
  2566. &mtr);
  2567. descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
  2568. &mtr);
  2569. n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
  2570. }
  2571.      next_node_addr = flst_get_next_addr(seg_inode_page
  2572. + FSEG_INODE_PAGE_NODE, &mtr);
  2573. mtr_commit(&mtr);
  2574.     }
  2575.     node_addr = next_node_addr;
  2576. }
  2577. ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
  2578. ut_a(n_used + n_full_frag_pages
  2579. == n_used2 + (free_limit + XDES_DESCRIBED_PER_PAGE - 1)
  2580.  / XDES_DESCRIBED_PER_PAGE
  2581.    + seg_inode_len_full + seg_inode_len_free);
  2582. ut_a(frag_n_used == n_used);
  2583. mtr_commit(&mtr2);
  2584. return(TRUE);
  2585. }
  2586. /***********************************************************************
  2587. Prints info of a file space. */
  2588. void
  2589. fsp_print(
  2590. /*======*/
  2591. ulint space) /* in: space id */
  2592. {
  2593. fsp_header_t* header;
  2594. fseg_inode_t* seg_inode;
  2595. page_t* seg_inode_page;
  2596. ulint size;
  2597. ulint free_limit;
  2598. ulint frag_n_used;
  2599. fil_addr_t node_addr;
  2600. fil_addr_t next_node_addr;
  2601. ulint n_free;
  2602. ulint n_free_frag;
  2603. ulint n_full_frag;
  2604. ulint seg_id_low;
  2605. ulint seg_id_high;
  2606. ulint n;
  2607. ulint n_segs = 0;
  2608. dulint          d_var;
  2609. mtr_t mtr;
  2610. mtr_t mtr2;
  2611. /* Start first a mini-transaction mtr2 to lock out all other threads
  2612. from the fsp system */
  2613. mtr_start(&mtr2);
  2614. mtr_x_lock(fil_space_get_latch(space), &mtr2);
  2615. mtr_start(&mtr);
  2616. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2617. header = fsp_get_space_header(space, &mtr);
  2618. size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr); 
  2619. free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
  2620. &mtr); 
  2621. frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
  2622. &mtr);
  2623. n_free = flst_get_len(header + FSP_FREE, &mtr);
  2624. n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
  2625. n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
  2626. d_var = mtr_read_dulint(header + FSP_SEG_ID, MLOG_8BYTES, &mtr);
  2627. seg_id_low = ut_dulint_get_low(d_var);
  2628. seg_id_high = ut_dulint_get_high(d_var);
  2629. printf("FILE SPACE INFO: id %lun", space);
  2630. printf("size %lu, free limit %lu, free extents %lun",
  2631. size, free_limit, n_free);
  2632. printf(
  2633. "not full frag extents %lu: used pages %lu, full frag extents %lun",
  2634. n_free_frag, frag_n_used, n_full_frag);
  2635. printf("first seg id not used %lu %lun", seg_id_high, seg_id_low);
  2636. mtr_commit(&mtr);
  2637. /* Print segments */
  2638. mtr_start(&mtr);
  2639. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2640. header = fsp_get_space_header(space, &mtr);
  2641. node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
  2642. mtr_commit(&mtr);
  2643. while (!fil_addr_is_null(node_addr)) {
  2644.     for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
  2645. mtr_start(&mtr);
  2646. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2647. seg_inode_page = fut_get_ptr(space, node_addr, RW_X_LATCH,
  2648. &mtr) - FSEG_INODE_PAGE_NODE;
  2649. seg_inode = fsp_seg_inode_page_get_nth_inode(seg_inode_page,
  2650. n, &mtr);
  2651. ut_a(ut_dulint_cmp(mach_read_from_8(seg_inode + FSEG_ID),
  2652. ut_dulint_zero) != 0);
  2653. fseg_print_low(seg_inode, &mtr);
  2654. n_segs++;
  2655.      next_node_addr = flst_get_next_addr(seg_inode_page
  2656. + FSEG_INODE_PAGE_NODE, &mtr);
  2657. mtr_commit(&mtr);
  2658.     }
  2659.     node_addr = next_node_addr;
  2660. }
  2661. mtr_start(&mtr);
  2662. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2663. header = fsp_get_space_header(space, &mtr);
  2664. node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
  2665. mtr_commit(&mtr);
  2666. while (!fil_addr_is_null(node_addr)) {
  2667.     for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
  2668. mtr_start(&mtr);
  2669. mtr_x_lock(fil_space_get_latch(space), &mtr);
  2670. seg_inode_page = fut_get_ptr(space, node_addr, RW_X_LATCH,
  2671. &mtr) - FSEG_INODE_PAGE_NODE;
  2672. seg_inode = fsp_seg_inode_page_get_nth_inode(seg_inode_page,
  2673. n, &mtr);
  2674. if (ut_dulint_cmp(mach_read_from_8(seg_inode + FSEG_ID),
  2675. ut_dulint_zero) != 0) {
  2676. fseg_print_low(seg_inode, &mtr);
  2677. n_segs++;
  2678. }
  2679.      next_node_addr = flst_get_next_addr(seg_inode_page
  2680. + FSEG_INODE_PAGE_NODE, &mtr);
  2681. mtr_commit(&mtr);
  2682.     }
  2683.     node_addr = next_node_addr;
  2684. }
  2685. mtr_commit(&mtr2);
  2686. printf("NUMBER of file segments: %lun", n_segs);
  2687. }