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

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