Drizzled Public API Documentation

fsp0fsp.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /******************************************************************/
00026 #include "fsp0fsp.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "fsp0fsp.ic"
00030 #endif
00031 
00032 #include "buf0buf.h"
00033 #include "fil0fil.h"
00034 #include "mtr0log.h"
00035 #include "ut0byte.h"
00036 #include "page0page.h"
00037 #include "page0zip.h"
00038 #ifdef UNIV_HOTBACKUP
00039 # include "fut0lst.h"
00040 #else /* UNIV_HOTBACKUP */
00041 # include "sync0sync.h"
00042 # include "fut0fut.h"
00043 # include "srv0srv.h"
00044 # include "ibuf0ibuf.h"
00045 # include "btr0btr.h"
00046 # include "btr0sea.h"
00047 # include "dict0boot.h"
00048 # include "log0log.h"
00049 #endif /* UNIV_HOTBACKUP */
00050 #include "dict0mem.h"
00051 
00052 
00053 #define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
00054             within a file page */
00055 
00056 /* The data structures in files are defined just as byte strings in C */
00057 typedef byte  fsp_header_t;
00058 typedef byte  xdes_t;
00059 
00060 /*      SPACE HEADER
00061       ============
00062 
00063 File space header data structure: this data structure is contained in the
00064 first page of a space. The space for this header is reserved in every extent
00065 descriptor page, but used only in the first. */
00066 
00067 /*-------------------------------------*/
00068 #define FSP_SPACE_ID    0 /* space id */
00069 #define FSP_NOT_USED    4 /* this field contained a value up to
00070           which we know that the modifications
00071           in the database have been flushed to
00072           the file space; not used now */
00073 #define FSP_SIZE    8 /* Current size of the space in
00074           pages */
00075 #define FSP_FREE_LIMIT    12  /* Minimum page number for which the
00076           free list has not been initialized:
00077           the pages >= this limit are, by
00078           definition, free; note that in a
00079           single-table tablespace where size
00080           < 64 pages, this number is 64, i.e.,
00081           we have initialized the space
00082           about the first extent, but have not
00083           physically allocted those pages to the
00084           file */
00085 #define FSP_SPACE_FLAGS   16  /* table->flags & ~DICT_TF_COMPACT */
00086 #define FSP_FRAG_N_USED   20  /* number of used pages in the
00087           FSP_FREE_FRAG list */
00088 #define FSP_FREE    24  /* list of free extents */
00089 #define FSP_FREE_FRAG   (24 + FLST_BASE_NODE_SIZE)
00090           /* list of partially free extents not
00091           belonging to any segment */
00092 #define FSP_FULL_FRAG   (24 + 2 * FLST_BASE_NODE_SIZE)
00093           /* list of full extents not belonging
00094           to any segment */
00095 #define FSP_SEG_ID    (24 + 3 * FLST_BASE_NODE_SIZE)
00096           /* 8 bytes which give the first unused
00097           segment id */
00098 #define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
00099           /* list of pages containing segment
00100           headers, where all the segment inode
00101           slots are reserved */
00102 #define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
00103           /* list of pages containing segment
00104           headers, where not all the segment
00105           header slots are reserved */
00106 /*-------------------------------------*/
00107 /* File space header size */
00108 #define FSP_HEADER_SIZE   (32 + 5 * FLST_BASE_NODE_SIZE)
00109 
00110 #define FSP_FREE_ADD    4 /* this many free extents are added
00111           to the free list from above
00112           FSP_FREE_LIMIT at a time */
00113 
00114 /*      FILE SEGMENT INODE
00115       ==================
00116 
00117 Segment inode which is created for each segment in a tablespace. NOTE: in
00118 purge we assume that a segment having only one currently used page can be
00119 freed in a few steps, so that the freeing cannot fill the file buffer with
00120 bufferfixed file pages. */
00121 
00122 typedef byte  fseg_inode_t;
00123 
00124 #define FSEG_INODE_PAGE_NODE  FSEG_PAGE_DATA
00125           /* the list node for linking
00126           segment inode pages */
00127 
00128 #define FSEG_ARR_OFFSET   (FSEG_PAGE_DATA + FLST_NODE_SIZE)
00129 /*-------------------------------------*/
00130 #define FSEG_ID     0 /* 8 bytes of segment id: if this is 0,
00131           it means that the header is unused */
00132 #define FSEG_NOT_FULL_N_USED  8
00133           /* number of used segment pages in
00134           the FSEG_NOT_FULL list */
00135 #define FSEG_FREE   12
00136           /* list of free extents of this
00137           segment */
00138 #define FSEG_NOT_FULL   (12 + FLST_BASE_NODE_SIZE)
00139           /* list of partially free extents */
00140 #define FSEG_FULL   (12 + 2 * FLST_BASE_NODE_SIZE)
00141           /* list of full extents */
00142 #define FSEG_MAGIC_N    (12 + 3 * FLST_BASE_NODE_SIZE)
00143           /* magic number used in debugging */
00144 #define FSEG_FRAG_ARR   (16 + 3 * FLST_BASE_NODE_SIZE)
00145           /* array of individual pages
00146           belonging to this segment in fsp
00147           fragment extent lists */
00148 #define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
00149           /* number of slots in the array for
00150           the fragment pages */
00151 #define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
00152           page number within space, FIL_NULL
00153           means that the slot is not in use */
00154 /*-------------------------------------*/
00155 #define FSEG_INODE_SIZE         \
00156   (16 + 3 * FLST_BASE_NODE_SIZE     \
00157    + FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
00158 
00159 #define FSP_SEG_INODES_PER_PAGE(zip_size)   \
00160   (((zip_size ? zip_size : UNIV_PAGE_SIZE)  \
00161     - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
00162         /* Number of segment inodes which fit on a
00163         single page */
00164 
00165 #define FSEG_MAGIC_N_VALUE  97937874
00166 
00167 #define FSEG_FILLFACTOR   8 /* If this value is x, then if
00168           the number of unused but reserved
00169           pages in a segment is less than
00170           reserved pages * 1/x, and there are
00171           at least FSEG_FRAG_LIMIT used pages,
00172           then we allow a new empty extent to
00173           be added to the segment in
00174           fseg_alloc_free_page. Otherwise, we
00175           use unused pages of the segment. */
00176 
00177 #define FSEG_FRAG_LIMIT   FSEG_FRAG_ARR_N_SLOTS
00178           /* If the segment has >= this many
00179           used pages, it may be expanded by
00180           allocating extents to the segment;
00181           until that only individual fragment
00182           pages are allocated from the space */
00183 
00184 #define FSEG_FREE_LIST_LIMIT  40  /* If the reserved size of a segment
00185           is at least this many extents, we
00186           allow extents to be put to the free
00187           list of the extent: at most
00188           FSEG_FREE_LIST_MAX_LEN many */
00189 #define FSEG_FREE_LIST_MAX_LEN  4
00190 
00191 
00192 /*      EXTENT DESCRIPTOR
00193       =================
00194 
00195 File extent descriptor data structure: contains bits to tell which pages in
00196 the extent are free and which contain old tuple version to clean. */
00197 
00198 /*-------------------------------------*/
00199 #define XDES_ID     0 /* The identifier of the segment
00200           to which this extent belongs */
00201 #define XDES_FLST_NODE    8 /* The list node data structure
00202           for the descriptors */
00203 #define XDES_STATE    (FLST_NODE_SIZE + 8)
00204           /* contains state information
00205           of the extent */
00206 #define XDES_BITMAP   (FLST_NODE_SIZE + 12)
00207           /* Descriptor bitmap of the pages
00208           in the extent */
00209 /*-------------------------------------*/
00210 
00211 #define XDES_BITS_PER_PAGE  2 /* How many bits are there per page */
00212 #define XDES_FREE_BIT   0 /* Index of the bit which tells if
00213           the page is free */
00214 #define XDES_CLEAN_BIT    1 /* NOTE: currently not used!
00215           Index of the bit which tells if
00216           there are old versions of tuples
00217           on the page */
00218 /* States of a descriptor */
00219 #define XDES_FREE   1 /* extent is in free list of space */
00220 #define XDES_FREE_FRAG    2 /* extent is in free fragment list of
00221           space */
00222 #define XDES_FULL_FRAG    3 /* extent is in full fragment list of
00223           space */
00224 #define XDES_FSEG   4 /* extent belongs to a segment */
00225 
00226 /* File extent data structure size in bytes. */
00227 #define XDES_SIZE             \
00228   (XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
00229 
00230 /* Offset of the descriptor array on a descriptor page */
00231 #define XDES_ARR_OFFSET   (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
00232 
00233 #ifndef UNIV_HOTBACKUP
00234 /* Flag to indicate if we have printed the tablespace full error. */
00235 static ibool fsp_tbs_full_error_printed = FALSE;
00236 
00237 /**********************************************************************/
00239 static
00240 void
00241 fsp_free_extent(
00242 /*============*/
00243   ulint   space,  
00244   ulint   zip_size,
00246   ulint   page, 
00247   mtr_t*    mtr); 
00248 /**********************************************************************/
00250 static
00251 void
00252 fseg_free_extent(
00253 /*=============*/
00254   fseg_inode_t* seg_inode, 
00255   ulint   space,  
00256   ulint   zip_size,
00258   ulint   page, 
00259   mtr_t*    mtr); 
00260 /**********************************************************************/
00264 static
00265 ulint
00266 fseg_n_reserved_pages_low(
00267 /*======================*/
00268   fseg_inode_t* header, 
00269   ulint*    used, 
00271   mtr_t*    mtr); 
00272 /********************************************************************/
00275 static
00276 void
00277 fseg_mark_page_used(
00278 /*================*/
00279   fseg_inode_t* seg_inode,
00280   ulint   space,  
00281   ulint   zip_size,
00283   ulint   page, 
00284   mtr_t*    mtr); 
00285 /**********************************************************************/
00290 static
00291 xdes_t*
00292 fseg_get_first_extent(
00293 /*==================*/
00294   fseg_inode_t* inode,  
00295   ulint   space,  
00296   ulint   zip_size,
00298   mtr_t*    mtr); 
00299 /**********************************************************************/
00304 static
00305 void
00306 fsp_fill_free_list(
00307 /*===============*/
00308   ibool   init_space, 
00313   ulint   space,    
00314   fsp_header_t* header,   
00315   mtr_t*    mtr);   
00316 /**********************************************************************/
00321 static
00322 ulint
00323 fseg_alloc_free_page_low(
00324 /*=====================*/
00325   ulint   space,  
00326   ulint   zip_size,
00328   fseg_inode_t* seg_inode, 
00329   ulint   hint, 
00330   byte    direction, 
00335   mtr_t*    mtr); 
00336 #endif /* !UNIV_HOTBACKUP */
00337 
00338 /**********************************************************************/
00341 UNIV_INTERN
00342 ulint
00343 fsp_get_size_low(
00344 /*=============*/
00345   page_t* page) 
00346 {
00347   return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
00348 }
00349 
00350 #ifndef UNIV_HOTBACKUP
00351 /**********************************************************************/
00354 UNIV_INLINE
00355 fsp_header_t*
00356 fsp_get_space_header(
00357 /*=================*/
00358   ulint id, 
00359   ulint zip_size,
00361   mtr_t*  mtr)  
00362 {
00363   buf_block_t*  block;
00364   fsp_header_t* header;
00365 
00366   ut_ad(ut_is_2pow(zip_size));
00367   ut_ad(zip_size <= UNIV_PAGE_SIZE);
00368   ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
00369   ut_ad(id || !zip_size);
00370 
00371   block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
00372   header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
00373   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00374 
00375   ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
00376   ut_ad(zip_size == dict_table_flags_to_zip_size(
00377           mach_read_from_4(FSP_SPACE_FLAGS + header)));
00378   return(header);
00379 }
00380 
00381 /**********************************************************************/
00384 UNIV_INLINE
00385 ibool
00386 xdes_get_bit(
00387 /*=========*/
00388   const xdes_t* descr,  
00389   ulint   bit,  
00390   ulint   offset, 
00392   mtr_t*    mtr)  
00393 {
00394   ulint index;
00395   ulint byte_index;
00396   ulint bit_index;
00397 
00398   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00399   ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
00400   ut_ad(offset < FSP_EXTENT_SIZE);
00401 
00402   index = bit + XDES_BITS_PER_PAGE * offset;
00403 
00404   byte_index = index / 8;
00405   bit_index = index % 8;
00406 
00407   return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
00408                MLOG_1BYTE, mtr),
00409             bit_index));
00410 }
00411 
00412 /**********************************************************************/
00414 UNIV_INLINE
00415 void
00416 xdes_set_bit(
00417 /*=========*/
00418   xdes_t* descr,  
00419   ulint bit,  
00420   ulint offset, 
00422   ibool val,  
00423   mtr_t*  mtr)  
00424 {
00425   ulint index;
00426   ulint byte_index;
00427   ulint bit_index;
00428   ulint descr_byte;
00429 
00430   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00431   ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
00432   ut_ad(offset < FSP_EXTENT_SIZE);
00433 
00434   index = bit + XDES_BITS_PER_PAGE * offset;
00435 
00436   byte_index = index / 8;
00437   bit_index = index % 8;
00438 
00439   descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
00440             MLOG_1BYTE, mtr);
00441   descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
00442 
00443   mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
00444        MLOG_1BYTE, mtr);
00445 }
00446 
00447 /**********************************************************************/
00452 UNIV_INLINE
00453 ulint
00454 xdes_find_bit(
00455 /*==========*/
00456   xdes_t* descr,  
00457   ulint bit,  
00458   ibool val,  
00459   ulint hint, 
00460   mtr_t*  mtr)  
00461 {
00462   ulint i;
00463 
00464   ut_ad(descr && mtr);
00465   ut_ad(val <= TRUE);
00466   ut_ad(hint < FSP_EXTENT_SIZE);
00467   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00468   for (i = hint; i < FSP_EXTENT_SIZE; i++) {
00469     if (val == xdes_get_bit(descr, bit, i, mtr)) {
00470 
00471       return(i);
00472     }
00473   }
00474 
00475   for (i = 0; i < hint; i++) {
00476     if (val == xdes_get_bit(descr, bit, i, mtr)) {
00477 
00478       return(i);
00479     }
00480   }
00481 
00482   return(ULINT_UNDEFINED);
00483 }
00484 
00485 /**********************************************************************/
00489 UNIV_INLINE
00490 ulint
00491 xdes_find_bit_downward(
00492 /*===================*/
00493   xdes_t* descr,  
00494   ulint bit,  
00495   ibool val,  
00496   ulint hint, 
00497   mtr_t*  mtr)  
00498 {
00499   ulint i;
00500 
00501   ut_ad(descr && mtr);
00502   ut_ad(val <= TRUE);
00503   ut_ad(hint < FSP_EXTENT_SIZE);
00504   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00505   for (i = hint + 1; i > 0; i--) {
00506     if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
00507 
00508       return(i - 1);
00509     }
00510   }
00511 
00512   for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
00513     if (val == xdes_get_bit(descr, bit, i, mtr)) {
00514 
00515       return(i);
00516     }
00517   }
00518 
00519   return(ULINT_UNDEFINED);
00520 }
00521 
00522 /**********************************************************************/
00525 UNIV_INLINE
00526 ulint
00527 xdes_get_n_used(
00528 /*============*/
00529   const xdes_t* descr,  
00530   mtr_t*    mtr)  
00531 {
00532   ulint i;
00533   ulint count = 0;
00534 
00535   ut_ad(descr && mtr);
00536   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00537   for (i = 0; i < FSP_EXTENT_SIZE; i++) {
00538     if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
00539       count++;
00540     }
00541   }
00542 
00543   return(count);
00544 }
00545 
00546 /**********************************************************************/
00549 UNIV_INLINE
00550 ibool
00551 xdes_is_free(
00552 /*=========*/
00553   const xdes_t* descr,  
00554   mtr_t*    mtr)  
00555 {
00556   if (0 == xdes_get_n_used(descr, mtr)) {
00557 
00558     return(TRUE);
00559   }
00560 
00561   return(FALSE);
00562 }
00563 
00564 /**********************************************************************/
00567 UNIV_INLINE
00568 ibool
00569 xdes_is_full(
00570 /*=========*/
00571   const xdes_t* descr,  
00572   mtr_t*    mtr)  
00573 {
00574   if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
00575 
00576     return(TRUE);
00577   }
00578 
00579   return(FALSE);
00580 }
00581 
00582 /**********************************************************************/
00584 UNIV_INLINE
00585 void
00586 xdes_set_state(
00587 /*===========*/
00588   xdes_t* descr,  
00589   ulint state,  
00590   mtr_t*  mtr)  
00591 {
00592   ut_ad(descr && mtr);
00593   ut_ad(state >= XDES_FREE);
00594   ut_ad(state <= XDES_FSEG);
00595   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00596 
00597   mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
00598 }
00599 
00600 /**********************************************************************/
00603 UNIV_INLINE
00604 ulint
00605 xdes_get_state(
00606 /*===========*/
00607   const xdes_t* descr,  
00608   mtr_t*    mtr)  
00609 {
00610   ulint state;
00611 
00612   ut_ad(descr && mtr);
00613   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00614 
00615   state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
00616   ut_ad(state - 1 < XDES_FSEG);
00617   return(state);
00618 }
00619 
00620 /**********************************************************************/
00622 UNIV_INLINE
00623 void
00624 xdes_init(
00625 /*======*/
00626   xdes_t* descr,  
00627   mtr_t*  mtr)  
00628 {
00629   ulint i;
00630 
00631   ut_ad(descr && mtr);
00632   ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
00633   ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
00634 
00635   for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
00636     mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
00637   }
00638 
00639   xdes_set_state(descr, XDES_FREE, mtr);
00640 }
00641 
00642 /********************************************************************/
00645 UNIV_INLINE
00646 ulint
00647 xdes_calc_descriptor_page(
00648 /*======================*/
00649   ulint zip_size, 
00651   ulint offset)   
00652 {
00653   ut_a(UNIV_PAGE_SIZE >
00654        XDES_ARR_OFFSET + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE);
00655   ut_a(PAGE_ZIP_MIN_SIZE >
00656        XDES_ARR_OFFSET +
00657        (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE);
00658 
00659   ut_ad(ut_is_2pow(zip_size));
00660 
00661   if (!zip_size) {
00662     return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
00663   } else {
00664     ut_ad(zip_size > XDES_ARR_OFFSET
00665           + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
00666     return(ut_2pow_round(offset, zip_size));
00667   }
00668 }
00669 
00670 /********************************************************************/
00673 UNIV_INLINE
00674 ulint
00675 xdes_calc_descriptor_index(
00676 /*=======================*/
00677   ulint zip_size, 
00679   ulint offset)   
00680 {
00681   ut_ad(ut_is_2pow(zip_size));
00682 
00683   if (!zip_size) {
00684     return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
00685            / FSP_EXTENT_SIZE);
00686   } else {
00687     return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
00688   }
00689 }
00690 
00691 /********************************************************************/
00699 UNIV_INLINE
00700 xdes_t*
00701 xdes_get_descriptor_with_space_hdr(
00702 /*===============================*/
00703   fsp_header_t* sp_header,
00704   ulint   space,  
00705   ulint   offset, 
00709   mtr_t*    mtr)  
00710 {
00711   ulint limit;
00712   ulint size;
00713   ulint zip_size;
00714   ulint descr_page_no;
00715   page_t* descr_page;
00716 
00717   ut_ad(mtr);
00718   ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
00719         MTR_MEMO_X_LOCK));
00720   ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
00721         || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
00722   ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
00723   /* Read free limit and space size */
00724   limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
00725   size  = mach_read_from_4(sp_header + FSP_SIZE);
00726   zip_size = dict_table_flags_to_zip_size(
00727     mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
00728 
00729   /* If offset is >= size or > limit, return NULL */
00730 
00731   if ((offset >= size) || (offset > limit)) {
00732 
00733     return(NULL);
00734   }
00735 
00736   /* If offset is == limit, fill free list of the space. */
00737 
00738   if (offset == limit) {
00739     fsp_fill_free_list(FALSE, space, sp_header, mtr);
00740   }
00741 
00742   descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
00743 
00744   if (descr_page_no == 0) {
00745     /* It is on the space header page */
00746 
00747     descr_page = page_align(sp_header);
00748   } else {
00749     buf_block_t*  block;
00750 
00751     block = buf_page_get(space, zip_size, descr_page_no,
00752              RW_X_LATCH, mtr);
00753     buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00754 
00755     descr_page = buf_block_get_frame(block);
00756   }
00757 
00758   return(descr_page + XDES_ARR_OFFSET
00759          + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
00760 }
00761 
00762 /********************************************************************/
00771 static
00772 xdes_t*
00773 xdes_get_descriptor(
00774 /*================*/
00775   ulint space,  
00776   ulint zip_size,
00778   ulint offset, 
00780   mtr_t*  mtr)  
00781 {
00782   buf_block_t*  block;
00783   fsp_header_t* sp_header;
00784 
00785   block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
00786   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00787 
00788   sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
00789   return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
00790               mtr));
00791 }
00792 
00793 /********************************************************************/
00798 UNIV_INLINE
00799 xdes_t*
00800 xdes_lst_get_descriptor(
00801 /*====================*/
00802   ulint   space,  
00803   ulint   zip_size,
00805   fil_addr_t  lst_node,
00807   mtr_t*    mtr)  
00808 {
00809   xdes_t* descr;
00810 
00811   ut_ad(mtr);
00812   ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
00813         MTR_MEMO_X_LOCK));
00814   descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
00815     - XDES_FLST_NODE;
00816 
00817   return(descr);
00818 }
00819 
00820 /********************************************************************/
00823 UNIV_INLINE
00824 ulint
00825 xdes_get_offset(
00826 /*============*/
00827   xdes_t* descr)  
00828 {
00829   ut_ad(descr);
00830 
00831   return(page_get_page_no(page_align(descr))
00832          + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
00833          * FSP_EXTENT_SIZE);
00834 }
00835 #endif /* !UNIV_HOTBACKUP */
00836 
00837 /***********************************************************/
00839 static
00840 void
00841 fsp_init_file_page_low(
00842 /*===================*/
00843   buf_block_t*  block)  
00844 {
00845   page_t*   page  = buf_block_get_frame(block);
00846   page_zip_des_t* page_zip= buf_block_get_page_zip(block);
00847 
00848 #ifndef UNIV_HOTBACKUP
00849   block->check_index_page_at_flush = FALSE;
00850 #endif /* !UNIV_HOTBACKUP */
00851 
00852   if (UNIV_LIKELY_NULL(page_zip)) {
00853     memset(page, 0, UNIV_PAGE_SIZE);
00854     memset(page_zip->data, 0, page_zip_get_size(page_zip));
00855     mach_write_to_4(page + FIL_PAGE_OFFSET,
00856         buf_block_get_page_no(block));
00857     mach_write_to_4(page
00858         + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
00859         buf_block_get_space(block));
00860     memcpy(page_zip->data + FIL_PAGE_OFFSET,
00861            page + FIL_PAGE_OFFSET, 4);
00862     memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
00863            page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
00864     return;
00865   }
00866 
00867   memset(page, 0, UNIV_PAGE_SIZE);
00868   mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
00869   mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
00870       buf_block_get_space(block));
00871 }
00872 
00873 #ifndef UNIV_HOTBACKUP
00874 /***********************************************************/
00876 static
00877 void
00878 fsp_init_file_page(
00879 /*===============*/
00880   buf_block_t*  block,  
00881   mtr_t*    mtr)  
00882 {
00883   fsp_init_file_page_low(block);
00884 
00885   mlog_write_initial_log_record(buf_block_get_frame(block),
00886               MLOG_INIT_FILE_PAGE, mtr);
00887 }
00888 #endif /* !UNIV_HOTBACKUP */
00889 
00890 /***********************************************************/
00893 UNIV_INTERN
00894 byte*
00895 fsp_parse_init_file_page(
00896 /*=====================*/
00897   byte*   ptr,  
00898   byte*   /*end_ptr __attribute__((unused))*/, 
00899   buf_block_t*  block)  
00900 {
00901   ut_ad(ptr && end_ptr);
00902 
00903   if (block) {
00904     fsp_init_file_page_low(block);
00905   }
00906 
00907   return(ptr);
00908 }
00909 
00910 /**********************************************************************/
00912 UNIV_INTERN
00913 void
00914 fsp_init(void)
00915 /*==========*/
00916 {
00917   /* Does nothing at the moment */
00918 }
00919 
00920 /**********************************************************************/
00924 UNIV_INTERN
00925 void
00926 fsp_header_init_fields(
00927 /*===================*/
00928   page_t* page,   
00929   ulint space_id, 
00930   ulint flags)    
00932 {
00933   /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
00934   ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
00935   ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
00936   format, the tablespace flags should equal table->flags. */
00937   ut_a(flags != DICT_TF_COMPACT);
00938 
00939   mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
00940       space_id);
00941   mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
00942       flags);
00943 }
00944 
00945 #ifndef UNIV_HOTBACKUP
00946 /**********************************************************************/
00949 UNIV_INTERN
00950 void
00951 fsp_header_init(
00952 /*============*/
00953   ulint space,    
00954   ulint size,   
00955   mtr_t*  mtr)    
00956 {
00957   fsp_header_t* header;
00958   buf_block_t*  block;
00959   page_t*   page;
00960   ulint   flags;
00961   ulint   zip_size;
00962 
00963   ut_ad(mtr);
00964 
00965   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
00966 
00967   zip_size = dict_table_flags_to_zip_size(flags);
00968   block = buf_page_create(space, 0, zip_size, mtr);
00969   buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
00970   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00971 
00972   /* The prior contents of the file page should be ignored */
00973 
00974   fsp_init_file_page(block, mtr);
00975   page = buf_block_get_frame(block);
00976 
00977   mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
00978        MLOG_2BYTES, mtr);
00979 
00980   header = FSP_HEADER_OFFSET + page;
00981 
00982   mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
00983   mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
00984 
00985   mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
00986   mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
00987   mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
00988        MLOG_4BYTES, mtr);
00989   mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
00990 
00991   flst_init(header + FSP_FREE, mtr);
00992   flst_init(header + FSP_FREE_FRAG, mtr);
00993   flst_init(header + FSP_FULL_FRAG, mtr);
00994   flst_init(header + FSP_SEG_INODES_FULL, mtr);
00995   flst_init(header + FSP_SEG_INODES_FREE, mtr);
00996 
00997   mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
00998   if (space == 0) {
00999     fsp_fill_free_list(FALSE, space, header, mtr);
01000     btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
01001          0, 0, DICT_IBUF_ID_MIN + space,
01002          dict_ind_redundant, mtr);
01003   } else {
01004     fsp_fill_free_list(TRUE, space, header, mtr);
01005   }
01006 }
01007 #endif /* !UNIV_HOTBACKUP */
01008 
01009 /**********************************************************************/
01012 UNIV_INTERN
01013 ulint
01014 fsp_header_get_space_id(
01015 /*====================*/
01016   const page_t* page) 
01017 {
01018   ulint fsp_id;
01019   ulint id;
01020 
01021   fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
01022 
01023   id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
01024 
01025   if (id != fsp_id) {
01026     fprintf(stderr,
01027       "InnoDB: Error: space id in fsp header %lu,"
01028       " but in the page header %lu\n",
01029       (ulong) fsp_id, (ulong) id);
01030 
01031     return(ULINT_UNDEFINED);
01032   }
01033 
01034   return(id);
01035 }
01036 
01037 /**********************************************************************/
01040 UNIV_INTERN
01041 ulint
01042 fsp_header_get_flags(
01043 /*=================*/
01044   const page_t* page) 
01045 {
01046   ut_ad(!page_offset(page));
01047 
01048   return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
01049 }
01050 
01051 /**********************************************************************/
01054 UNIV_INTERN
01055 ulint
01056 fsp_header_get_zip_size(
01057 /*====================*/
01058   const page_t* page) 
01059 {
01060   ulint flags = fsp_header_get_flags(page);
01061 
01062   return(dict_table_flags_to_zip_size(flags));
01063 }
01064 
01065 #ifndef UNIV_HOTBACKUP
01066 /**********************************************************************/
01068 UNIV_INTERN
01069 void
01070 fsp_header_inc_size(
01071 /*================*/
01072   ulint space,  
01073   ulint size_inc,
01074   mtr_t*  mtr)  
01075 {
01076   fsp_header_t* header;
01077   ulint   size;
01078   ulint   flags;
01079 
01080   ut_ad(mtr);
01081 
01082   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
01083 
01084   header = fsp_get_space_header(space,
01085               dict_table_flags_to_zip_size(flags),
01086               mtr);
01087 
01088   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01089 
01090   mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
01091        mtr);
01092 }
01093 
01094 /**********************************************************************/
01100 UNIV_INTERN
01101 ulint
01102 fsp_header_get_free_limit(void)
01103 /*===========================*/
01104 {
01105   fsp_header_t* header;
01106   ulint   limit;
01107   mtr_t   mtr;
01108 
01109   mtr_start(&mtr);
01110 
01111   mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
01112 
01113   header = fsp_get_space_header(0, 0, &mtr);
01114 
01115   limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
01116 
01117   limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
01118 
01119   log_fsp_current_free_limit_set_and_checkpoint(limit);
01120 
01121   mtr_commit(&mtr);
01122 
01123   return(limit);
01124 }
01125 
01126 /**********************************************************************/
01132 UNIV_INTERN
01133 ulint
01134 fsp_header_get_tablespace_size(void)
01135 /*================================*/
01136 {
01137   fsp_header_t* header;
01138   ulint   size;
01139   mtr_t   mtr;
01140 
01141   mtr_start(&mtr);
01142 
01143   mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
01144 
01145   header = fsp_get_space_header(0, 0, &mtr);
01146 
01147   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
01148 
01149   mtr_commit(&mtr);
01150 
01151   return(size);
01152 }
01153 
01154 /***********************************************************************/
01158 static
01159 ibool
01160 fsp_try_extend_data_file_with_pages(
01161 /*================================*/
01162   ulint   space,    
01163   ulint   page_no,  
01164   fsp_header_t* header,   
01165   mtr_t*    mtr)    
01166 {
01167   ibool success;
01168   ulint actual_size;
01169   ulint size;
01170 
01171   ut_a(space != 0);
01172 
01173   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01174 
01175   ut_a(page_no >= size);
01176 
01177   success = fil_extend_space_to_desired_size(&actual_size, space,
01178                page_no + 1);
01179   /* actual_size now has the space size in pages; it may be less than
01180   we wanted if we ran out of disk space */
01181 
01182   mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
01183 
01184   return(success);
01185 }
01186 
01187 /***********************************************************************/
01190 static
01191 ibool
01192 fsp_try_extend_data_file(
01193 /*=====================*/
01194   ulint*    actual_increase,
01199   ulint   space,    
01200   fsp_header_t* header,   
01201   mtr_t*    mtr)    
01202 {
01203   ulint size;
01204   ulint zip_size;
01205   ulint new_size;
01206   ulint old_size;
01207   ulint size_increase;
01208   ulint actual_size;
01209   ibool success;
01210 
01211   *actual_increase = 0;
01212 
01213   if (space == 0 && !srv_auto_extend_last_data_file) {
01214 
01215     /* We print the error message only once to avoid
01216     spamming the error log. Note that we don't need
01217     to reset the flag to FALSE as dealing with this
01218     error requires server restart. */
01219     if (fsp_tbs_full_error_printed == FALSE) {
01220       fprintf(stderr,
01221         "InnoDB: Error: Data file(s) ran"
01222         " out of space.\n"
01223         "Please add another data file or"
01224         " use \'autoextend\' for the last"
01225         " data file.\n");
01226       fsp_tbs_full_error_printed = TRUE;
01227     }
01228     return(FALSE);
01229   }
01230 
01231   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01232   zip_size = dict_table_flags_to_zip_size(
01233     mach_read_from_4(header + FSP_SPACE_FLAGS));
01234 
01235   old_size = size;
01236 
01237   if (space == 0) {
01238     if (!srv_last_file_size_max) {
01239       size_increase = SRV_AUTO_EXTEND_INCREMENT;
01240     } else {
01241       if (srv_last_file_size_max
01242           < srv_data_file_sizes[srv_n_data_files - 1]) {
01243 
01244         fprintf(stderr,
01245           "InnoDB: Error: Last data file size"
01246           " is %lu, max size allowed %lu\n",
01247           (ulong) srv_data_file_sizes[
01248             srv_n_data_files - 1],
01249           (ulong) srv_last_file_size_max);
01250       }
01251 
01252       size_increase = srv_last_file_size_max
01253         - srv_data_file_sizes[srv_n_data_files - 1];
01254       if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
01255         size_increase = SRV_AUTO_EXTEND_INCREMENT;
01256       }
01257     }
01258   } else {
01259     /* We extend single-table tablespaces first one extent
01260     at a time, but for bigger tablespaces more. It is not
01261     enough to extend always by one extent, because some
01262     extents are frag page extents. */
01263     ulint extent_size;  
01265     if (!zip_size) {
01266       extent_size = FSP_EXTENT_SIZE;
01267     } else {
01268       extent_size = FSP_EXTENT_SIZE
01269         * UNIV_PAGE_SIZE / zip_size;
01270     }
01271 
01272     if (size < extent_size) {
01273       /* Let us first extend the file to extent_size */
01274       success = fsp_try_extend_data_file_with_pages(
01275         space, extent_size - 1, header, mtr);
01276       if (!success) {
01277         new_size = mtr_read_ulint(header + FSP_SIZE,
01278                 MLOG_4BYTES, mtr);
01279 
01280         *actual_increase = new_size - old_size;
01281 
01282         return(FALSE);
01283       }
01284 
01285       size = extent_size;
01286     }
01287 
01288     if (size < 32 * extent_size) {
01289       size_increase = extent_size;
01290     } else {
01291       /* Below in fsp_fill_free_list() we assume
01292       that we add at most FSP_FREE_ADD extents at
01293       a time */
01294       size_increase = FSP_FREE_ADD * extent_size;
01295     }
01296   }
01297 
01298   if (size_increase == 0) {
01299 
01300     return(TRUE);
01301   }
01302 
01303   success = fil_extend_space_to_desired_size(&actual_size, space,
01304                size + size_increase);
01305   /* We ignore any fragments of a full megabyte when storing the size
01306   to the space header */
01307 
01308   if (!zip_size) {
01309     new_size = ut_calc_align_down(actual_size,
01310                 (1024 * 1024) / UNIV_PAGE_SIZE);
01311   } else {
01312     new_size = ut_calc_align_down(actual_size,
01313                 (1024 * 1024) / zip_size);
01314   }
01315   mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
01316 
01317   *actual_increase = new_size - old_size;
01318 
01319   return(TRUE);
01320 }
01321 
01322 /**********************************************************************/
01326 static
01327 void
01328 fsp_fill_free_list(
01329 /*===============*/
01330   ibool   init_space, 
01335   ulint   space,    
01336   fsp_header_t* header,   
01337   mtr_t*    mtr)    
01338 {
01339   ulint limit;
01340   ulint size;
01341   ulint zip_size;
01342   xdes_t* descr;
01343   ulint count   = 0;
01344   ulint frag_n_used;
01345   ulint actual_increase;
01346   ulint i;
01347   mtr_t ibuf_mtr;
01348 
01349   ut_ad(header && mtr);
01350   ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
01351 
01352   /* Check if we can fill free list from above the free list limit */
01353   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01354   limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
01355 
01356   zip_size = dict_table_flags_to_zip_size(
01357     mach_read_from_4(FSP_SPACE_FLAGS + header));
01358   ut_a(ut_is_2pow(zip_size));
01359   ut_a(zip_size <= UNIV_PAGE_SIZE);
01360   ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
01361 
01362   if (space == 0 && srv_auto_extend_last_data_file
01363       && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
01364 
01365     /* Try to increase the last data file size */
01366     fsp_try_extend_data_file(&actual_increase, space, header, mtr);
01367     size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01368   }
01369 
01370   if (space != 0 && !init_space
01371       && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
01372 
01373     /* Try to increase the .ibd file size */
01374     fsp_try_extend_data_file(&actual_increase, space, header, mtr);
01375     size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01376   }
01377 
01378   i = limit;
01379 
01380   while ((init_space && i < 1)
01381          || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
01382 
01383     ibool init_xdes;
01384     if (zip_size) {
01385       init_xdes = ut_2pow_remainder(i, zip_size) == 0;
01386     } else {
01387       init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
01388     }
01389 
01390     mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
01391          MLOG_4BYTES, mtr);
01392 
01393     /* Update the free limit info in the log system and make
01394     a checkpoint */
01395     if (space == 0) {
01396       ut_a(!zip_size);
01397       log_fsp_current_free_limit_set_and_checkpoint(
01398         (i + FSP_EXTENT_SIZE)
01399         / ((1024 * 1024) / UNIV_PAGE_SIZE));
01400     }
01401 
01402     if (UNIV_UNLIKELY(init_xdes)) {
01403 
01404       buf_block_t*  block;
01405 
01406       /* We are going to initialize a new descriptor page
01407       and a new ibuf bitmap page: the prior contents of the
01408       pages should be ignored. */
01409 
01410       if (i > 0) {
01411         block = buf_page_create(
01412           space, i, zip_size, mtr);
01413         buf_page_get(space, zip_size, i,
01414                RW_X_LATCH, mtr);
01415         buf_block_dbg_add_level(block,
01416               SYNC_FSP_PAGE);
01417 
01418         fsp_init_file_page(block, mtr);
01419         mlog_write_ulint(buf_block_get_frame(block)
01420              + FIL_PAGE_TYPE,
01421              FIL_PAGE_TYPE_XDES,
01422              MLOG_2BYTES, mtr);
01423       }
01424 
01425       /* Initialize the ibuf bitmap page in a separate
01426       mini-transaction because it is low in the latching
01427       order, and we must be able to release its latch
01428       before returning from the fsp routine */
01429 
01430       mtr_start(&ibuf_mtr);
01431 
01432       block = buf_page_create(space,
01433                 i + FSP_IBUF_BITMAP_OFFSET,
01434                 zip_size, &ibuf_mtr);
01435       buf_page_get(space, zip_size,
01436              i + FSP_IBUF_BITMAP_OFFSET,
01437              RW_X_LATCH, &ibuf_mtr);
01438       buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01439 
01440       fsp_init_file_page(block, &ibuf_mtr);
01441 
01442       ibuf_bitmap_page_init(block, &ibuf_mtr);
01443 
01444       mtr_commit(&ibuf_mtr);
01445     }
01446 
01447     descr = xdes_get_descriptor_with_space_hdr(header, space, i,
01448                  mtr);
01449     xdes_init(descr, mtr);
01450 
01451     if (UNIV_UNLIKELY(init_xdes)) {
01452 
01453       /* The first page in the extent is a descriptor page
01454       and the second is an ibuf bitmap page: mark them
01455       used */
01456 
01457       xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
01458       xdes_set_bit(descr, XDES_FREE_BIT,
01459              FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
01460       xdes_set_state(descr, XDES_FREE_FRAG, mtr);
01461 
01462       flst_add_last(header + FSP_FREE_FRAG,
01463               descr + XDES_FLST_NODE, mtr);
01464       frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
01465                  MLOG_4BYTES, mtr);
01466       mlog_write_ulint(header + FSP_FRAG_N_USED,
01467            frag_n_used + 2, MLOG_4BYTES, mtr);
01468     } else {
01469       flst_add_last(header + FSP_FREE,
01470               descr + XDES_FLST_NODE, mtr);
01471       count++;
01472     }
01473 
01474     i += FSP_EXTENT_SIZE;
01475   }
01476 }
01477 
01478 /**********************************************************************/
01481 static
01482 xdes_t*
01483 fsp_alloc_free_extent(
01484 /*==================*/
01485   ulint space,  
01486   ulint zip_size,
01488   ulint hint, 
01491   mtr_t*  mtr)  
01492 {
01493   fsp_header_t* header;
01494   fil_addr_t  first;
01495   xdes_t*   descr;
01496 
01497   ut_ad(mtr);
01498 
01499   header = fsp_get_space_header(space, zip_size, mtr);
01500 
01501   descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
01502 
01503   if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
01504     /* Ok, we can take this extent */
01505   } else {
01506     /* Take the first extent in the free list */
01507     first = flst_get_first(header + FSP_FREE, mtr);
01508 
01509     if (fil_addr_is_null(first)) {
01510       fsp_fill_free_list(FALSE, space, header, mtr);
01511 
01512       first = flst_get_first(header + FSP_FREE, mtr);
01513     }
01514 
01515     if (fil_addr_is_null(first)) {
01516 
01517       return(NULL); /* No free extents left */
01518     }
01519 
01520     descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
01521   }
01522 
01523   flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
01524 
01525   return(descr);
01526 }
01527 
01528 /**********************************************************************/
01531 static
01532 ulint
01533 fsp_alloc_free_page(
01534 /*================*/
01535   ulint space,  
01536   ulint zip_size,
01538   ulint hint, 
01539   mtr_t*  mtr)  
01540 {
01541   fsp_header_t* header;
01542   fil_addr_t  first;
01543   xdes_t*   descr;
01544   buf_block_t*  block;
01545   ulint   free;
01546   ulint   frag_n_used;
01547   ulint   page_no;
01548   ulint   space_size;
01549   ibool   success;
01550 
01551   ut_ad(mtr);
01552 
01553   header = fsp_get_space_header(space, zip_size, mtr);
01554 
01555   /* Get the hinted descriptor */
01556   descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
01557 
01558   if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
01559     /* Ok, we can take this extent */
01560   } else {
01561     /* Else take the first extent in free_frag list */
01562     first = flst_get_first(header + FSP_FREE_FRAG, mtr);
01563 
01564     if (fil_addr_is_null(first)) {
01565       /* There are no partially full fragments: allocate
01566       a free extent and add it to the FREE_FRAG list. NOTE
01567       that the allocation may have as a side-effect that an
01568       extent containing a descriptor page is added to the
01569       FREE_FRAG list. But we will allocate our page from the
01570       the free extent anyway. */
01571 
01572       descr = fsp_alloc_free_extent(space, zip_size,
01573                   hint, mtr);
01574 
01575       if (descr == NULL) {
01576         /* No free space left */
01577 
01578         return(FIL_NULL);
01579       }
01580 
01581       xdes_set_state(descr, XDES_FREE_FRAG, mtr);
01582       flst_add_last(header + FSP_FREE_FRAG,
01583               descr + XDES_FLST_NODE, mtr);
01584     } else {
01585       descr = xdes_lst_get_descriptor(space, zip_size,
01586               first, mtr);
01587     }
01588 
01589     /* Reset the hint */
01590     hint = 0;
01591   }
01592 
01593   /* Now we have in descr an extent with at least one free page. Look
01594   for a free page in the extent. */
01595 
01596   free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
01597            hint % FSP_EXTENT_SIZE, mtr);
01598   if (free == ULINT_UNDEFINED) {
01599 
01600     ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
01601     putc('\n', stderr);
01602 
01603     ut_error;
01604   }
01605 
01606   page_no = xdes_get_offset(descr) + free;
01607 
01608   space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01609 
01610   if (space_size <= page_no) {
01611     /* It must be that we are extending a single-table tablespace
01612     whose size is still < 64 pages */
01613 
01614     ut_a(space != 0);
01615     if (page_no >= FSP_EXTENT_SIZE) {
01616       fprintf(stderr,
01617         "InnoDB: Error: trying to extend a"
01618         " single-table tablespace %lu\n"
01619         "InnoDB: by single page(s) though the"
01620         " space size %lu. Page no %lu.\n",
01621         (ulong) space, (ulong) space_size,
01622         (ulong) page_no);
01623       return(FIL_NULL);
01624     }
01625     success = fsp_try_extend_data_file_with_pages(space, page_no,
01626                     header, mtr);
01627     if (!success) {
01628       /* No disk space left */
01629       return(FIL_NULL);
01630     }
01631   }
01632 
01633   xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
01634 
01635   /* Update the FRAG_N_USED field */
01636   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
01637              mtr);
01638   frag_n_used++;
01639   mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
01640        mtr);
01641   if (xdes_is_full(descr, mtr)) {
01642     /* The fragment is full: move it to another list */
01643     flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
01644           mtr);
01645     xdes_set_state(descr, XDES_FULL_FRAG, mtr);
01646 
01647     flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
01648             mtr);
01649     mlog_write_ulint(header + FSP_FRAG_N_USED,
01650          frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
01651          mtr);
01652   }
01653 
01654   /* Initialize the allocated page to the buffer pool, so that it can
01655   be obtained immediately with buf_page_get without need for a disk
01656   read. */
01657 
01658   buf_page_create(space, page_no, zip_size, mtr);
01659 
01660   block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
01661   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01662 
01663   /* Prior contents of the page should be ignored */
01664   fsp_init_file_page(block, mtr);
01665 
01666   return(page_no);
01667 }
01668 
01669 /**********************************************************************/
01671 static
01672 void
01673 fsp_free_page(
01674 /*==========*/
01675   ulint space,  
01676   ulint zip_size,
01678   ulint page, 
01679   mtr_t*  mtr)  
01680 {
01681   fsp_header_t* header;
01682   xdes_t*   descr;
01683   ulint   state;
01684   ulint   frag_n_used;
01685 
01686   ut_ad(mtr);
01687 
01688   /* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
01689 
01690   header = fsp_get_space_header(space, zip_size, mtr);
01691 
01692   descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
01693 
01694   state = xdes_get_state(descr, mtr);
01695 
01696   if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
01697     fprintf(stderr,
01698       "InnoDB: Error: File space extent descriptor"
01699       " of page %lu has state %lu\n",
01700       (ulong) page,
01701       (ulong) state);
01702     fputs("InnoDB: Dump of descriptor: ", stderr);
01703     ut_print_buf(stderr, ((byte*)descr) - 50, 200);
01704     putc('\n', stderr);
01705 
01706     if (state == XDES_FREE) {
01707       /* We put here some fault tolerance: if the page
01708       is already free, return without doing anything! */
01709 
01710       return;
01711     }
01712 
01713     ut_error;
01714   }
01715 
01716   if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
01717     fprintf(stderr,
01718       "InnoDB: Error: File space extent descriptor"
01719       " of page %lu says it is free\n"
01720       "InnoDB: Dump of descriptor: ", (ulong) page);
01721     ut_print_buf(stderr, ((byte*)descr) - 50, 200);
01722     putc('\n', stderr);
01723 
01724     /* We put here some fault tolerance: if the page
01725     is already free, return without doing anything! */
01726 
01727     return;
01728   }
01729 
01730   xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
01731   xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
01732 
01733   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
01734              mtr);
01735   if (state == XDES_FULL_FRAG) {
01736     /* The fragment was full: move it to another list */
01737     flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
01738           mtr);
01739     xdes_set_state(descr, XDES_FREE_FRAG, mtr);
01740     flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
01741             mtr);
01742     mlog_write_ulint(header + FSP_FRAG_N_USED,
01743          frag_n_used + FSP_EXTENT_SIZE - 1,
01744          MLOG_4BYTES, mtr);
01745   } else {
01746     ut_a(frag_n_used > 0);
01747     mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
01748          MLOG_4BYTES, mtr);
01749   }
01750 
01751   if (xdes_is_free(descr, mtr)) {
01752     /* The extent has become free: move it to another list */
01753     flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
01754           mtr);
01755     fsp_free_extent(space, zip_size, page, mtr);
01756   }
01757 }
01758 
01759 /**********************************************************************/
01761 static
01762 void
01763 fsp_free_extent(
01764 /*============*/
01765   ulint space,  
01766   ulint zip_size,
01768   ulint page, 
01769   mtr_t*  mtr)  
01770 {
01771   fsp_header_t* header;
01772   xdes_t*   descr;
01773 
01774   ut_ad(mtr);
01775 
01776   header = fsp_get_space_header(space, zip_size, mtr);
01777 
01778   descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
01779 
01780   if (xdes_get_state(descr, mtr) == XDES_FREE) {
01781 
01782     ut_print_buf(stderr, (byte*)descr - 500, 1000);
01783     putc('\n', stderr);
01784 
01785     ut_error;
01786   }
01787 
01788   xdes_init(descr, mtr);
01789 
01790   flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
01791 }
01792 
01793 /**********************************************************************/
01796 UNIV_INLINE
01797 fseg_inode_t*
01798 fsp_seg_inode_page_get_nth_inode(
01799 /*=============================*/
01800   page_t* page, 
01801   ulint i,  
01802   ulint /*zip_size __attribute__((unused))*/,
01804   mtr_t*  /*mtr __attribute__((unused))*/)
01806 {
01807   ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
01808   ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
01809 
01810   return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
01811 }
01812 
01813 /**********************************************************************/
01816 static
01817 ulint
01818 fsp_seg_inode_page_find_used(
01819 /*=========================*/
01820   page_t* page, 
01821   ulint zip_size,
01822   mtr_t*  mtr)  
01823 {
01824   ulint   i;
01825   fseg_inode_t* inode;
01826 
01827   for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
01828 
01829     inode = fsp_seg_inode_page_get_nth_inode(
01830       page, i, zip_size, mtr);
01831 
01832     if (mach_read_from_8(inode + FSEG_ID)) {
01833       /* This is used */
01834 
01835       ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
01836             == FSEG_MAGIC_N_VALUE);
01837       return(i);
01838     }
01839   }
01840 
01841   return(ULINT_UNDEFINED);
01842 }
01843 
01844 /**********************************************************************/
01847 static
01848 ulint
01849 fsp_seg_inode_page_find_free(
01850 /*=========================*/
01851   page_t* page, 
01852   ulint i,  
01853   ulint zip_size,
01854   mtr_t*  mtr)  
01855 {
01856   fseg_inode_t* inode;
01857 
01858   for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
01859 
01860     inode = fsp_seg_inode_page_get_nth_inode(
01861       page, i, zip_size, mtr);
01862 
01863     if (!mach_read_from_8(inode + FSEG_ID)) {
01864       /* This is unused */
01865 
01866       return(i);
01867     }
01868 
01869     ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
01870           == FSEG_MAGIC_N_VALUE);
01871   }
01872 
01873   return(ULINT_UNDEFINED);
01874 }
01875 
01876 /**********************************************************************/
01879 static
01880 ibool
01881 fsp_alloc_seg_inode_page(
01882 /*=====================*/
01883   fsp_header_t* space_header, 
01884   mtr_t*    mtr)    
01885 {
01886   fseg_inode_t* inode;
01887   buf_block_t*  block;
01888   page_t*   page;
01889   ulint   page_no;
01890   ulint   space;
01891   ulint   zip_size;
01892   ulint   i;
01893 
01894   ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
01895 
01896   space = page_get_space_id(page_align(space_header));
01897   zip_size = dict_table_flags_to_zip_size(
01898     mach_read_from_4(FSP_SPACE_FLAGS + space_header));
01899 
01900   page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
01901 
01902   if (page_no == FIL_NULL) {
01903 
01904     return(FALSE);
01905   }
01906 
01907   block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
01908   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01909 
01910   block->check_index_page_at_flush = FALSE;
01911 
01912   page = buf_block_get_frame(block);
01913 
01914   mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
01915        MLOG_2BYTES, mtr);
01916 
01917   for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
01918 
01919     inode = fsp_seg_inode_page_get_nth_inode(page, i,
01920                zip_size, mtr);
01921 
01922     mlog_write_ull(inode + FSEG_ID, 0, mtr);
01923   }
01924 
01925   flst_add_last(space_header + FSP_SEG_INODES_FREE,
01926           page + FSEG_INODE_PAGE_NODE, mtr);
01927   return(TRUE);
01928 }
01929 
01930 /**********************************************************************/
01933 static
01934 fseg_inode_t*
01935 fsp_alloc_seg_inode(
01936 /*================*/
01937   fsp_header_t* space_header, 
01938   mtr_t*    mtr)    
01939 {
01940   ulint   page_no;
01941   buf_block_t*  block;
01942   page_t*   page;
01943   fseg_inode_t* inode;
01944   ibool   success;
01945   ulint   zip_size;
01946   ulint   n;
01947 
01948   ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
01949 
01950   if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
01951     /* Allocate a new segment inode page */
01952 
01953     success = fsp_alloc_seg_inode_page(space_header, mtr);
01954 
01955     if (!success) {
01956 
01957       return(NULL);
01958     }
01959   }
01960 
01961   page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
01962 
01963   zip_size = dict_table_flags_to_zip_size(
01964     mach_read_from_4(FSP_SPACE_FLAGS + space_header));
01965   block = buf_page_get(page_get_space_id(page_align(space_header)),
01966            zip_size, page_no, RW_X_LATCH, mtr);
01967   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01968 
01969   page = buf_block_get_frame(block);
01970 
01971   n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
01972 
01973   ut_a(n != ULINT_UNDEFINED);
01974 
01975   inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
01976 
01977   if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
01978                   zip_size, mtr)) {
01979     /* There are no other unused headers left on the page: move it
01980     to another list */
01981 
01982     flst_remove(space_header + FSP_SEG_INODES_FREE,
01983           page + FSEG_INODE_PAGE_NODE, mtr);
01984 
01985     flst_add_last(space_header + FSP_SEG_INODES_FULL,
01986             page + FSEG_INODE_PAGE_NODE, mtr);
01987   }
01988 
01989   ut_ad(!mach_read_from_8(inode + FSEG_ID)
01990         || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
01991   return(inode);
01992 }
01993 
01994 /**********************************************************************/
01996 static
01997 void
01998 fsp_free_seg_inode(
01999 /*===============*/
02000   ulint   space,  
02001   ulint   zip_size,
02003   fseg_inode_t* inode,  
02004   mtr_t*    mtr)  
02005 {
02006   page_t*   page;
02007   fsp_header_t* space_header;
02008 
02009   page = page_align(inode);
02010 
02011   space_header = fsp_get_space_header(space, zip_size, mtr);
02012 
02013   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02014 
02015   if (ULINT_UNDEFINED
02016       == fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
02017 
02018     /* Move the page to another list */
02019 
02020     flst_remove(space_header + FSP_SEG_INODES_FULL,
02021           page + FSEG_INODE_PAGE_NODE, mtr);
02022 
02023     flst_add_last(space_header + FSP_SEG_INODES_FREE,
02024             page + FSEG_INODE_PAGE_NODE, mtr);
02025   }
02026 
02027   mlog_write_ull(inode + FSEG_ID, 0, mtr);
02028   mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
02029 
02030   if (ULINT_UNDEFINED
02031       == fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
02032 
02033     /* There are no other used headers left on the page: free it */
02034 
02035     flst_remove(space_header + FSP_SEG_INODES_FREE,
02036           page + FSEG_INODE_PAGE_NODE, mtr);
02037 
02038     fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
02039   }
02040 }
02041 
02042 /**********************************************************************/
02045 static
02046 fseg_inode_t*
02047 fseg_inode_try_get(
02048 /*===============*/
02049   fseg_header_t*  header, 
02050   ulint   space,  
02051   ulint   zip_size,
02053   mtr_t*    mtr)  
02054 {
02055   fil_addr_t  inode_addr;
02056   fseg_inode_t* inode;
02057 
02058   inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
02059   inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
02060   ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
02061 
02062   inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
02063 
02064   if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
02065 
02066     inode = NULL;
02067   } else {
02068     ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
02069           == FSEG_MAGIC_N_VALUE);
02070   }
02071 
02072   return(inode);
02073 }
02074 
02075 /**********************************************************************/
02078 static
02079 fseg_inode_t*
02080 fseg_inode_get(
02081 /*===========*/
02082   fseg_header_t*  header, 
02083   ulint   space,  
02084   ulint   zip_size,
02086   mtr_t*    mtr)  
02087 {
02088   fseg_inode_t* inode
02089     = fseg_inode_try_get(header, space, zip_size, mtr);
02090   ut_a(inode);
02091   return(inode);
02092 }
02093 
02094 /**********************************************************************/
02097 UNIV_INLINE
02098 ulint
02099 fseg_get_nth_frag_page_no(
02100 /*======================*/
02101   fseg_inode_t* inode,  
02102   ulint   n,  
02103   mtr_t*    /*mtr __attribute__((unused))*/) 
02104 {
02105   ut_ad(inode && mtr);
02106   ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
02107   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
02108   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02109   return(mach_read_from_4(inode + FSEG_FRAG_ARR
02110         + n * FSEG_FRAG_SLOT_SIZE));
02111 }
02112 
02113 /**********************************************************************/
02115 UNIV_INLINE
02116 void
02117 fseg_set_nth_frag_page_no(
02118 /*======================*/
02119   fseg_inode_t* inode,  
02120   ulint   n,  
02121   ulint   page_no,
02122   mtr_t*    mtr)  
02123 {
02124   ut_ad(inode && mtr);
02125   ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
02126   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
02127   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02128 
02129   mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
02130        page_no, MLOG_4BYTES, mtr);
02131 }
02132 
02133 /**********************************************************************/
02136 static
02137 ulint
02138 fseg_find_free_frag_page_slot(
02139 /*==========================*/
02140   fseg_inode_t* inode,  
02141   mtr_t*    mtr)  
02142 {
02143   ulint i;
02144   ulint page_no;
02145 
02146   ut_ad(inode && mtr);
02147 
02148   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02149     page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
02150 
02151     if (page_no == FIL_NULL) {
02152 
02153       return(i);
02154     }
02155   }
02156 
02157   return(ULINT_UNDEFINED);
02158 }
02159 
02160 /**********************************************************************/
02163 static
02164 ulint
02165 fseg_find_last_used_frag_page_slot(
02166 /*===============================*/
02167   fseg_inode_t* inode,  
02168   mtr_t*    mtr)  
02169 {
02170   ulint i;
02171   ulint page_no;
02172 
02173   ut_ad(inode && mtr);
02174 
02175   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02176     page_no = fseg_get_nth_frag_page_no(
02177       inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
02178 
02179     if (page_no != FIL_NULL) {
02180 
02181       return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
02182     }
02183   }
02184 
02185   return(ULINT_UNDEFINED);
02186 }
02187 
02188 /**********************************************************************/
02191 static
02192 ulint
02193 fseg_get_n_frag_pages(
02194 /*==================*/
02195   fseg_inode_t* inode,  
02196   mtr_t*    mtr)  
02197 {
02198   ulint i;
02199   ulint count = 0;
02200 
02201   ut_ad(inode && mtr);
02202 
02203   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02204     if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
02205       count++;
02206     }
02207   }
02208 
02209   return(count);
02210 }
02211 
02212 /**********************************************************************/
02216 UNIV_INTERN
02217 buf_block_t*
02218 fseg_create_general(
02219 /*================*/
02220   ulint space,  
02221   ulint page, 
02225   ulint byte_offset, 
02227   ibool has_done_reservation, 
02233   mtr_t*  mtr)  
02234 {
02235   ulint   flags;
02236   ulint   zip_size;
02237   fsp_header_t* space_header;
02238   fseg_inode_t* inode;
02239   ib_id_t   seg_id;
02240   buf_block_t*  block = 0; /* remove warning */
02241   fseg_header_t*  header  = 0; /* remove warning */
02242   rw_lock_t*  latch;
02243   ibool   success;
02244   ulint   n_reserved;
02245   ulint   i;
02246 
02247   ut_ad(mtr);
02248   ut_ad(byte_offset + FSEG_HEADER_SIZE
02249         <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
02250 
02251   latch = fil_space_get_latch(space, &flags);
02252   zip_size = dict_table_flags_to_zip_size(flags);
02253 
02254   if (page != 0) {
02255     block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
02256     header = byte_offset + buf_block_get_frame(block);
02257   }
02258 
02259   ut_ad(!mutex_own(&kernel_mutex)
02260         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02261 
02262   mtr_x_lock(latch, mtr);
02263 
02264   if (rw_lock_get_x_lock_count(latch) == 1) {
02265     /* This thread did not own the latch before this call: free
02266     excess pages from the insert buffer free list */
02267 
02268     if (space == IBUF_SPACE_ID) {
02269       ibuf_free_excess_pages();
02270     }
02271   }
02272 
02273   if (!has_done_reservation) {
02274     success = fsp_reserve_free_extents(&n_reserved, space, 2,
02275                FSP_NORMAL, mtr);
02276     if (!success) {
02277       return(NULL);
02278     }
02279   }
02280 
02281   space_header = fsp_get_space_header(space, zip_size, mtr);
02282 
02283   inode = fsp_alloc_seg_inode(space_header, mtr);
02284 
02285   if (inode == NULL) {
02286 
02287     goto funct_exit;
02288   }
02289 
02290   /* Read the next segment id from space header and increment the
02291   value in space header */
02292 
02293   seg_id = mach_read_from_8(space_header + FSP_SEG_ID);
02294 
02295   mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr);
02296 
02297   mlog_write_ull(inode + FSEG_ID, seg_id, mtr);
02298   mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
02299 
02300   flst_init(inode + FSEG_FREE, mtr);
02301   flst_init(inode + FSEG_NOT_FULL, mtr);
02302   flst_init(inode + FSEG_FULL, mtr);
02303 
02304   mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
02305        MLOG_4BYTES, mtr);
02306   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02307     fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
02308   }
02309 
02310   if (page == 0) {
02311     page = fseg_alloc_free_page_low(space, zip_size,
02312             inode, 0, FSP_UP, mtr);
02313 
02314     if (page == FIL_NULL) {
02315 
02316       fsp_free_seg_inode(space, zip_size, inode, mtr);
02317 
02318       goto funct_exit;
02319     }
02320 
02321     block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
02322     header = byte_offset + buf_block_get_frame(block);
02323     mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
02324          FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
02325   }
02326 
02327   mlog_write_ulint(header + FSEG_HDR_OFFSET,
02328        page_offset(inode), MLOG_2BYTES, mtr);
02329 
02330   mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
02331        page_get_page_no(page_align(inode)),
02332        MLOG_4BYTES, mtr);
02333 
02334   mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
02335 
02336 funct_exit:
02337   if (!has_done_reservation) {
02338 
02339     fil_space_release_free_extents(space, n_reserved);
02340   }
02341 
02342   return(block);
02343 }
02344 
02345 /**********************************************************************/
02349 UNIV_INTERN
02350 buf_block_t*
02351 fseg_create(
02352 /*========*/
02353   ulint space,  
02354   ulint page, 
02358   ulint byte_offset, 
02360   mtr_t*  mtr)  
02361 {
02362   return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
02363 }
02364 
02365 /**********************************************************************/
02369 static
02370 ulint
02371 fseg_n_reserved_pages_low(
02372 /*======================*/
02373   fseg_inode_t* inode,  
02374   ulint*    used, 
02376   mtr_t*    mtr)  
02377 {
02378   ulint ret;
02379 
02380   ut_ad(inode && used && mtr);
02381   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
02382 
02383   *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
02384     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
02385     + fseg_get_n_frag_pages(inode, mtr);
02386 
02387   ret = fseg_get_n_frag_pages(inode, mtr)
02388     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
02389     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
02390     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
02391 
02392   return(ret);
02393 }
02394 
02395 /**********************************************************************/
02399 UNIV_INTERN
02400 ulint
02401 fseg_n_reserved_pages(
02402 /*==================*/
02403   fseg_header_t*  header, 
02404   ulint*    used, 
02405   mtr_t*    mtr)  
02406 {
02407   ulint   ret;
02408   fseg_inode_t* inode;
02409   ulint   space;
02410   ulint   flags;
02411   ulint   zip_size;
02412   rw_lock_t*  latch;
02413 
02414   space = page_get_space_id(page_align(header));
02415   latch = fil_space_get_latch(space, &flags);
02416   zip_size = dict_table_flags_to_zip_size(flags);
02417 
02418   ut_ad(!mutex_own(&kernel_mutex)
02419         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02420 
02421   mtr_x_lock(latch, mtr);
02422 
02423   inode = fseg_inode_get(header, space, zip_size, mtr);
02424 
02425   ret = fseg_n_reserved_pages_low(inode, used, mtr);
02426 
02427   return(ret);
02428 }
02429 
02430 /*********************************************************************/
02435 static
02436 void
02437 fseg_fill_free_list(
02438 /*================*/
02439   fseg_inode_t* inode,  
02440   ulint   space,  
02441   ulint   zip_size,
02443   ulint   hint, 
02445   mtr_t*    mtr)  
02446 {
02447   xdes_t* descr;
02448   ulint i;
02449   ib_id_t seg_id;
02450   ulint reserved;
02451   ulint used;
02452 
02453   ut_ad(inode && mtr);
02454   ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
02455 
02456   reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
02457 
02458   if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
02459 
02460     /* The segment is too small to allow extents in free list */
02461 
02462     return;
02463   }
02464 
02465   if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
02466     /* Free list is not empty */
02467 
02468     return;
02469   }
02470 
02471   for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
02472     descr = xdes_get_descriptor(space, zip_size, hint, mtr);
02473 
02474     if ((descr == NULL)
02475         || (XDES_FREE != xdes_get_state(descr, mtr))) {
02476 
02477       /* We cannot allocate the desired extent: stop */
02478 
02479       return;
02480     }
02481 
02482     descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
02483 
02484     xdes_set_state(descr, XDES_FSEG, mtr);
02485 
02486     seg_id = mach_read_from_8(inode + FSEG_ID);
02487     ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
02488           == FSEG_MAGIC_N_VALUE);
02489     mlog_write_ull(descr + XDES_ID, seg_id, mtr);
02490 
02491     flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
02492     hint += FSP_EXTENT_SIZE;
02493   }
02494 }
02495 
02496 /*********************************************************************/
02502 static
02503 xdes_t*
02504 fseg_alloc_free_extent(
02505 /*===================*/
02506   fseg_inode_t* inode,  
02507   ulint   space,  
02508   ulint   zip_size,
02510   mtr_t*    mtr)  
02511 {
02512   xdes_t*   descr;
02513   ib_id_t   seg_id;
02514   fil_addr_t  first;
02515 
02516   ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
02517   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02518 
02519   if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
02520     /* Segment free list is not empty, allocate from it */
02521 
02522     first = flst_get_first(inode + FSEG_FREE, mtr);
02523 
02524     descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
02525   } else {
02526     /* Segment free list was empty, allocate from space */
02527     descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
02528 
02529     if (descr == NULL) {
02530 
02531       return(NULL);
02532     }
02533 
02534     seg_id = mach_read_from_8(inode + FSEG_ID);
02535 
02536     xdes_set_state(descr, XDES_FSEG, mtr);
02537     mlog_write_ull(descr + XDES_ID, seg_id, mtr);
02538     flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
02539 
02540     /* Try to fill the segment free list */
02541     fseg_fill_free_list(inode, space, zip_size,
02542             xdes_get_offset(descr) + FSP_EXTENT_SIZE,
02543             mtr);
02544   }
02545 
02546   return(descr);
02547 }
02548 
02549 /**********************************************************************/
02554 static
02555 ulint
02556 fseg_alloc_free_page_low(
02557 /*=====================*/
02558   ulint   space,  
02559   ulint   zip_size,
02561   fseg_inode_t* seg_inode, 
02562   ulint   hint, 
02563   byte    direction, 
02568   mtr_t*    mtr)  
02569 {
02570   fsp_header_t* space_header;
02571   ulint   space_size;
02572   ib_id_t   seg_id;
02573   ulint   used;
02574   ulint   reserved;
02575   xdes_t*   descr;    
02576   ulint   ret_page; 
02578   xdes_t*   ret_descr;  
02579   ibool   frag_page_allocated = FALSE;
02580   ibool   success;
02581   ulint   n;
02582 
02583   ut_ad(mtr);
02584   ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
02585   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
02586         == FSEG_MAGIC_N_VALUE);
02587   ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
02588   seg_id = mach_read_from_8(seg_inode + FSEG_ID);
02589 
02590   ut_ad(seg_id);
02591 
02592   reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
02593 
02594   space_header = fsp_get_space_header(space, zip_size, mtr);
02595 
02596   descr = xdes_get_descriptor_with_space_hdr(space_header, space,
02597                hint, mtr);
02598   if (descr == NULL) {
02599     /* Hint outside space or too high above free limit: reset
02600     hint */
02601     hint = 0;
02602     descr = xdes_get_descriptor(space, zip_size, hint, mtr);
02603   }
02604 
02605   /* In the big if-else below we look for ret_page and ret_descr */
02606   /*-------------------------------------------------------------*/
02607   if ((xdes_get_state(descr, mtr) == XDES_FSEG)
02608       && mach_read_from_8(descr + XDES_ID) == seg_id
02609       && (xdes_get_bit(descr, XDES_FREE_BIT,
02610            hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
02611 
02612     /* 1. We can take the hinted page
02613     =================================*/
02614     ret_descr = descr;
02615     ret_page = hint;
02616     /*-----------------------------------------------------------*/
02617   } else if ((xdes_get_state(descr, mtr) == XDES_FREE)
02618        && ((reserved - used) < reserved / FSEG_FILLFACTOR)
02619        && (used >= FSEG_FRAG_LIMIT)) {
02620 
02621     /* 2. We allocate the free extent from space and can take
02622     =========================================================
02623     the hinted page
02624     ===============*/
02625     ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
02626 
02627     ut_a(ret_descr == descr);
02628 
02629     xdes_set_state(ret_descr, XDES_FSEG, mtr);
02630     mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
02631     flst_add_last(seg_inode + FSEG_FREE,
02632             ret_descr + XDES_FLST_NODE, mtr);
02633 
02634     /* Try to fill the segment free list */
02635     fseg_fill_free_list(seg_inode, space, zip_size,
02636             hint + FSP_EXTENT_SIZE, mtr);
02637     ret_page = hint;
02638     /*-----------------------------------------------------------*/
02639   } else if ((direction != FSP_NO_DIR)
02640        && ((reserved - used) < reserved / FSEG_FILLFACTOR)
02641        && (used >= FSEG_FRAG_LIMIT)
02642        && (!!(ret_descr
02643         = fseg_alloc_free_extent(seg_inode,
02644                space, zip_size, mtr)))) {
02645 
02646     /* 3. We take any free extent (which was already assigned above
02647     ===============================================================
02648     in the if-condition to ret_descr) and take the lowest or
02649     ========================================================
02650     highest page in it, depending on the direction
02651     ==============================================*/
02652     ret_page = xdes_get_offset(ret_descr);
02653 
02654     if (direction == FSP_DOWN) {
02655       ret_page += FSP_EXTENT_SIZE - 1;
02656     }
02657     /*-----------------------------------------------------------*/
02658   } else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
02659        && mach_read_from_8(descr + XDES_ID) == seg_id
02660        && (!xdes_is_full(descr, mtr))) {
02661 
02662     /* 4. We can take the page from the same extent as the
02663     ======================================================
02664     hinted page (and the extent already belongs to the
02665     ==================================================
02666     segment)
02667     ========*/
02668     ret_descr = descr;
02669     ret_page = xdes_get_offset(ret_descr)
02670       + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
02671           hint % FSP_EXTENT_SIZE, mtr);
02672     /*-----------------------------------------------------------*/
02673   } else if (reserved - used > 0) {
02674     /* 5. We take any unused page from the segment
02675     ==============================================*/
02676     fil_addr_t  first;
02677 
02678     if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
02679       first = flst_get_first(seg_inode + FSEG_NOT_FULL,
02680                  mtr);
02681     } else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
02682       first = flst_get_first(seg_inode + FSEG_FREE, mtr);
02683     } else {
02684       ut_error;
02685       return(FIL_NULL);
02686     }
02687 
02688     ret_descr = xdes_lst_get_descriptor(space, zip_size,
02689                 first, mtr);
02690     ret_page = xdes_get_offset(ret_descr)
02691       + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
02692           0, mtr);
02693     /*-----------------------------------------------------------*/
02694   } else if (used < FSEG_FRAG_LIMIT) {
02695     /* 6. We allocate an individual page from the space
02696     ===================================================*/
02697     ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
02698     ret_descr = NULL;
02699 
02700     frag_page_allocated = TRUE;
02701 
02702     if (ret_page != FIL_NULL) {
02703       /* Put the page in the fragment page array of the
02704       segment */
02705       n = fseg_find_free_frag_page_slot(seg_inode, mtr);
02706       ut_a(n != FIL_NULL);
02707 
02708       fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
02709               mtr);
02710     }
02711     /*-----------------------------------------------------------*/
02712   } else {
02713     /* 7. We allocate a new extent and take its first page
02714     ======================================================*/
02715     ret_descr = fseg_alloc_free_extent(seg_inode,
02716                space, zip_size, mtr);
02717 
02718     if (ret_descr == NULL) {
02719       ret_page = FIL_NULL;
02720     } else {
02721       ret_page = xdes_get_offset(ret_descr);
02722     }
02723   }
02724 
02725   if (ret_page == FIL_NULL) {
02726     /* Page could not be allocated */
02727 
02728     return(FIL_NULL);
02729   }
02730 
02731   if (space != 0) {
02732     space_size = fil_space_get_size(space);
02733 
02734     if (space_size <= ret_page) {
02735       /* It must be that we are extending a single-table
02736       tablespace whose size is still < 64 pages */
02737 
02738       if (ret_page >= FSP_EXTENT_SIZE) {
02739         fprintf(stderr,
02740           "InnoDB: Error (2): trying to extend"
02741           " a single-table tablespace %lu\n"
02742           "InnoDB: by single page(s) though"
02743           " the space size %lu. Page no %lu.\n",
02744           (ulong) space, (ulong) space_size,
02745           (ulong) ret_page);
02746         return(FIL_NULL);
02747       }
02748 
02749       success = fsp_try_extend_data_file_with_pages(
02750         space, ret_page, space_header, mtr);
02751       if (!success) {
02752         /* No disk space left */
02753         return(FIL_NULL);
02754       }
02755     }
02756   }
02757 
02758   if (!frag_page_allocated) {
02759     /* Initialize the allocated page to buffer pool, so that it
02760     can be obtained immediately with buf_page_get without need
02761     for a disk read */
02762     buf_block_t*  block;
02763     ulint   page_zip_size = dict_table_flags_to_zip_size(
02764       mach_read_from_4(FSP_SPACE_FLAGS + space_header));
02765 
02766     block = buf_page_create(space, ret_page, page_zip_size, mtr);
02767     buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
02768 
02769     if (UNIV_UNLIKELY(block != buf_page_get(space, page_zip_size,
02770               ret_page, RW_X_LATCH,
02771               mtr))) {
02772       ut_error;
02773     }
02774 
02775     /* The prior contents of the page should be ignored */
02776     fsp_init_file_page(block, mtr);
02777 
02778     /* At this point we know the extent and the page offset.
02779     The extent is still in the appropriate list (FSEG_NOT_FULL
02780     or FSEG_FREE), and the page is not yet marked as used. */
02781 
02782     ut_ad(xdes_get_descriptor(space, page_zip_size, ret_page, mtr)
02783           == ret_descr);
02784     ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
02785            ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
02786 
02787     fseg_mark_page_used(seg_inode, space, page_zip_size, ret_page, mtr);
02788   }
02789 
02790   buf_reset_check_index_page_at_flush(space, ret_page);
02791 
02792   return(ret_page);
02793 }
02794 
02795 /**********************************************************************/
02800 UNIV_INTERN
02801 ulint
02802 fseg_alloc_free_page_general(
02803 /*=========================*/
02804   fseg_header_t*  seg_header,
02805   ulint   hint, 
02806   byte    direction,
02811   ibool   has_done_reservation, 
02816   mtr_t*    mtr)  
02817 {
02818   fseg_inode_t* inode;
02819   ulint   space;
02820   ulint   flags;
02821   ulint   zip_size;
02822   rw_lock_t*  latch;
02823   ibool   success;
02824   ulint   page_no;
02825   ulint   n_reserved;
02826 
02827   space = page_get_space_id(page_align(seg_header));
02828 
02829   latch = fil_space_get_latch(space, &flags);
02830 
02831   zip_size = dict_table_flags_to_zip_size(flags);
02832 
02833   ut_ad(!mutex_own(&kernel_mutex)
02834         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02835 
02836   mtr_x_lock(latch, mtr);
02837 
02838   if (rw_lock_get_x_lock_count(latch) == 1) {
02839     /* This thread did not own the latch before this call: free
02840     excess pages from the insert buffer free list */
02841 
02842     if (space == IBUF_SPACE_ID) {
02843       ibuf_free_excess_pages();
02844     }
02845   }
02846 
02847   inode = fseg_inode_get(seg_header, space, zip_size, mtr);
02848 
02849   if (!has_done_reservation) {
02850     success = fsp_reserve_free_extents(&n_reserved, space, 2,
02851                FSP_NORMAL, mtr);
02852     if (!success) {
02853       return(FIL_NULL);
02854     }
02855   }
02856 
02857   page_no = fseg_alloc_free_page_low(space, zip_size,
02858              inode, hint, direction, mtr);
02859   if (!has_done_reservation) {
02860     fil_space_release_free_extents(space, n_reserved);
02861   }
02862 
02863   return(page_no);
02864 }
02865 
02866 /**********************************************************************/
02871 UNIV_INTERN
02872 ulint
02873 fseg_alloc_free_page(
02874 /*=================*/
02875   fseg_header_t*  seg_header,
02876   ulint   hint, 
02877   byte    direction,
02882   mtr_t*    mtr)  
02883 {
02884   return(fseg_alloc_free_page_general(seg_header, hint, direction,
02885               FALSE, mtr));
02886 }
02887 
02888 /**********************************************************************/
02895 static
02896 ibool
02897 fsp_reserve_free_pages(
02898 /*===================*/
02899   ulint   space,    
02900   fsp_header_t* space_header, 
02902   ulint   size,   
02904   mtr_t*    mtr)    
02905 {
02906   xdes_t* descr;
02907   ulint n_used;
02908 
02909   ut_a(space != 0);
02910   ut_a(size < FSP_EXTENT_SIZE / 2);
02911 
02912   descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
02913                mtr);
02914   n_used = xdes_get_n_used(descr, mtr);
02915 
02916   ut_a(n_used <= size);
02917 
02918   if (size >= n_used + 2) {
02919 
02920     return(TRUE);
02921   }
02922 
02923   return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
02924                space_header, mtr));
02925 }
02926 
02927 /**********************************************************************/
02953 UNIV_INTERN
02954 ibool
02955 fsp_reserve_free_extents(
02956 /*=====================*/
02957   ulint*  n_reserved,
02960   ulint space,  
02961   ulint n_ext,  
02962   ulint alloc_type,
02963   mtr_t*  mtr)  
02964 {
02965   fsp_header_t* space_header;
02966   rw_lock_t*  latch;
02967   ulint   n_free_list_ext;
02968   ulint   free_limit;
02969   ulint   size;
02970   ulint   flags;
02971   ulint   zip_size;
02972   ulint   n_free;
02973   ulint   n_free_up;
02974   ulint   reserve;
02975   ibool   success;
02976   ulint   n_pages_added;
02977 
02978   ut_ad(mtr);
02979   *n_reserved = n_ext;
02980 
02981   latch = fil_space_get_latch(space, &flags);
02982   zip_size = dict_table_flags_to_zip_size(flags);
02983 
02984   ut_ad(!mutex_own(&kernel_mutex)
02985         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02986 
02987   mtr_x_lock(latch, mtr);
02988 
02989   space_header = fsp_get_space_header(space, zip_size, mtr);
02990 try_again:
02991   size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
02992 
02993   if (size < FSP_EXTENT_SIZE / 2) {
02994     /* Use different rules for small single-table tablespaces */
02995     *n_reserved = 0;
02996     return(fsp_reserve_free_pages(space, space_header, size, mtr));
02997   }
02998 
02999   n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
03000 
03001   free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
03002             MLOG_4BYTES, mtr);
03003 
03004   /* Below we play safe when counting free extents above the free limit:
03005   some of them will contain extent descriptor pages, and therefore
03006   will not be free extents */
03007 
03008   n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
03009 
03010   if (n_free_up > 0) {
03011     n_free_up--;
03012     if (!zip_size) {
03013       n_free_up -= n_free_up
03014         / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
03015     } else {
03016       n_free_up -= n_free_up
03017         / (zip_size / FSP_EXTENT_SIZE);
03018     }
03019   }
03020 
03021   n_free = n_free_list_ext + n_free_up;
03022 
03023   if (alloc_type == FSP_NORMAL) {
03024     /* We reserve 1 extent + 0.5 % of the space size to undo logs
03025     and 1 extent + 0.5 % to cleaning operations; NOTE: this source
03026     code is duplicated in the function below! */
03027 
03028     reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
03029 
03030     if (n_free <= reserve + n_ext) {
03031 
03032       goto try_to_extend;
03033     }
03034   } else if (alloc_type == FSP_UNDO) {
03035     /* We reserve 0.5 % of the space size to cleaning operations */
03036 
03037     reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
03038 
03039     if (n_free <= reserve + n_ext) {
03040 
03041       goto try_to_extend;
03042     }
03043   } else {
03044     ut_a(alloc_type == FSP_CLEANING);
03045   }
03046 
03047   success = fil_space_reserve_free_extents(space, n_free, n_ext);
03048 
03049   if (success) {
03050     return(TRUE);
03051   }
03052 try_to_extend:
03053   success = fsp_try_extend_data_file(&n_pages_added, space,
03054              space_header, mtr);
03055   if (success && n_pages_added > 0) {
03056 
03057     goto try_again;
03058   }
03059 
03060   return(FALSE);
03061 }
03062 
03063 /**********************************************************************/
03069 UNIV_INTERN
03070 ullint
03071 fsp_get_available_space_in_free_extents(
03072 /*====================================*/
03073   ulint space)  
03074 {
03075   fsp_header_t* space_header;
03076   ulint   n_free_list_ext;
03077   ulint   free_limit;
03078   ulint   size;
03079   ulint   flags;
03080   ulint   zip_size;
03081   ulint   n_free;
03082   ulint   n_free_up;
03083   ulint   reserve;
03084   rw_lock_t*  latch;
03085   mtr_t   mtr;
03086 
03087   ut_ad(!mutex_own(&kernel_mutex));
03088 
03089   /* The convoluted mutex acquire is to overcome latching order
03090   issues: The problem is that the fil_mutex is at a lower level
03091   than the tablespace latch and the buffer pool mutex. We have to
03092   first prevent any operations on the file system by acquiring the
03093   dictionary mutex. Then acquire the tablespace latch to obey the
03094   latching order and then release the dictionary mutex. That way we
03095   ensure that the tablespace instance can't be freed while we are
03096   examining its contents (see fil_space_free()).
03097 
03098   However, there is one further complication, we release the fil_mutex
03099   when we need to invalidate the the pages in the buffer pool and we
03100   reacquire the fil_mutex when deleting and freeing the tablespace
03101   instance in fil0fil.c. Here we need to account for that situation
03102   too. */
03103 
03104   mutex_enter(&dict_sys->mutex);
03105 
03106   /* At this stage there is no guarantee that the tablespace even
03107   exists in the cache. */
03108 
03109   if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
03110 
03111     mutex_exit(&dict_sys->mutex);
03112 
03113     return(ULLINT_UNDEFINED);
03114   }
03115 
03116   mtr_start(&mtr);
03117 
03118   latch = fil_space_get_latch(space, &flags);
03119 
03120   /* This should ensure that the tablespace instance can't be freed
03121   by another thread. However, the tablespace pages can still be freed
03122   from the buffer pool. We need to check for that again. */
03123 
03124   zip_size = dict_table_flags_to_zip_size(flags);
03125 
03126   mtr_x_lock(latch, &mtr);
03127 
03128   mutex_exit(&dict_sys->mutex);
03129 
03130   /* At this point it is possible for the tablespace to be deleted and
03131   its pages removed from the buffer pool. We need to check for that
03132   situation. However, the tablespace instance can't be deleted because
03133   our latching above should ensure that. */
03134 
03135   if (fil_tablespace_is_being_deleted(space)) {
03136 
03137     mtr_commit(&mtr);
03138 
03139     return(ULLINT_UNDEFINED);
03140   }
03141 
03142   /* From here on even if the user has dropped the tablespace, the
03143   pages _must_ still exist in the buffer pool and the tablespace
03144   instance _must_ be in the file system hash table. */
03145 
03146   space_header = fsp_get_space_header(space, zip_size, &mtr);
03147 
03148   size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
03149 
03150   n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
03151 
03152   free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
03153             MLOG_4BYTES, &mtr);
03154   mtr_commit(&mtr);
03155 
03156   if (size < FSP_EXTENT_SIZE) {
03157     ut_a(space != 0); /* This must be a single-table
03158           tablespace */
03159 
03160     return(0);    /* TODO: count free frag pages and
03161           return a value based on that */
03162   }
03163 
03164   /* Below we play safe when counting free extents above the free limit:
03165   some of them will contain extent descriptor pages, and therefore
03166   will not be free extents */
03167 
03168   n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
03169 
03170   if (n_free_up > 0) {
03171     n_free_up--;
03172     if (!zip_size) {
03173       n_free_up -= n_free_up
03174         / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
03175     } else {
03176       n_free_up -= n_free_up
03177         / (zip_size / FSP_EXTENT_SIZE);
03178     }
03179   }
03180 
03181   n_free = n_free_list_ext + n_free_up;
03182 
03183   /* We reserve 1 extent + 0.5 % of the space size to undo logs
03184   and 1 extent + 0.5 % to cleaning operations; NOTE: this source
03185   code is duplicated in the function above! */
03186 
03187   reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
03188 
03189   if (reserve > n_free) {
03190     return(0);
03191   }
03192 
03193   if (!zip_size) {
03194     return((ullint) (n_free - reserve)
03195            * FSP_EXTENT_SIZE
03196            * (UNIV_PAGE_SIZE / 1024));
03197   } else {
03198     return((ullint) (n_free - reserve)
03199            * FSP_EXTENT_SIZE
03200            * (zip_size / 1024));
03201   }
03202 }
03203 
03204 /********************************************************************/
03207 static
03208 void
03209 fseg_mark_page_used(
03210 /*================*/
03211   fseg_inode_t* seg_inode,
03212   ulint   space,  
03213   ulint   zip_size,
03215   ulint   page, 
03216   mtr_t*    mtr)  
03217 {
03218   xdes_t* descr;
03219   ulint not_full_n_used;
03220 
03221   ut_ad(seg_inode && mtr);
03222   ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
03223   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
03224         == FSEG_MAGIC_N_VALUE);
03225 
03226   descr = xdes_get_descriptor(space, zip_size, page, mtr);
03227 
03228   ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
03229         == mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
03230 
03231   if (xdes_is_free(descr, mtr)) {
03232     /* We move the extent from the free list to the
03233     NOT_FULL list */
03234     flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
03235           mtr);
03236     flst_add_last(seg_inode + FSEG_NOT_FULL,
03237             descr + XDES_FLST_NODE, mtr);
03238   }
03239 
03240   ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
03241         == TRUE);
03242   /* We mark the page as used */
03243   xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
03244 
03245   not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03246            MLOG_4BYTES, mtr);
03247   not_full_n_used++;
03248   mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
03249        MLOG_4BYTES, mtr);
03250   if (xdes_is_full(descr, mtr)) {
03251     /* We move the extent from the NOT_FULL list to the
03252     FULL list */
03253     flst_remove(seg_inode + FSEG_NOT_FULL,
03254           descr + XDES_FLST_NODE, mtr);
03255     flst_add_last(seg_inode + FSEG_FULL,
03256             descr + XDES_FLST_NODE, mtr);
03257 
03258     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03259          not_full_n_used - FSP_EXTENT_SIZE,
03260          MLOG_4BYTES, mtr);
03261   }
03262 }
03263 
03264 /**********************************************************************/
03266 static
03267 void
03268 fseg_free_page_low(
03269 /*===============*/
03270   fseg_inode_t* seg_inode, 
03271   ulint   space,  
03272   ulint   zip_size,
03274   ulint   page, 
03275   mtr_t*    mtr)  
03276 {
03277   xdes_t* descr;
03278   ulint not_full_n_used;
03279   ulint state;
03280   ib_id_t descr_id;
03281   ib_id_t seg_id;
03282   ulint i;
03283 
03284   ut_ad(seg_inode && mtr);
03285   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
03286         == FSEG_MAGIC_N_VALUE);
03287   ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
03288 
03289   /* Drop search system page hash index if the page is found in
03290   the pool and is hashed */
03291 
03292   btr_search_drop_page_hash_when_freed(space, zip_size, page);
03293 
03294   descr = xdes_get_descriptor(space, zip_size, page, mtr);
03295 
03296   ut_a(descr);
03297   if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
03298     fputs("InnoDB: Dump of the tablespace extent descriptor: ",
03299           stderr);
03300     ut_print_buf(stderr, descr, 40);
03301 
03302     fprintf(stderr, "\n"
03303       "InnoDB: Serious error! InnoDB is trying to"
03304       " free page %lu\n"
03305       "InnoDB: though it is already marked as free"
03306       " in the tablespace!\n"
03307       "InnoDB: The tablespace free space info is corrupt.\n"
03308       "InnoDB: You may need to dump your"
03309       " InnoDB tables and recreate the whole\n"
03310       "InnoDB: database!\n", (ulong) page);
03311 crash:
03312     fputs("InnoDB: Please refer to\n"
03313           "InnoDB: " REFMAN "forcing-recovery.html\n"
03314           "InnoDB: about forcing recovery.\n", stderr);
03315     ut_error;
03316   }
03317 
03318   state = xdes_get_state(descr, mtr);
03319 
03320   if (state != XDES_FSEG) {
03321     /* The page is in the fragment pages of the segment */
03322 
03323     for (i = 0;; i++) {
03324       if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
03325           == page) {
03326 
03327         fseg_set_nth_frag_page_no(seg_inode, i,
03328                 FIL_NULL, mtr);
03329         break;
03330       }
03331     }
03332 
03333     fsp_free_page(space, zip_size, page, mtr);
03334 
03335     return;
03336   }
03337 
03338   /* If we get here, the page is in some extent of the segment */
03339 
03340   descr_id = mach_read_from_8(descr + XDES_ID);
03341   seg_id = mach_read_from_8(seg_inode + FSEG_ID);
03342 #if 0
03343   fprintf(stderr,
03344     "InnoDB: InnoDB is freeing space %lu page %lu,\n"
03345     "InnoDB: which belongs to descr seg %llu\n"
03346     "InnoDB: segment %llu.\n",
03347     (ulong) space, (ulong) page,
03348     (ullint) descr_id,
03349     (ullint) seg_id);
03350 #endif /* 0 */
03351   if (UNIV_UNLIKELY(descr_id != seg_id)) {
03352     fputs("InnoDB: Dump of the tablespace extent descriptor: ",
03353           stderr);
03354     ut_print_buf(stderr, descr, 40);
03355     fputs("\nInnoDB: Dump of the segment inode: ", stderr);
03356     ut_print_buf(stderr, seg_inode, 40);
03357     putc('\n', stderr);
03358 
03359     fprintf(stderr,
03360       "InnoDB: Serious error: InnoDB is trying to"
03361       " free space %lu page %lu,\n"
03362       "InnoDB: which does not belong to"
03363       " segment %llu but belongs\n"
03364       "InnoDB: to segment %llu.\n",
03365       (ulong) space, (ulong) page,
03366       (ullint) descr_id,
03367       (ullint) seg_id);
03368     goto crash;
03369   }
03370 
03371   not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03372            MLOG_4BYTES, mtr);
03373   if (xdes_is_full(descr, mtr)) {
03374     /* The fragment is full: move it to another list */
03375     flst_remove(seg_inode + FSEG_FULL,
03376           descr + XDES_FLST_NODE, mtr);
03377     flst_add_last(seg_inode + FSEG_NOT_FULL,
03378             descr + XDES_FLST_NODE, mtr);
03379     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03380          not_full_n_used + FSP_EXTENT_SIZE - 1,
03381          MLOG_4BYTES, mtr);
03382   } else {
03383     ut_a(not_full_n_used > 0);
03384     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03385          not_full_n_used - 1, MLOG_4BYTES, mtr);
03386   }
03387 
03388   xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
03389   xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
03390 
03391   if (xdes_is_free(descr, mtr)) {
03392     /* The extent has become free: free it to space */
03393     flst_remove(seg_inode + FSEG_NOT_FULL,
03394           descr + XDES_FLST_NODE, mtr);
03395     fsp_free_extent(space, zip_size, page, mtr);
03396   }
03397 }
03398 
03399 /**********************************************************************/
03401 UNIV_INTERN
03402 void
03403 fseg_free_page(
03404 /*===========*/
03405   fseg_header_t*  seg_header, 
03406   ulint   space,  
03407   ulint   page, 
03408   mtr_t*    mtr)  
03409 {
03410   ulint   flags;
03411   ulint   zip_size;
03412   fseg_inode_t* seg_inode;
03413   rw_lock_t*  latch;
03414 
03415   latch = fil_space_get_latch(space, &flags);
03416   zip_size = dict_table_flags_to_zip_size(flags);
03417 
03418   ut_ad(!mutex_own(&kernel_mutex)
03419         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
03420 
03421   mtr_x_lock(latch, mtr);
03422 
03423   seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
03424 
03425   fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
03426 
03427 #ifdef UNIV_DEBUG_FILE_ACCESSES
03428   buf_page_set_file_page_was_freed(space, page);
03429 #endif
03430 }
03431 
03432 /**********************************************************************/
03434 static
03435 void
03436 fseg_free_extent(
03437 /*=============*/
03438   fseg_inode_t* seg_inode, 
03439   ulint   space,  
03440   ulint   zip_size,
03442   ulint   page, 
03443   mtr_t*    mtr)  
03444 {
03445   ulint first_page_in_extent;
03446   xdes_t* descr;
03447   ulint not_full_n_used;
03448   ulint descr_n_used;
03449   ulint i;
03450 
03451   ut_ad(seg_inode && mtr);
03452 
03453   descr = xdes_get_descriptor(space, zip_size, page, mtr);
03454 
03455   ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
03456   ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
03457   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
03458         == FSEG_MAGIC_N_VALUE);
03459 
03460   first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
03461 
03462   for (i = 0; i < FSP_EXTENT_SIZE; i++) {
03463     if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
03464 
03465       /* Drop search system page hash index if the page is
03466       found in the pool and is hashed */
03467 
03468       btr_search_drop_page_hash_when_freed(
03469         space, zip_size, first_page_in_extent + i);
03470     }
03471   }
03472 
03473   if (xdes_is_full(descr, mtr)) {
03474     flst_remove(seg_inode + FSEG_FULL,
03475           descr + XDES_FLST_NODE, mtr);
03476   } else if (xdes_is_free(descr, mtr)) {
03477     flst_remove(seg_inode + FSEG_FREE,
03478           descr + XDES_FLST_NODE, mtr);
03479   } else {
03480     flst_remove(seg_inode + FSEG_NOT_FULL,
03481           descr + XDES_FLST_NODE, mtr);
03482 
03483     not_full_n_used = mtr_read_ulint(
03484       seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
03485 
03486     descr_n_used = xdes_get_n_used(descr, mtr);
03487     ut_a(not_full_n_used >= descr_n_used);
03488     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03489          not_full_n_used - descr_n_used,
03490          MLOG_4BYTES, mtr);
03491   }
03492 
03493   fsp_free_extent(space, zip_size, page, mtr);
03494 
03495 #ifdef UNIV_DEBUG_FILE_ACCESSES
03496   for (i = 0; i < FSP_EXTENT_SIZE; i++) {
03497 
03498     buf_page_set_file_page_was_freed(space,
03499              first_page_in_extent + i);
03500   }
03501 #endif
03502 }
03503 
03504 /**********************************************************************/
03510 UNIV_INTERN
03511 ibool
03512 fseg_free_step(
03513 /*===========*/
03514   fseg_header_t*  header, 
03518   mtr_t*    mtr)  
03519 {
03520   ulint   n;
03521   ulint   page;
03522   xdes_t*   descr;
03523   fseg_inode_t* inode;
03524   ulint   space;
03525   ulint   flags;
03526   ulint   zip_size;
03527   ulint   header_page;
03528   rw_lock_t*  latch;
03529 
03530   space = page_get_space_id(page_align(header));
03531   header_page = page_get_page_no(page_align(header));
03532 
03533   latch = fil_space_get_latch(space, &flags);
03534   zip_size = dict_table_flags_to_zip_size(flags);
03535 
03536   ut_ad(!mutex_own(&kernel_mutex)
03537         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
03538 
03539   mtr_x_lock(latch, mtr);
03540 
03541   descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
03542 
03543   /* Check that the header resides on a page which has not been
03544   freed yet */
03545 
03546   ut_a(descr);
03547   ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
03548         header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
03549   inode = fseg_inode_try_get(header, space, zip_size, mtr);
03550 
03551   if (UNIV_UNLIKELY(inode == NULL)) {
03552     fprintf(stderr, "double free of inode from %u:%u\n",
03553       (unsigned) space, (unsigned) header_page);
03554     return(TRUE);
03555   }
03556 
03557   descr = fseg_get_first_extent(inode, space, zip_size, mtr);
03558 
03559   if (descr != NULL) {
03560     /* Free the extent held by the segment */
03561     page = xdes_get_offset(descr);
03562 
03563     fseg_free_extent(inode, space, zip_size, page, mtr);
03564 
03565     return(FALSE);
03566   }
03567 
03568   /* Free a frag page */
03569   n = fseg_find_last_used_frag_page_slot(inode, mtr);
03570 
03571   if (n == ULINT_UNDEFINED) {
03572     /* Freeing completed: free the segment inode */
03573     fsp_free_seg_inode(space, zip_size, inode, mtr);
03574 
03575     return(TRUE);
03576   }
03577 
03578   fseg_free_page_low(inode, space, zip_size,
03579          fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
03580 
03581   n = fseg_find_last_used_frag_page_slot(inode, mtr);
03582 
03583   if (n == ULINT_UNDEFINED) {
03584     /* Freeing completed: free the segment inode */
03585     fsp_free_seg_inode(space, zip_size, inode, mtr);
03586 
03587     return(TRUE);
03588   }
03589 
03590   return(FALSE);
03591 }
03592 
03593 /**********************************************************************/
03597 UNIV_INTERN
03598 ibool
03599 fseg_free_step_not_header(
03600 /*======================*/
03601   fseg_header_t*  header, 
03603   mtr_t*    mtr)  
03604 {
03605   ulint   n;
03606   ulint   page;
03607   xdes_t*   descr;
03608   fseg_inode_t* inode;
03609   ulint   space;
03610   ulint   flags;
03611   ulint   zip_size;
03612   ulint   page_no;
03613   rw_lock_t*  latch;
03614 
03615   space = page_get_space_id(page_align(header));
03616 
03617   latch = fil_space_get_latch(space, &flags);
03618   zip_size = dict_table_flags_to_zip_size(flags);
03619 
03620   ut_ad(!mutex_own(&kernel_mutex)
03621         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
03622 
03623   mtr_x_lock(latch, mtr);
03624 
03625   inode = fseg_inode_get(header, space, zip_size, mtr);
03626 
03627   descr = fseg_get_first_extent(inode, space, zip_size, mtr);
03628 
03629   if (descr != NULL) {
03630     /* Free the extent held by the segment */
03631     page = xdes_get_offset(descr);
03632 
03633     fseg_free_extent(inode, space, zip_size, page, mtr);
03634 
03635     return(FALSE);
03636   }
03637 
03638   /* Free a frag page */
03639 
03640   n = fseg_find_last_used_frag_page_slot(inode, mtr);
03641 
03642   if (n == ULINT_UNDEFINED) {
03643     ut_error;
03644   }
03645 
03646   page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
03647 
03648   if (page_no == page_get_page_no(page_align(header))) {
03649 
03650     return(TRUE);
03651   }
03652 
03653   fseg_free_page_low(inode, space, zip_size, page_no, mtr);
03654 
03655   return(FALSE);
03656 }
03657 
03658 /**********************************************************************/
03663 static
03664 xdes_t*
03665 fseg_get_first_extent(
03666 /*==================*/
03667   fseg_inode_t* inode,  
03668   ulint   space,  
03669   ulint   zip_size,
03671   mtr_t*    mtr)  
03672 {
03673   fil_addr_t  first;
03674   xdes_t*   descr;
03675 
03676   ut_ad(inode && mtr);
03677 
03678   ut_ad(space == page_get_space_id(page_align(inode)));
03679   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
03680 
03681   first = fil_addr_null;
03682 
03683   if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
03684 
03685     first = flst_get_first(inode + FSEG_FULL, mtr);
03686 
03687   } else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
03688 
03689     first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
03690 
03691   } else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
03692 
03693     first = flst_get_first(inode + FSEG_FREE, mtr);
03694   }
03695 
03696   if (first.page == FIL_NULL) {
03697 
03698     return(NULL);
03699   }
03700   descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
03701 
03702   return(descr);
03703 }
03704 
03705 /*******************************************************************/
03708 static
03709 ibool
03710 fseg_validate_low(
03711 /*==============*/
03712   fseg_inode_t* inode, 
03713   mtr_t*    mtr2) 
03714 {
03715   ulint   space;
03716   ib_id_t   seg_id;
03717   mtr_t   mtr;
03718   xdes_t*   descr;
03719   fil_addr_t  node_addr;
03720   ulint   n_used    = 0;
03721   ulint   n_used2   = 0;
03722 
03723   ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
03724   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
03725 
03726   space = page_get_space_id(page_align(inode));
03727 
03728   seg_id = mach_read_from_8(inode + FSEG_ID);
03729   n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
03730         MLOG_4BYTES, mtr2);
03731   flst_validate(inode + FSEG_FREE, mtr2);
03732   flst_validate(inode + FSEG_NOT_FULL, mtr2);
03733   flst_validate(inode + FSEG_FULL, mtr2);
03734 
03735   /* Validate FSEG_FREE list */
03736   node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
03737 
03738   while (!fil_addr_is_null(node_addr)) {
03739     ulint flags;
03740     ulint zip_size;
03741 
03742     mtr_start(&mtr);
03743     mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
03744     zip_size = dict_table_flags_to_zip_size(flags);
03745 
03746     descr = xdes_lst_get_descriptor(space, zip_size,
03747             node_addr, &mtr);
03748 
03749     ut_a(xdes_get_n_used(descr, &mtr) == 0);
03750     ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
03751     ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
03752 
03753     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
03754     mtr_commit(&mtr);
03755   }
03756 
03757   /* Validate FSEG_NOT_FULL list */
03758 
03759   node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
03760 
03761   while (!fil_addr_is_null(node_addr)) {
03762     ulint flags;
03763     ulint zip_size;
03764 
03765     mtr_start(&mtr);
03766     mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
03767     zip_size = dict_table_flags_to_zip_size(flags);
03768 
03769     descr = xdes_lst_get_descriptor(space, zip_size,
03770             node_addr, &mtr);
03771 
03772     ut_a(xdes_get_n_used(descr, &mtr) > 0);
03773     ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
03774     ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
03775     ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
03776 
03777     n_used2 += xdes_get_n_used(descr, &mtr);
03778 
03779     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
03780     mtr_commit(&mtr);
03781   }
03782 
03783   /* Validate FSEG_FULL list */
03784 
03785   node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
03786 
03787   while (!fil_addr_is_null(node_addr)) {
03788     ulint flags;
03789     ulint zip_size;
03790 
03791     mtr_start(&mtr);
03792     mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
03793     zip_size = dict_table_flags_to_zip_size(flags);
03794 
03795     descr = xdes_lst_get_descriptor(space, zip_size,
03796             node_addr, &mtr);
03797 
03798     ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
03799     ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
03800     ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
03801 
03802     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
03803     mtr_commit(&mtr);
03804   }
03805 
03806   ut_a(n_used == n_used2);
03807 
03808   return(TRUE);
03809 }
03810 
03811 #ifdef UNIV_DEBUG
03812 /*******************************************************************/
03815 UNIV_INTERN
03816 ibool
03817 fseg_validate(
03818 /*==========*/
03819   fseg_header_t*  header, 
03820   mtr_t*    mtr)  
03821 {
03822   fseg_inode_t* inode;
03823   ibool   ret;
03824   ulint   space;
03825   ulint   flags;
03826   ulint   zip_size;
03827 
03828   space = page_get_space_id(page_align(header));
03829 
03830   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
03831   zip_size = dict_table_flags_to_zip_size(flags);
03832 
03833   inode = fseg_inode_get(header, space, zip_size, mtr);
03834 
03835   ret = fseg_validate_low(inode, mtr);
03836 
03837   return(ret);
03838 }
03839 #endif /* UNIV_DEBUG */
03840 
03841 /*******************************************************************/
03843 static
03844 void
03845 fseg_print_low(
03846 /*===========*/
03847   fseg_inode_t* inode, 
03848   mtr_t*    mtr)  
03849 {
03850   ulint space;
03851   ulint n_used;
03852   ulint n_frag;
03853   ulint n_free;
03854   ulint n_not_full;
03855   ulint n_full;
03856   ulint reserved;
03857   ulint used;
03858   ulint page_no;
03859   ib_id_t seg_id;
03860 
03861   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
03862   space = page_get_space_id(page_align(inode));
03863   page_no = page_get_page_no(page_align(inode));
03864 
03865   reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
03866 
03867   seg_id = mach_read_from_8(inode + FSEG_ID);
03868 
03869   n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
03870         MLOG_4BYTES, mtr);
03871   n_frag = fseg_get_n_frag_pages(inode, mtr);
03872   n_free = flst_get_len(inode + FSEG_FREE, mtr);
03873   n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
03874   n_full = flst_get_len(inode + FSEG_FULL, mtr);
03875 
03876   fprintf(stderr,
03877     "SEGMENT id %llu space %lu; page %lu;"
03878     " res %lu used %lu; full ext %lu\n"
03879     "fragm pages %lu; free extents %lu;"
03880     " not full extents %lu: pages %lu\n",
03881     (ullint) seg_id,
03882     (ulong) space, (ulong) page_no,
03883     (ulong) reserved, (ulong) used, (ulong) n_full,
03884     (ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
03885     (ulong) n_used);
03886   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
03887 }
03888 
03889 #ifdef UNIV_BTR_PRINT
03890 /*******************************************************************/
03892 UNIV_INTERN
03893 void
03894 fseg_print(
03895 /*=======*/
03896   fseg_header_t*  header, 
03897   mtr_t*    mtr)  
03898 {
03899   fseg_inode_t* inode;
03900   ulint   space;
03901   ulint   flags;
03902   ulint   zip_size;
03903 
03904   space = page_get_space_id(page_align(header));
03905 
03906   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
03907   zip_size = dict_table_flags_to_zip_size(flags);
03908 
03909   inode = fseg_inode_get(header, space, zip_size, mtr);
03910 
03911   fseg_print_low(inode, mtr);
03912 }
03913 #endif /* UNIV_BTR_PRINT */
03914 
03915 /*******************************************************************/
03918 UNIV_INTERN
03919 ibool
03920 fsp_validate(
03921 /*=========*/
03922   ulint space)  
03923 {
03924   fsp_header_t* header;
03925   fseg_inode_t* seg_inode;
03926   page_t*   seg_inode_page;
03927   rw_lock_t*  latch;
03928   ulint   size;
03929   ulint   flags;
03930   ulint   zip_size;
03931   ulint   free_limit;
03932   ulint   frag_n_used;
03933   mtr_t   mtr;
03934   mtr_t   mtr2;
03935   xdes_t*   descr;
03936   fil_addr_t  node_addr;
03937   fil_addr_t  next_node_addr;
03938   ulint   descr_count = 0;
03939   ulint   n_used    = 0;
03940   ulint   n_used2   = 0;
03941   ulint   n_full_frag_pages;
03942   ulint   n;
03943   ulint   seg_inode_len_free;
03944   ulint   seg_inode_len_full;
03945 
03946   latch = fil_space_get_latch(space, &flags);
03947   zip_size = dict_table_flags_to_zip_size(flags);
03948   ut_a(ut_is_2pow(zip_size));
03949   ut_a(zip_size <= UNIV_PAGE_SIZE);
03950   ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
03951 
03952   /* Start first a mini-transaction mtr2 to lock out all other threads
03953   from the fsp system */
03954   mtr_start(&mtr2);
03955   mtr_x_lock(latch, &mtr2);
03956 
03957   mtr_start(&mtr);
03958   mtr_x_lock(latch, &mtr);
03959 
03960   header = fsp_get_space_header(space, zip_size, &mtr);
03961 
03962   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
03963   free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
03964             MLOG_4BYTES, &mtr);
03965   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
03966              MLOG_4BYTES, &mtr);
03967 
03968   n_full_frag_pages = FSP_EXTENT_SIZE
03969     * flst_get_len(header + FSP_FULL_FRAG, &mtr);
03970 
03971   if (UNIV_UNLIKELY(free_limit > size)) {
03972 
03973     ut_a(space != 0);
03974     ut_a(size < FSP_EXTENT_SIZE);
03975   }
03976 
03977   flst_validate(header + FSP_FREE, &mtr);
03978   flst_validate(header + FSP_FREE_FRAG, &mtr);
03979   flst_validate(header + FSP_FULL_FRAG, &mtr);
03980 
03981   mtr_commit(&mtr);
03982 
03983   /* Validate FSP_FREE list */
03984   mtr_start(&mtr);
03985   mtr_x_lock(latch, &mtr);
03986 
03987   header = fsp_get_space_header(space, zip_size, &mtr);
03988   node_addr = flst_get_first(header + FSP_FREE, &mtr);
03989 
03990   mtr_commit(&mtr);
03991 
03992   while (!fil_addr_is_null(node_addr)) {
03993     mtr_start(&mtr);
03994     mtr_x_lock(latch, &mtr);
03995 
03996     descr_count++;
03997     descr = xdes_lst_get_descriptor(space, zip_size,
03998             node_addr, &mtr);
03999 
04000     ut_a(xdes_get_n_used(descr, &mtr) == 0);
04001     ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
04002 
04003     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
04004     mtr_commit(&mtr);
04005   }
04006 
04007   /* Validate FSP_FREE_FRAG list */
04008   mtr_start(&mtr);
04009   mtr_x_lock(latch, &mtr);
04010 
04011   header = fsp_get_space_header(space, zip_size, &mtr);
04012   node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
04013 
04014   mtr_commit(&mtr);
04015 
04016   while (!fil_addr_is_null(node_addr)) {
04017     mtr_start(&mtr);
04018     mtr_x_lock(latch, &mtr);
04019 
04020     descr_count++;
04021     descr = xdes_lst_get_descriptor(space, zip_size,
04022             node_addr, &mtr);
04023 
04024     ut_a(xdes_get_n_used(descr, &mtr) > 0);
04025     ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
04026     ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
04027 
04028     n_used += xdes_get_n_used(descr, &mtr);
04029     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
04030 
04031     mtr_commit(&mtr);
04032   }
04033 
04034   /* Validate FSP_FULL_FRAG list */
04035   mtr_start(&mtr);
04036   mtr_x_lock(latch, &mtr);
04037 
04038   header = fsp_get_space_header(space, zip_size, &mtr);
04039   node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
04040 
04041   mtr_commit(&mtr);
04042 
04043   while (!fil_addr_is_null(node_addr)) {
04044     mtr_start(&mtr);
04045     mtr_x_lock(latch, &mtr);
04046 
04047     descr_count++;
04048     descr = xdes_lst_get_descriptor(space, zip_size,
04049             node_addr, &mtr);
04050 
04051     ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
04052     ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
04053 
04054     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
04055     mtr_commit(&mtr);
04056   }
04057 
04058   /* Validate segments */
04059   mtr_start(&mtr);
04060   mtr_x_lock(latch, &mtr);
04061 
04062   header = fsp_get_space_header(space, zip_size, &mtr);
04063 
04064   node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
04065 
04066   seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
04067 
04068   mtr_commit(&mtr);
04069 
04070   while (!fil_addr_is_null(node_addr)) {
04071 
04072     n = 0;
04073     do {
04074       mtr_start(&mtr);
04075       mtr_x_lock(latch, &mtr);
04076 
04077       seg_inode_page = fut_get_ptr(
04078         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04079         - FSEG_INODE_PAGE_NODE;
04080 
04081       seg_inode = fsp_seg_inode_page_get_nth_inode(
04082         seg_inode_page, n, zip_size, &mtr);
04083       ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
04084       fseg_validate_low(seg_inode, &mtr);
04085 
04086       descr_count += flst_get_len(seg_inode + FSEG_FREE,
04087                 &mtr);
04088       descr_count += flst_get_len(seg_inode + FSEG_FULL,
04089                 &mtr);
04090       descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
04091                 &mtr);
04092 
04093       n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
04094 
04095       next_node_addr = flst_get_next_addr(
04096         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04097       mtr_commit(&mtr);
04098     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04099 
04100     node_addr = next_node_addr;
04101   }
04102 
04103   mtr_start(&mtr);
04104   mtr_x_lock(latch, &mtr);
04105 
04106   header = fsp_get_space_header(space, zip_size, &mtr);
04107 
04108   node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
04109 
04110   seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
04111 
04112   mtr_commit(&mtr);
04113 
04114   while (!fil_addr_is_null(node_addr)) {
04115 
04116     n = 0;
04117 
04118     do {
04119       mtr_start(&mtr);
04120       mtr_x_lock(latch, &mtr);
04121 
04122       seg_inode_page = fut_get_ptr(
04123         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04124         - FSEG_INODE_PAGE_NODE;
04125 
04126       seg_inode = fsp_seg_inode_page_get_nth_inode(
04127         seg_inode_page, n, zip_size, &mtr);
04128       if (mach_read_from_8(seg_inode + FSEG_ID)) {
04129         fseg_validate_low(seg_inode, &mtr);
04130 
04131         descr_count += flst_get_len(
04132           seg_inode + FSEG_FREE, &mtr);
04133         descr_count += flst_get_len(
04134           seg_inode + FSEG_FULL, &mtr);
04135         descr_count += flst_get_len(
04136           seg_inode + FSEG_NOT_FULL, &mtr);
04137         n_used2 += fseg_get_n_frag_pages(
04138           seg_inode, &mtr);
04139       }
04140 
04141       next_node_addr = flst_get_next_addr(
04142         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04143       mtr_commit(&mtr);
04144     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04145 
04146     node_addr = next_node_addr;
04147   }
04148 
04149   ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
04150   if (!zip_size) {
04151     ut_a(n_used + n_full_frag_pages
04152          == n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
04153                / UNIV_PAGE_SIZE)
04154          + seg_inode_len_full + seg_inode_len_free);
04155   } else {
04156     ut_a(n_used + n_full_frag_pages
04157          == n_used2 + 2 * ((free_limit + (zip_size - 1))
04158                / zip_size)
04159          + seg_inode_len_full + seg_inode_len_free);
04160   }
04161   ut_a(frag_n_used == n_used);
04162 
04163   mtr_commit(&mtr2);
04164 
04165   return(TRUE);
04166 }
04167 
04168 /*******************************************************************/
04170 UNIV_INTERN
04171 void
04172 fsp_print(
04173 /*======*/
04174   ulint space)  
04175 {
04176   fsp_header_t* header;
04177   fseg_inode_t* seg_inode;
04178   page_t*   seg_inode_page;
04179   rw_lock_t*  latch;
04180   ulint   flags;
04181   ulint   zip_size;
04182   ulint   size;
04183   ulint   free_limit;
04184   ulint   frag_n_used;
04185   fil_addr_t  node_addr;
04186   fil_addr_t  next_node_addr;
04187   ulint   n_free;
04188   ulint   n_free_frag;
04189   ulint   n_full_frag;
04190   ib_id_t   seg_id;
04191   ulint   n;
04192   ulint   n_segs    = 0;
04193   mtr_t   mtr;
04194   mtr_t   mtr2;
04195 
04196   latch = fil_space_get_latch(space, &flags);
04197   zip_size = dict_table_flags_to_zip_size(flags);
04198 
04199   /* Start first a mini-transaction mtr2 to lock out all other threads
04200   from the fsp system */
04201 
04202   mtr_start(&mtr2);
04203 
04204   mtr_x_lock(latch, &mtr2);
04205 
04206   mtr_start(&mtr);
04207 
04208   mtr_x_lock(latch, &mtr);
04209 
04210   header = fsp_get_space_header(space, zip_size, &mtr);
04211 
04212   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
04213 
04214   free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
04215             &mtr);
04216   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
04217              &mtr);
04218   n_free = flst_get_len(header + FSP_FREE, &mtr);
04219   n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
04220   n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
04221 
04222   seg_id = mach_read_from_8(header + FSP_SEG_ID);
04223 
04224   fprintf(stderr,
04225     "FILE SPACE INFO: id %lu\n"
04226     "size %lu, free limit %lu, free extents %lu\n"
04227     "not full frag extents %lu: used pages %lu,"
04228     " full frag extents %lu\n"
04229     "first seg id not used %llu\n",
04230     (ulong) space,
04231     (ulong) size, (ulong) free_limit, (ulong) n_free,
04232     (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
04233     (ullint) seg_id);
04234 
04235   mtr_commit(&mtr);
04236 
04237   /* Print segments */
04238 
04239   mtr_start(&mtr);
04240   mtr_x_lock(latch, &mtr);
04241 
04242   header = fsp_get_space_header(space, zip_size, &mtr);
04243 
04244   node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
04245 
04246   mtr_commit(&mtr);
04247 
04248   while (!fil_addr_is_null(node_addr)) {
04249 
04250     n = 0;
04251 
04252     do {
04253 
04254       mtr_start(&mtr);
04255       mtr_x_lock(latch, &mtr);
04256 
04257       seg_inode_page = fut_get_ptr(
04258         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04259         - FSEG_INODE_PAGE_NODE;
04260 
04261       seg_inode = fsp_seg_inode_page_get_nth_inode(
04262         seg_inode_page, n, zip_size, &mtr);
04263       ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
04264       fseg_print_low(seg_inode, &mtr);
04265 
04266       n_segs++;
04267 
04268       next_node_addr = flst_get_next_addr(
04269         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04270       mtr_commit(&mtr);
04271     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04272 
04273     node_addr = next_node_addr;
04274   }
04275 
04276   mtr_start(&mtr);
04277   mtr_x_lock(latch, &mtr);
04278 
04279   header = fsp_get_space_header(space, zip_size, &mtr);
04280 
04281   node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
04282 
04283   mtr_commit(&mtr);
04284 
04285   while (!fil_addr_is_null(node_addr)) {
04286 
04287     n = 0;
04288 
04289     do {
04290 
04291       mtr_start(&mtr);
04292       mtr_x_lock(latch, &mtr);
04293 
04294       seg_inode_page = fut_get_ptr(
04295         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04296         - FSEG_INODE_PAGE_NODE;
04297 
04298       seg_inode = fsp_seg_inode_page_get_nth_inode(
04299         seg_inode_page, n, zip_size, &mtr);
04300       if (mach_read_from_8(seg_inode + FSEG_ID)) {
04301 
04302         fseg_print_low(seg_inode, &mtr);
04303         n_segs++;
04304       }
04305 
04306       next_node_addr = flst_get_next_addr(
04307         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04308       mtr_commit(&mtr);
04309     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04310 
04311     node_addr = next_node_addr;
04312   }
04313 
04314   mtr_commit(&mtr2);
04315 
04316   fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
04317 }
04318 #endif /* !UNIV_HOTBACKUP */