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 #ifndef DOXYGEN /* Doxygen gets confused of these */
00654 # if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
00655     + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
00656 #  error
00657 # endif
00658 # if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
00659     + (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
00660 #  error
00661 # endif
00662 #endif /* !DOXYGEN */
00663   ut_ad(ut_is_2pow(zip_size));
00664 
00665   if (!zip_size) {
00666     return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
00667   } else {
00668     ut_ad(zip_size > XDES_ARR_OFFSET
00669           + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
00670     return(ut_2pow_round(offset, zip_size));
00671   }
00672 }
00673 
00674 /********************************************************************/
00677 UNIV_INLINE
00678 ulint
00679 xdes_calc_descriptor_index(
00680 /*=======================*/
00681   ulint zip_size, 
00683   ulint offset)   
00684 {
00685   ut_ad(ut_is_2pow(zip_size));
00686 
00687   if (!zip_size) {
00688     return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
00689            / FSP_EXTENT_SIZE);
00690   } else {
00691     return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
00692   }
00693 }
00694 
00695 /********************************************************************/
00703 UNIV_INLINE
00704 xdes_t*
00705 xdes_get_descriptor_with_space_hdr(
00706 /*===============================*/
00707   fsp_header_t* sp_header,
00708   ulint   space,  
00709   ulint   offset, 
00713   mtr_t*    mtr)  
00714 {
00715   ulint limit;
00716   ulint size;
00717   ulint zip_size;
00718   ulint descr_page_no;
00719   page_t* descr_page;
00720 
00721   ut_ad(mtr);
00722   ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
00723         MTR_MEMO_X_LOCK));
00724   ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
00725         || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
00726   ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
00727   /* Read free limit and space size */
00728   limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
00729   size  = mach_read_from_4(sp_header + FSP_SIZE);
00730   zip_size = dict_table_flags_to_zip_size(
00731     mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
00732 
00733   /* If offset is >= size or > limit, return NULL */
00734 
00735   if ((offset >= size) || (offset > limit)) {
00736 
00737     return(NULL);
00738   }
00739 
00740   /* If offset is == limit, fill free list of the space. */
00741 
00742   if (offset == limit) {
00743     fsp_fill_free_list(FALSE, space, sp_header, mtr);
00744   }
00745 
00746   descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
00747 
00748   if (descr_page_no == 0) {
00749     /* It is on the space header page */
00750 
00751     descr_page = page_align(sp_header);
00752   } else {
00753     buf_block_t*  block;
00754 
00755     block = buf_page_get(space, zip_size, descr_page_no,
00756              RW_X_LATCH, mtr);
00757     buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00758 
00759     descr_page = buf_block_get_frame(block);
00760   }
00761 
00762   return(descr_page + XDES_ARR_OFFSET
00763          + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
00764 }
00765 
00766 /********************************************************************/
00775 static
00776 xdes_t*
00777 xdes_get_descriptor(
00778 /*================*/
00779   ulint space,  
00780   ulint zip_size,
00782   ulint offset, 
00784   mtr_t*  mtr)  
00785 {
00786   buf_block_t*  block;
00787   fsp_header_t* sp_header;
00788 
00789   block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
00790   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00791 
00792   sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
00793   return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
00794               mtr));
00795 }
00796 
00797 /********************************************************************/
00802 UNIV_INLINE
00803 xdes_t*
00804 xdes_lst_get_descriptor(
00805 /*====================*/
00806   ulint   space,  
00807   ulint   zip_size,
00809   fil_addr_t  lst_node,
00811   mtr_t*    mtr)  
00812 {
00813   xdes_t* descr;
00814 
00815   ut_ad(mtr);
00816   ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
00817         MTR_MEMO_X_LOCK));
00818   descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
00819     - XDES_FLST_NODE;
00820 
00821   return(descr);
00822 }
00823 
00824 /********************************************************************/
00827 UNIV_INLINE
00828 ulint
00829 xdes_get_offset(
00830 /*============*/
00831   xdes_t* descr)  
00832 {
00833   ut_ad(descr);
00834 
00835   return(page_get_page_no(page_align(descr))
00836          + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
00837          * FSP_EXTENT_SIZE);
00838 }
00839 #endif /* !UNIV_HOTBACKUP */
00840 
00841 /***********************************************************/
00843 static
00844 void
00845 fsp_init_file_page_low(
00846 /*===================*/
00847   buf_block_t*  block)  
00848 {
00849   page_t*   page  = buf_block_get_frame(block);
00850   page_zip_des_t* page_zip= buf_block_get_page_zip(block);
00851 
00852 #ifndef UNIV_HOTBACKUP
00853   block->check_index_page_at_flush = FALSE;
00854 #endif /* !UNIV_HOTBACKUP */
00855 
00856   if (UNIV_LIKELY_NULL(page_zip)) {
00857     memset(page, 0, UNIV_PAGE_SIZE);
00858     memset(page_zip->data, 0, page_zip_get_size(page_zip));
00859     mach_write_to_4(page + FIL_PAGE_OFFSET,
00860         buf_block_get_page_no(block));
00861     mach_write_to_4(page
00862         + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
00863         buf_block_get_space(block));
00864     memcpy(page_zip->data + FIL_PAGE_OFFSET,
00865            page + FIL_PAGE_OFFSET, 4);
00866     memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
00867            page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
00868     return;
00869   }
00870 
00871   memset(page, 0, UNIV_PAGE_SIZE);
00872   mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
00873   mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
00874       buf_block_get_space(block));
00875 }
00876 
00877 #ifndef UNIV_HOTBACKUP
00878 /***********************************************************/
00880 static
00881 void
00882 fsp_init_file_page(
00883 /*===============*/
00884   buf_block_t*  block,  
00885   mtr_t*    mtr)  
00886 {
00887   fsp_init_file_page_low(block);
00888 
00889   mlog_write_initial_log_record(buf_block_get_frame(block),
00890               MLOG_INIT_FILE_PAGE, mtr);
00891 }
00892 #endif /* !UNIV_HOTBACKUP */
00893 
00894 /***********************************************************/
00897 UNIV_INTERN
00898 byte*
00899 fsp_parse_init_file_page(
00900 /*=====================*/
00901   byte*   ptr,  
00902   byte*   /*end_ptr __attribute__((unused))*/, 
00903   buf_block_t*  block)  
00904 {
00905   ut_ad(ptr && end_ptr);
00906 
00907   if (block) {
00908     fsp_init_file_page_low(block);
00909   }
00910 
00911   return(ptr);
00912 }
00913 
00914 /**********************************************************************/
00916 UNIV_INTERN
00917 void
00918 fsp_init(void)
00919 /*==========*/
00920 {
00921   /* Does nothing at the moment */
00922 }
00923 
00924 /**********************************************************************/
00928 UNIV_INTERN
00929 void
00930 fsp_header_init_fields(
00931 /*===================*/
00932   page_t* page,   
00933   ulint space_id, 
00934   ulint flags)    
00936 {
00937   /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
00938   ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
00939   ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
00940   format, the tablespace flags should equal table->flags. */
00941   ut_a(flags != DICT_TF_COMPACT);
00942 
00943   mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
00944       space_id);
00945   mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
00946       flags);
00947 }
00948 
00949 #ifndef UNIV_HOTBACKUP
00950 /**********************************************************************/
00953 UNIV_INTERN
00954 void
00955 fsp_header_init(
00956 /*============*/
00957   ulint space,    
00958   ulint size,   
00959   mtr_t*  mtr)    
00960 {
00961   fsp_header_t* header;
00962   buf_block_t*  block;
00963   page_t*   page;
00964   ulint   flags;
00965   ulint   zip_size;
00966 
00967   ut_ad(mtr);
00968 
00969   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
00970 
00971   zip_size = dict_table_flags_to_zip_size(flags);
00972   block = buf_page_create(space, 0, zip_size, mtr);
00973   buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
00974   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
00975 
00976   /* The prior contents of the file page should be ignored */
00977 
00978   fsp_init_file_page(block, mtr);
00979   page = buf_block_get_frame(block);
00980 
00981   mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
00982        MLOG_2BYTES, mtr);
00983 
00984   header = FSP_HEADER_OFFSET + page;
00985 
00986   mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
00987   mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
00988 
00989   mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
00990   mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
00991   mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
00992        MLOG_4BYTES, mtr);
00993   mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
00994 
00995   flst_init(header + FSP_FREE, mtr);
00996   flst_init(header + FSP_FREE_FRAG, mtr);
00997   flst_init(header + FSP_FULL_FRAG, mtr);
00998   flst_init(header + FSP_SEG_INODES_FULL, mtr);
00999   flst_init(header + FSP_SEG_INODES_FREE, mtr);
01000 
01001   mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
01002   if (space == 0) {
01003     fsp_fill_free_list(FALSE, space, header, mtr);
01004     btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
01005          0, 0, DICT_IBUF_ID_MIN + space,
01006          dict_ind_redundant, mtr);
01007   } else {
01008     fsp_fill_free_list(TRUE, space, header, mtr);
01009   }
01010 }
01011 #endif /* !UNIV_HOTBACKUP */
01012 
01013 /**********************************************************************/
01016 UNIV_INTERN
01017 ulint
01018 fsp_header_get_space_id(
01019 /*====================*/
01020   const page_t* page) 
01021 {
01022   ulint fsp_id;
01023   ulint id;
01024 
01025   fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
01026 
01027   id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
01028 
01029   if (id != fsp_id) {
01030     fprintf(stderr,
01031       "InnoDB: Error: space id in fsp header %lu,"
01032       " but in the page header %lu\n",
01033       (ulong) fsp_id, (ulong) id);
01034 
01035     return(ULINT_UNDEFINED);
01036   }
01037 
01038   return(id);
01039 }
01040 
01041 /**********************************************************************/
01044 UNIV_INTERN
01045 ulint
01046 fsp_header_get_flags(
01047 /*=================*/
01048   const page_t* page) 
01049 {
01050   ut_ad(!page_offset(page));
01051 
01052   return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
01053 }
01054 
01055 /**********************************************************************/
01058 UNIV_INTERN
01059 ulint
01060 fsp_header_get_zip_size(
01061 /*====================*/
01062   const page_t* page) 
01063 {
01064   ulint flags = fsp_header_get_flags(page);
01065 
01066   return(dict_table_flags_to_zip_size(flags));
01067 }
01068 
01069 #ifndef UNIV_HOTBACKUP
01070 /**********************************************************************/
01072 UNIV_INTERN
01073 void
01074 fsp_header_inc_size(
01075 /*================*/
01076   ulint space,  
01077   ulint size_inc,
01078   mtr_t*  mtr)  
01079 {
01080   fsp_header_t* header;
01081   ulint   size;
01082   ulint   flags;
01083 
01084   ut_ad(mtr);
01085 
01086   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
01087 
01088   header = fsp_get_space_header(space,
01089               dict_table_flags_to_zip_size(flags),
01090               mtr);
01091 
01092   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01093 
01094   mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
01095        mtr);
01096 }
01097 
01098 /**********************************************************************/
01104 UNIV_INTERN
01105 ulint
01106 fsp_header_get_free_limit(void)
01107 /*===========================*/
01108 {
01109   fsp_header_t* header;
01110   ulint   limit;
01111   mtr_t   mtr;
01112 
01113   mtr_start(&mtr);
01114 
01115   mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
01116 
01117   header = fsp_get_space_header(0, 0, &mtr);
01118 
01119   limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
01120 
01121   limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
01122 
01123   log_fsp_current_free_limit_set_and_checkpoint(limit);
01124 
01125   mtr_commit(&mtr);
01126 
01127   return(limit);
01128 }
01129 
01130 /**********************************************************************/
01136 UNIV_INTERN
01137 ulint
01138 fsp_header_get_tablespace_size(void)
01139 /*================================*/
01140 {
01141   fsp_header_t* header;
01142   ulint   size;
01143   mtr_t   mtr;
01144 
01145   mtr_start(&mtr);
01146 
01147   mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
01148 
01149   header = fsp_get_space_header(0, 0, &mtr);
01150 
01151   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
01152 
01153   mtr_commit(&mtr);
01154 
01155   return(size);
01156 }
01157 
01158 /***********************************************************************/
01162 static
01163 ibool
01164 fsp_try_extend_data_file_with_pages(
01165 /*================================*/
01166   ulint   space,    
01167   ulint   page_no,  
01168   fsp_header_t* header,   
01169   mtr_t*    mtr)    
01170 {
01171   ibool success;
01172   ulint actual_size;
01173   ulint size;
01174 
01175   ut_a(space != 0);
01176 
01177   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01178 
01179   ut_a(page_no >= size);
01180 
01181   success = fil_extend_space_to_desired_size(&actual_size, space,
01182                page_no + 1);
01183   /* actual_size now has the space size in pages; it may be less than
01184   we wanted if we ran out of disk space */
01185 
01186   mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
01187 
01188   return(success);
01189 }
01190 
01191 /***********************************************************************/
01194 static
01195 ibool
01196 fsp_try_extend_data_file(
01197 /*=====================*/
01198   ulint*    actual_increase,
01203   ulint   space,    
01204   fsp_header_t* header,   
01205   mtr_t*    mtr)    
01206 {
01207   ulint size;
01208   ulint zip_size;
01209   ulint new_size;
01210   ulint old_size;
01211   ulint size_increase;
01212   ulint actual_size;
01213   ibool success;
01214 
01215   *actual_increase = 0;
01216 
01217   if (space == 0 && !srv_auto_extend_last_data_file) {
01218 
01219     /* We print the error message only once to avoid
01220     spamming the error log. Note that we don't need
01221     to reset the flag to FALSE as dealing with this
01222     error requires server restart. */
01223     if (fsp_tbs_full_error_printed == FALSE) {
01224       fprintf(stderr,
01225         "InnoDB: Error: Data file(s) ran"
01226         " out of space.\n"
01227         "Please add another data file or"
01228         " use \'autoextend\' for the last"
01229         " data file.\n");
01230       fsp_tbs_full_error_printed = TRUE;
01231     }
01232     return(FALSE);
01233   }
01234 
01235   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01236   zip_size = dict_table_flags_to_zip_size(
01237     mach_read_from_4(header + FSP_SPACE_FLAGS));
01238 
01239   old_size = size;
01240 
01241   if (space == 0) {
01242     if (!srv_last_file_size_max) {
01243       size_increase = SRV_AUTO_EXTEND_INCREMENT;
01244     } else {
01245       if (srv_last_file_size_max
01246           < srv_data_file_sizes[srv_n_data_files - 1]) {
01247 
01248         fprintf(stderr,
01249           "InnoDB: Error: Last data file size"
01250           " is %lu, max size allowed %lu\n",
01251           (ulong) srv_data_file_sizes[
01252             srv_n_data_files - 1],
01253           (ulong) srv_last_file_size_max);
01254       }
01255 
01256       size_increase = srv_last_file_size_max
01257         - srv_data_file_sizes[srv_n_data_files - 1];
01258       if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
01259         size_increase = SRV_AUTO_EXTEND_INCREMENT;
01260       }
01261     }
01262   } else {
01263     /* We extend single-table tablespaces first one extent
01264     at a time, but for bigger tablespaces more. It is not
01265     enough to extend always by one extent, because some
01266     extents are frag page extents. */
01267     ulint extent_size;  
01269     if (!zip_size) {
01270       extent_size = FSP_EXTENT_SIZE;
01271     } else {
01272       extent_size = FSP_EXTENT_SIZE
01273         * UNIV_PAGE_SIZE / zip_size;
01274     }
01275 
01276     if (size < extent_size) {
01277       /* Let us first extend the file to extent_size */
01278       success = fsp_try_extend_data_file_with_pages(
01279         space, extent_size - 1, header, mtr);
01280       if (!success) {
01281         new_size = mtr_read_ulint(header + FSP_SIZE,
01282                 MLOG_4BYTES, mtr);
01283 
01284         *actual_increase = new_size - old_size;
01285 
01286         return(FALSE);
01287       }
01288 
01289       size = extent_size;
01290     }
01291 
01292     if (size < 32 * extent_size) {
01293       size_increase = extent_size;
01294     } else {
01295       /* Below in fsp_fill_free_list() we assume
01296       that we add at most FSP_FREE_ADD extents at
01297       a time */
01298       size_increase = FSP_FREE_ADD * extent_size;
01299     }
01300   }
01301 
01302   if (size_increase == 0) {
01303 
01304     return(TRUE);
01305   }
01306 
01307   success = fil_extend_space_to_desired_size(&actual_size, space,
01308                size + size_increase);
01309   /* We ignore any fragments of a full megabyte when storing the size
01310   to the space header */
01311 
01312   if (!zip_size) {
01313     new_size = ut_calc_align_down(actual_size,
01314                 (1024 * 1024) / UNIV_PAGE_SIZE);
01315   } else {
01316     new_size = ut_calc_align_down(actual_size,
01317                 (1024 * 1024) / zip_size);
01318   }
01319   mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
01320 
01321   *actual_increase = new_size - old_size;
01322 
01323   return(TRUE);
01324 }
01325 
01326 /**********************************************************************/
01330 static
01331 void
01332 fsp_fill_free_list(
01333 /*===============*/
01334   ibool   init_space, 
01339   ulint   space,    
01340   fsp_header_t* header,   
01341   mtr_t*    mtr)    
01342 {
01343   ulint limit;
01344   ulint size;
01345   ulint zip_size;
01346   xdes_t* descr;
01347   ulint count   = 0;
01348   ulint frag_n_used;
01349   ulint actual_increase;
01350   ulint i;
01351   mtr_t ibuf_mtr;
01352 
01353   ut_ad(header && mtr);
01354   ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
01355 
01356   /* Check if we can fill free list from above the free list limit */
01357   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01358   limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
01359 
01360   zip_size = dict_table_flags_to_zip_size(
01361     mach_read_from_4(FSP_SPACE_FLAGS + header));
01362   ut_a(ut_is_2pow(zip_size));
01363   ut_a(zip_size <= UNIV_PAGE_SIZE);
01364   ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
01365 
01366   if (space == 0 && srv_auto_extend_last_data_file
01367       && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
01368 
01369     /* Try to increase the last data file size */
01370     fsp_try_extend_data_file(&actual_increase, space, header, mtr);
01371     size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01372   }
01373 
01374   if (space != 0 && !init_space
01375       && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
01376 
01377     /* Try to increase the .ibd file size */
01378     fsp_try_extend_data_file(&actual_increase, space, header, mtr);
01379     size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01380   }
01381 
01382   i = limit;
01383 
01384   while ((init_space && i < 1)
01385          || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
01386 
01387     ibool init_xdes;
01388     if (zip_size) {
01389       init_xdes = ut_2pow_remainder(i, zip_size) == 0;
01390     } else {
01391       init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
01392     }
01393 
01394     mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
01395          MLOG_4BYTES, mtr);
01396 
01397     /* Update the free limit info in the log system and make
01398     a checkpoint */
01399     if (space == 0) {
01400       ut_a(!zip_size);
01401       log_fsp_current_free_limit_set_and_checkpoint(
01402         (i + FSP_EXTENT_SIZE)
01403         / ((1024 * 1024) / UNIV_PAGE_SIZE));
01404     }
01405 
01406     if (UNIV_UNLIKELY(init_xdes)) {
01407 
01408       buf_block_t*  block;
01409 
01410       /* We are going to initialize a new descriptor page
01411       and a new ibuf bitmap page: the prior contents of the
01412       pages should be ignored. */
01413 
01414       if (i > 0) {
01415         block = buf_page_create(
01416           space, i, zip_size, mtr);
01417         buf_page_get(space, zip_size, i,
01418                RW_X_LATCH, mtr);
01419         buf_block_dbg_add_level(block,
01420               SYNC_FSP_PAGE);
01421 
01422         fsp_init_file_page(block, mtr);
01423         mlog_write_ulint(buf_block_get_frame(block)
01424              + FIL_PAGE_TYPE,
01425              FIL_PAGE_TYPE_XDES,
01426              MLOG_2BYTES, mtr);
01427       }
01428 
01429       /* Initialize the ibuf bitmap page in a separate
01430       mini-transaction because it is low in the latching
01431       order, and we must be able to release its latch
01432       before returning from the fsp routine */
01433 
01434       mtr_start(&ibuf_mtr);
01435 
01436       block = buf_page_create(space,
01437                 i + FSP_IBUF_BITMAP_OFFSET,
01438                 zip_size, &ibuf_mtr);
01439       buf_page_get(space, zip_size,
01440              i + FSP_IBUF_BITMAP_OFFSET,
01441              RW_X_LATCH, &ibuf_mtr);
01442       buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01443 
01444       fsp_init_file_page(block, &ibuf_mtr);
01445 
01446       ibuf_bitmap_page_init(block, &ibuf_mtr);
01447 
01448       mtr_commit(&ibuf_mtr);
01449     }
01450 
01451     descr = xdes_get_descriptor_with_space_hdr(header, space, i,
01452                  mtr);
01453     xdes_init(descr, mtr);
01454 
01455 #if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
01456 # error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
01457 #endif
01458 #if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
01459 # error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
01460 #endif
01461 
01462     if (UNIV_UNLIKELY(init_xdes)) {
01463 
01464       /* The first page in the extent is a descriptor page
01465       and the second is an ibuf bitmap page: mark them
01466       used */
01467 
01468       xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
01469       xdes_set_bit(descr, XDES_FREE_BIT,
01470              FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
01471       xdes_set_state(descr, XDES_FREE_FRAG, mtr);
01472 
01473       flst_add_last(header + FSP_FREE_FRAG,
01474               descr + XDES_FLST_NODE, mtr);
01475       frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
01476                  MLOG_4BYTES, mtr);
01477       mlog_write_ulint(header + FSP_FRAG_N_USED,
01478            frag_n_used + 2, MLOG_4BYTES, mtr);
01479     } else {
01480       flst_add_last(header + FSP_FREE,
01481               descr + XDES_FLST_NODE, mtr);
01482       count++;
01483     }
01484 
01485     i += FSP_EXTENT_SIZE;
01486   }
01487 }
01488 
01489 /**********************************************************************/
01492 static
01493 xdes_t*
01494 fsp_alloc_free_extent(
01495 /*==================*/
01496   ulint space,  
01497   ulint zip_size,
01499   ulint hint, 
01502   mtr_t*  mtr)  
01503 {
01504   fsp_header_t* header;
01505   fil_addr_t  first;
01506   xdes_t*   descr;
01507 
01508   ut_ad(mtr);
01509 
01510   header = fsp_get_space_header(space, zip_size, mtr);
01511 
01512   descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
01513 
01514   if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
01515     /* Ok, we can take this extent */
01516   } else {
01517     /* Take the first extent in the free list */
01518     first = flst_get_first(header + FSP_FREE, mtr);
01519 
01520     if (fil_addr_is_null(first)) {
01521       fsp_fill_free_list(FALSE, space, header, mtr);
01522 
01523       first = flst_get_first(header + FSP_FREE, mtr);
01524     }
01525 
01526     if (fil_addr_is_null(first)) {
01527 
01528       return(NULL); /* No free extents left */
01529     }
01530 
01531     descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
01532   }
01533 
01534   flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
01535 
01536   return(descr);
01537 }
01538 
01539 /**********************************************************************/
01542 static
01543 ulint
01544 fsp_alloc_free_page(
01545 /*================*/
01546   ulint space,  
01547   ulint zip_size,
01549   ulint hint, 
01550   mtr_t*  mtr)  
01551 {
01552   fsp_header_t* header;
01553   fil_addr_t  first;
01554   xdes_t*   descr;
01555   buf_block_t*  block;
01556   ulint   free;
01557   ulint   frag_n_used;
01558   ulint   page_no;
01559   ulint   space_size;
01560   ibool   success;
01561 
01562   ut_ad(mtr);
01563 
01564   header = fsp_get_space_header(space, zip_size, mtr);
01565 
01566   /* Get the hinted descriptor */
01567   descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
01568 
01569   if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
01570     /* Ok, we can take this extent */
01571   } else {
01572     /* Else take the first extent in free_frag list */
01573     first = flst_get_first(header + FSP_FREE_FRAG, mtr);
01574 
01575     if (fil_addr_is_null(first)) {
01576       /* There are no partially full fragments: allocate
01577       a free extent and add it to the FREE_FRAG list. NOTE
01578       that the allocation may have as a side-effect that an
01579       extent containing a descriptor page is added to the
01580       FREE_FRAG list. But we will allocate our page from the
01581       the free extent anyway. */
01582 
01583       descr = fsp_alloc_free_extent(space, zip_size,
01584                   hint, mtr);
01585 
01586       if (descr == NULL) {
01587         /* No free space left */
01588 
01589         return(FIL_NULL);
01590       }
01591 
01592       xdes_set_state(descr, XDES_FREE_FRAG, mtr);
01593       flst_add_last(header + FSP_FREE_FRAG,
01594               descr + XDES_FLST_NODE, mtr);
01595     } else {
01596       descr = xdes_lst_get_descriptor(space, zip_size,
01597               first, mtr);
01598     }
01599 
01600     /* Reset the hint */
01601     hint = 0;
01602   }
01603 
01604   /* Now we have in descr an extent with at least one free page. Look
01605   for a free page in the extent. */
01606 
01607   free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
01608            hint % FSP_EXTENT_SIZE, mtr);
01609   if (free == ULINT_UNDEFINED) {
01610 
01611     ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
01612     putc('\n', stderr);
01613 
01614     ut_error;
01615   }
01616 
01617   page_no = xdes_get_offset(descr) + free;
01618 
01619   space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
01620 
01621   if (space_size <= page_no) {
01622     /* It must be that we are extending a single-table tablespace
01623     whose size is still < 64 pages */
01624 
01625     ut_a(space != 0);
01626     if (page_no >= FSP_EXTENT_SIZE) {
01627       fprintf(stderr,
01628         "InnoDB: Error: trying to extend a"
01629         " single-table tablespace %lu\n"
01630         "InnoDB: by single page(s) though the"
01631         " space size %lu. Page no %lu.\n",
01632         (ulong) space, (ulong) space_size,
01633         (ulong) page_no);
01634       return(FIL_NULL);
01635     }
01636     success = fsp_try_extend_data_file_with_pages(space, page_no,
01637                     header, mtr);
01638     if (!success) {
01639       /* No disk space left */
01640       return(FIL_NULL);
01641     }
01642   }
01643 
01644   xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
01645 
01646   /* Update the FRAG_N_USED field */
01647   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
01648              mtr);
01649   frag_n_used++;
01650   mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
01651        mtr);
01652   if (xdes_is_full(descr, mtr)) {
01653     /* The fragment is full: move it to another list */
01654     flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
01655           mtr);
01656     xdes_set_state(descr, XDES_FULL_FRAG, mtr);
01657 
01658     flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
01659             mtr);
01660     mlog_write_ulint(header + FSP_FRAG_N_USED,
01661          frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
01662          mtr);
01663   }
01664 
01665   /* Initialize the allocated page to the buffer pool, so that it can
01666   be obtained immediately with buf_page_get without need for a disk
01667   read. */
01668 
01669   buf_page_create(space, page_no, zip_size, mtr);
01670 
01671   block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
01672   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01673 
01674   /* Prior contents of the page should be ignored */
01675   fsp_init_file_page(block, mtr);
01676 
01677   return(page_no);
01678 }
01679 
01680 /**********************************************************************/
01682 static
01683 void
01684 fsp_free_page(
01685 /*==========*/
01686   ulint space,  
01687   ulint zip_size,
01689   ulint page, 
01690   mtr_t*  mtr)  
01691 {
01692   fsp_header_t* header;
01693   xdes_t*   descr;
01694   ulint   state;
01695   ulint   frag_n_used;
01696 
01697   ut_ad(mtr);
01698 
01699   /* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
01700 
01701   header = fsp_get_space_header(space, zip_size, mtr);
01702 
01703   descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
01704 
01705   state = xdes_get_state(descr, mtr);
01706 
01707   if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
01708     fprintf(stderr,
01709       "InnoDB: Error: File space extent descriptor"
01710       " of page %lu has state %lu\n",
01711       (ulong) page,
01712       (ulong) state);
01713     fputs("InnoDB: Dump of descriptor: ", stderr);
01714     ut_print_buf(stderr, ((byte*)descr) - 50, 200);
01715     putc('\n', stderr);
01716 
01717     if (state == XDES_FREE) {
01718       /* We put here some fault tolerance: if the page
01719       is already free, return without doing anything! */
01720 
01721       return;
01722     }
01723 
01724     ut_error;
01725   }
01726 
01727   if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
01728     fprintf(stderr,
01729       "InnoDB: Error: File space extent descriptor"
01730       " of page %lu says it is free\n"
01731       "InnoDB: Dump of descriptor: ", (ulong) page);
01732     ut_print_buf(stderr, ((byte*)descr) - 50, 200);
01733     putc('\n', stderr);
01734 
01735     /* We put here some fault tolerance: if the page
01736     is already free, return without doing anything! */
01737 
01738     return;
01739   }
01740 
01741   xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
01742   xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
01743 
01744   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
01745              mtr);
01746   if (state == XDES_FULL_FRAG) {
01747     /* The fragment was full: move it to another list */
01748     flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
01749           mtr);
01750     xdes_set_state(descr, XDES_FREE_FRAG, mtr);
01751     flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
01752             mtr);
01753     mlog_write_ulint(header + FSP_FRAG_N_USED,
01754          frag_n_used + FSP_EXTENT_SIZE - 1,
01755          MLOG_4BYTES, mtr);
01756   } else {
01757     ut_a(frag_n_used > 0);
01758     mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
01759          MLOG_4BYTES, mtr);
01760   }
01761 
01762   if (xdes_is_free(descr, mtr)) {
01763     /* The extent has become free: move it to another list */
01764     flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
01765           mtr);
01766     fsp_free_extent(space, zip_size, page, mtr);
01767   }
01768 }
01769 
01770 /**********************************************************************/
01772 static
01773 void
01774 fsp_free_extent(
01775 /*============*/
01776   ulint space,  
01777   ulint zip_size,
01779   ulint page, 
01780   mtr_t*  mtr)  
01781 {
01782   fsp_header_t* header;
01783   xdes_t*   descr;
01784 
01785   ut_ad(mtr);
01786 
01787   header = fsp_get_space_header(space, zip_size, mtr);
01788 
01789   descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
01790 
01791   if (xdes_get_state(descr, mtr) == XDES_FREE) {
01792 
01793     ut_print_buf(stderr, (byte*)descr - 500, 1000);
01794     putc('\n', stderr);
01795 
01796     ut_error;
01797   }
01798 
01799   xdes_init(descr, mtr);
01800 
01801   flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
01802 }
01803 
01804 /**********************************************************************/
01807 UNIV_INLINE
01808 fseg_inode_t*
01809 fsp_seg_inode_page_get_nth_inode(
01810 /*=============================*/
01811   page_t* page, 
01812   ulint i,  
01813   ulint /*zip_size __attribute__((unused))*/,
01815   mtr_t*  /*mtr __attribute__((unused))*/)
01817 {
01818   ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
01819   ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
01820 
01821   return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
01822 }
01823 
01824 /**********************************************************************/
01827 static
01828 ulint
01829 fsp_seg_inode_page_find_used(
01830 /*=========================*/
01831   page_t* page, 
01832   ulint zip_size,
01833   mtr_t*  mtr)  
01834 {
01835   ulint   i;
01836   fseg_inode_t* inode;
01837 
01838   for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
01839 
01840     inode = fsp_seg_inode_page_get_nth_inode(
01841       page, i, zip_size, mtr);
01842 
01843     if (mach_read_from_8(inode + FSEG_ID)) {
01844       /* This is used */
01845 
01846       ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
01847             == FSEG_MAGIC_N_VALUE);
01848       return(i);
01849     }
01850   }
01851 
01852   return(ULINT_UNDEFINED);
01853 }
01854 
01855 /**********************************************************************/
01858 static
01859 ulint
01860 fsp_seg_inode_page_find_free(
01861 /*=========================*/
01862   page_t* page, 
01863   ulint i,  
01864   ulint zip_size,
01865   mtr_t*  mtr)  
01866 {
01867   fseg_inode_t* inode;
01868 
01869   for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
01870 
01871     inode = fsp_seg_inode_page_get_nth_inode(
01872       page, i, zip_size, mtr);
01873 
01874     if (!mach_read_from_8(inode + FSEG_ID)) {
01875       /* This is unused */
01876 
01877       return(i);
01878     }
01879 
01880     ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
01881           == FSEG_MAGIC_N_VALUE);
01882   }
01883 
01884   return(ULINT_UNDEFINED);
01885 }
01886 
01887 /**********************************************************************/
01890 static
01891 ibool
01892 fsp_alloc_seg_inode_page(
01893 /*=====================*/
01894   fsp_header_t* space_header, 
01895   mtr_t*    mtr)    
01896 {
01897   fseg_inode_t* inode;
01898   buf_block_t*  block;
01899   page_t*   page;
01900   ulint   page_no;
01901   ulint   space;
01902   ulint   zip_size;
01903   ulint   i;
01904 
01905   ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
01906 
01907   space = page_get_space_id(page_align(space_header));
01908   zip_size = dict_table_flags_to_zip_size(
01909     mach_read_from_4(FSP_SPACE_FLAGS + space_header));
01910 
01911   page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
01912 
01913   if (page_no == FIL_NULL) {
01914 
01915     return(FALSE);
01916   }
01917 
01918   block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
01919   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01920 
01921   block->check_index_page_at_flush = FALSE;
01922 
01923   page = buf_block_get_frame(block);
01924 
01925   mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
01926        MLOG_2BYTES, mtr);
01927 
01928   for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
01929 
01930     inode = fsp_seg_inode_page_get_nth_inode(page, i,
01931                zip_size, mtr);
01932 
01933     mlog_write_ull(inode + FSEG_ID, 0, mtr);
01934   }
01935 
01936   flst_add_last(space_header + FSP_SEG_INODES_FREE,
01937           page + FSEG_INODE_PAGE_NODE, mtr);
01938   return(TRUE);
01939 }
01940 
01941 /**********************************************************************/
01944 static
01945 fseg_inode_t*
01946 fsp_alloc_seg_inode(
01947 /*================*/
01948   fsp_header_t* space_header, 
01949   mtr_t*    mtr)    
01950 {
01951   ulint   page_no;
01952   buf_block_t*  block;
01953   page_t*   page;
01954   fseg_inode_t* inode;
01955   ibool   success;
01956   ulint   zip_size;
01957   ulint   n;
01958 
01959   ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
01960 
01961   if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
01962     /* Allocate a new segment inode page */
01963 
01964     success = fsp_alloc_seg_inode_page(space_header, mtr);
01965 
01966     if (!success) {
01967 
01968       return(NULL);
01969     }
01970   }
01971 
01972   page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
01973 
01974   zip_size = dict_table_flags_to_zip_size(
01975     mach_read_from_4(FSP_SPACE_FLAGS + space_header));
01976   block = buf_page_get(page_get_space_id(page_align(space_header)),
01977            zip_size, page_no, RW_X_LATCH, mtr);
01978   buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
01979 
01980   page = buf_block_get_frame(block);
01981 
01982   n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
01983 
01984   ut_a(n != ULINT_UNDEFINED);
01985 
01986   inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
01987 
01988   if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
01989                   zip_size, mtr)) {
01990     /* There are no other unused headers left on the page: move it
01991     to another list */
01992 
01993     flst_remove(space_header + FSP_SEG_INODES_FREE,
01994           page + FSEG_INODE_PAGE_NODE, mtr);
01995 
01996     flst_add_last(space_header + FSP_SEG_INODES_FULL,
01997             page + FSEG_INODE_PAGE_NODE, mtr);
01998   }
01999 
02000   ut_ad(!mach_read_from_8(inode + FSEG_ID)
02001         || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02002   return(inode);
02003 }
02004 
02005 /**********************************************************************/
02007 static
02008 void
02009 fsp_free_seg_inode(
02010 /*===============*/
02011   ulint   space,  
02012   ulint   zip_size,
02014   fseg_inode_t* inode,  
02015   mtr_t*    mtr)  
02016 {
02017   page_t*   page;
02018   fsp_header_t* space_header;
02019 
02020   page = page_align(inode);
02021 
02022   space_header = fsp_get_space_header(space, zip_size, mtr);
02023 
02024   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02025 
02026   if (ULINT_UNDEFINED
02027       == fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
02028 
02029     /* Move the page to another list */
02030 
02031     flst_remove(space_header + FSP_SEG_INODES_FULL,
02032           page + FSEG_INODE_PAGE_NODE, mtr);
02033 
02034     flst_add_last(space_header + FSP_SEG_INODES_FREE,
02035             page + FSEG_INODE_PAGE_NODE, mtr);
02036   }
02037 
02038   mlog_write_ull(inode + FSEG_ID, 0, mtr);
02039   mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
02040 
02041   if (ULINT_UNDEFINED
02042       == fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
02043 
02044     /* There are no other used headers left on the page: free it */
02045 
02046     flst_remove(space_header + FSP_SEG_INODES_FREE,
02047           page + FSEG_INODE_PAGE_NODE, mtr);
02048 
02049     fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
02050   }
02051 }
02052 
02053 /**********************************************************************/
02056 static
02057 fseg_inode_t*
02058 fseg_inode_try_get(
02059 /*===============*/
02060   fseg_header_t*  header, 
02061   ulint   space,  
02062   ulint   zip_size,
02064   mtr_t*    mtr)  
02065 {
02066   fil_addr_t  inode_addr;
02067   fseg_inode_t* inode;
02068 
02069   inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
02070   inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
02071   ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
02072 
02073   inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
02074 
02075   if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
02076 
02077     inode = NULL;
02078   } else {
02079     ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
02080           == FSEG_MAGIC_N_VALUE);
02081   }
02082 
02083   return(inode);
02084 }
02085 
02086 /**********************************************************************/
02089 static
02090 fseg_inode_t*
02091 fseg_inode_get(
02092 /*===========*/
02093   fseg_header_t*  header, 
02094   ulint   space,  
02095   ulint   zip_size,
02097   mtr_t*    mtr)  
02098 {
02099   fseg_inode_t* inode
02100     = fseg_inode_try_get(header, space, zip_size, mtr);
02101   ut_a(inode);
02102   return(inode);
02103 }
02104 
02105 /**********************************************************************/
02108 UNIV_INLINE
02109 ulint
02110 fseg_get_nth_frag_page_no(
02111 /*======================*/
02112   fseg_inode_t* inode,  
02113   ulint   n,  
02114   mtr_t*    /*mtr __attribute__((unused))*/) 
02115 {
02116   ut_ad(inode && mtr);
02117   ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
02118   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
02119   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02120   return(mach_read_from_4(inode + FSEG_FRAG_ARR
02121         + n * FSEG_FRAG_SLOT_SIZE));
02122 }
02123 
02124 /**********************************************************************/
02126 UNIV_INLINE
02127 void
02128 fseg_set_nth_frag_page_no(
02129 /*======================*/
02130   fseg_inode_t* inode,  
02131   ulint   n,  
02132   ulint   page_no,
02133   mtr_t*    mtr)  
02134 {
02135   ut_ad(inode && mtr);
02136   ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
02137   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
02138   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02139 
02140   mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
02141        page_no, MLOG_4BYTES, mtr);
02142 }
02143 
02144 /**********************************************************************/
02147 static
02148 ulint
02149 fseg_find_free_frag_page_slot(
02150 /*==========================*/
02151   fseg_inode_t* inode,  
02152   mtr_t*    mtr)  
02153 {
02154   ulint i;
02155   ulint page_no;
02156 
02157   ut_ad(inode && mtr);
02158 
02159   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02160     page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
02161 
02162     if (page_no == FIL_NULL) {
02163 
02164       return(i);
02165     }
02166   }
02167 
02168   return(ULINT_UNDEFINED);
02169 }
02170 
02171 /**********************************************************************/
02174 static
02175 ulint
02176 fseg_find_last_used_frag_page_slot(
02177 /*===============================*/
02178   fseg_inode_t* inode,  
02179   mtr_t*    mtr)  
02180 {
02181   ulint i;
02182   ulint page_no;
02183 
02184   ut_ad(inode && mtr);
02185 
02186   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02187     page_no = fseg_get_nth_frag_page_no(
02188       inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
02189 
02190     if (page_no != FIL_NULL) {
02191 
02192       return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
02193     }
02194   }
02195 
02196   return(ULINT_UNDEFINED);
02197 }
02198 
02199 /**********************************************************************/
02202 static
02203 ulint
02204 fseg_get_n_frag_pages(
02205 /*==================*/
02206   fseg_inode_t* inode,  
02207   mtr_t*    mtr)  
02208 {
02209   ulint i;
02210   ulint count = 0;
02211 
02212   ut_ad(inode && mtr);
02213 
02214   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02215     if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
02216       count++;
02217     }
02218   }
02219 
02220   return(count);
02221 }
02222 
02223 /**********************************************************************/
02227 UNIV_INTERN
02228 buf_block_t*
02229 fseg_create_general(
02230 /*================*/
02231   ulint space,  
02232   ulint page, 
02236   ulint byte_offset, 
02238   ibool has_done_reservation, 
02244   mtr_t*  mtr)  
02245 {
02246   ulint   flags;
02247   ulint   zip_size;
02248   fsp_header_t* space_header;
02249   fseg_inode_t* inode;
02250   ib_id_t   seg_id;
02251   buf_block_t*  block = 0; /* remove warning */
02252   fseg_header_t*  header  = 0; /* remove warning */
02253   rw_lock_t*  latch;
02254   ibool   success;
02255   ulint   n_reserved;
02256   ulint   i;
02257 
02258   ut_ad(mtr);
02259   ut_ad(byte_offset + FSEG_HEADER_SIZE
02260         <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
02261 
02262   latch = fil_space_get_latch(space, &flags);
02263   zip_size = dict_table_flags_to_zip_size(flags);
02264 
02265   if (page != 0) {
02266     block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
02267     header = byte_offset + buf_block_get_frame(block);
02268   }
02269 
02270   ut_ad(!mutex_own(&kernel_mutex)
02271         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02272 
02273   mtr_x_lock(latch, mtr);
02274 
02275   if (rw_lock_get_x_lock_count(latch) == 1) {
02276     /* This thread did not own the latch before this call: free
02277     excess pages from the insert buffer free list */
02278 
02279     if (space == IBUF_SPACE_ID) {
02280       ibuf_free_excess_pages();
02281     }
02282   }
02283 
02284   if (!has_done_reservation) {
02285     success = fsp_reserve_free_extents(&n_reserved, space, 2,
02286                FSP_NORMAL, mtr);
02287     if (!success) {
02288       return(NULL);
02289     }
02290   }
02291 
02292   space_header = fsp_get_space_header(space, zip_size, mtr);
02293 
02294   inode = fsp_alloc_seg_inode(space_header, mtr);
02295 
02296   if (inode == NULL) {
02297 
02298     goto funct_exit;
02299   }
02300 
02301   /* Read the next segment id from space header and increment the
02302   value in space header */
02303 
02304   seg_id = mach_read_from_8(space_header + FSP_SEG_ID);
02305 
02306   mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr);
02307 
02308   mlog_write_ull(inode + FSEG_ID, seg_id, mtr);
02309   mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
02310 
02311   flst_init(inode + FSEG_FREE, mtr);
02312   flst_init(inode + FSEG_NOT_FULL, mtr);
02313   flst_init(inode + FSEG_FULL, mtr);
02314 
02315   mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
02316        MLOG_4BYTES, mtr);
02317   for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
02318     fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
02319   }
02320 
02321   if (page == 0) {
02322     page = fseg_alloc_free_page_low(space, zip_size,
02323             inode, 0, FSP_UP, mtr);
02324 
02325     if (page == FIL_NULL) {
02326 
02327       fsp_free_seg_inode(space, zip_size, inode, mtr);
02328 
02329       goto funct_exit;
02330     }
02331 
02332     block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
02333     header = byte_offset + buf_block_get_frame(block);
02334     mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
02335          FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
02336   }
02337 
02338   mlog_write_ulint(header + FSEG_HDR_OFFSET,
02339        page_offset(inode), MLOG_2BYTES, mtr);
02340 
02341   mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
02342        page_get_page_no(page_align(inode)),
02343        MLOG_4BYTES, mtr);
02344 
02345   mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
02346 
02347 funct_exit:
02348   if (!has_done_reservation) {
02349 
02350     fil_space_release_free_extents(space, n_reserved);
02351   }
02352 
02353   return(block);
02354 }
02355 
02356 /**********************************************************************/
02360 UNIV_INTERN
02361 buf_block_t*
02362 fseg_create(
02363 /*========*/
02364   ulint space,  
02365   ulint page, 
02369   ulint byte_offset, 
02371   mtr_t*  mtr)  
02372 {
02373   return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
02374 }
02375 
02376 /**********************************************************************/
02380 static
02381 ulint
02382 fseg_n_reserved_pages_low(
02383 /*======================*/
02384   fseg_inode_t* inode,  
02385   ulint*    used, 
02387   mtr_t*    mtr)  
02388 {
02389   ulint ret;
02390 
02391   ut_ad(inode && used && mtr);
02392   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
02393 
02394   *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
02395     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
02396     + fseg_get_n_frag_pages(inode, mtr);
02397 
02398   ret = fseg_get_n_frag_pages(inode, mtr)
02399     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
02400     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
02401     + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
02402 
02403   return(ret);
02404 }
02405 
02406 /**********************************************************************/
02410 UNIV_INTERN
02411 ulint
02412 fseg_n_reserved_pages(
02413 /*==================*/
02414   fseg_header_t*  header, 
02415   ulint*    used, 
02416   mtr_t*    mtr)  
02417 {
02418   ulint   ret;
02419   fseg_inode_t* inode;
02420   ulint   space;
02421   ulint   flags;
02422   ulint   zip_size;
02423   rw_lock_t*  latch;
02424 
02425   space = page_get_space_id(page_align(header));
02426   latch = fil_space_get_latch(space, &flags);
02427   zip_size = dict_table_flags_to_zip_size(flags);
02428 
02429   ut_ad(!mutex_own(&kernel_mutex)
02430         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02431 
02432   mtr_x_lock(latch, mtr);
02433 
02434   inode = fseg_inode_get(header, space, zip_size, mtr);
02435 
02436   ret = fseg_n_reserved_pages_low(inode, used, mtr);
02437 
02438   return(ret);
02439 }
02440 
02441 /*********************************************************************/
02446 static
02447 void
02448 fseg_fill_free_list(
02449 /*================*/
02450   fseg_inode_t* inode,  
02451   ulint   space,  
02452   ulint   zip_size,
02454   ulint   hint, 
02456   mtr_t*    mtr)  
02457 {
02458   xdes_t* descr;
02459   ulint i;
02460   ib_id_t seg_id;
02461   ulint reserved;
02462   ulint used;
02463 
02464   ut_ad(inode && mtr);
02465   ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
02466 
02467   reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
02468 
02469   if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
02470 
02471     /* The segment is too small to allow extents in free list */
02472 
02473     return;
02474   }
02475 
02476   if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
02477     /* Free list is not empty */
02478 
02479     return;
02480   }
02481 
02482   for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
02483     descr = xdes_get_descriptor(space, zip_size, hint, mtr);
02484 
02485     if ((descr == NULL)
02486         || (XDES_FREE != xdes_get_state(descr, mtr))) {
02487 
02488       /* We cannot allocate the desired extent: stop */
02489 
02490       return;
02491     }
02492 
02493     descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
02494 
02495     xdes_set_state(descr, XDES_FSEG, mtr);
02496 
02497     seg_id = mach_read_from_8(inode + FSEG_ID);
02498     ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
02499           == FSEG_MAGIC_N_VALUE);
02500     mlog_write_ull(descr + XDES_ID, seg_id, mtr);
02501 
02502     flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
02503     hint += FSP_EXTENT_SIZE;
02504   }
02505 }
02506 
02507 /*********************************************************************/
02513 static
02514 xdes_t*
02515 fseg_alloc_free_extent(
02516 /*===================*/
02517   fseg_inode_t* inode,  
02518   ulint   space,  
02519   ulint   zip_size,
02521   mtr_t*    mtr)  
02522 {
02523   xdes_t*   descr;
02524   ib_id_t   seg_id;
02525   fil_addr_t  first;
02526 
02527   ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
02528   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
02529 
02530   if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
02531     /* Segment free list is not empty, allocate from it */
02532 
02533     first = flst_get_first(inode + FSEG_FREE, mtr);
02534 
02535     descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
02536   } else {
02537     /* Segment free list was empty, allocate from space */
02538     descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
02539 
02540     if (descr == NULL) {
02541 
02542       return(NULL);
02543     }
02544 
02545     seg_id = mach_read_from_8(inode + FSEG_ID);
02546 
02547     xdes_set_state(descr, XDES_FSEG, mtr);
02548     mlog_write_ull(descr + XDES_ID, seg_id, mtr);
02549     flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
02550 
02551     /* Try to fill the segment free list */
02552     fseg_fill_free_list(inode, space, zip_size,
02553             xdes_get_offset(descr) + FSP_EXTENT_SIZE,
02554             mtr);
02555   }
02556 
02557   return(descr);
02558 }
02559 
02560 /**********************************************************************/
02565 static
02566 ulint
02567 fseg_alloc_free_page_low(
02568 /*=====================*/
02569   ulint   space,  
02570   ulint   zip_size,
02572   fseg_inode_t* seg_inode, 
02573   ulint   hint, 
02574   byte    direction, 
02579   mtr_t*    mtr)  
02580 {
02581   fsp_header_t* space_header;
02582   ulint   space_size;
02583   ib_id_t   seg_id;
02584   ulint   used;
02585   ulint   reserved;
02586   xdes_t*   descr;    
02587   ulint   ret_page; 
02589   xdes_t*   ret_descr;  
02590   ibool   frag_page_allocated = FALSE;
02591   ibool   success;
02592   ulint   n;
02593 
02594   ut_ad(mtr);
02595   ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
02596   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
02597         == FSEG_MAGIC_N_VALUE);
02598   ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
02599   seg_id = mach_read_from_8(seg_inode + FSEG_ID);
02600 
02601   ut_ad(seg_id);
02602 
02603   reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
02604 
02605   space_header = fsp_get_space_header(space, zip_size, mtr);
02606 
02607   descr = xdes_get_descriptor_with_space_hdr(space_header, space,
02608                hint, mtr);
02609   if (descr == NULL) {
02610     /* Hint outside space or too high above free limit: reset
02611     hint */
02612     hint = 0;
02613     descr = xdes_get_descriptor(space, zip_size, hint, mtr);
02614   }
02615 
02616   /* In the big if-else below we look for ret_page and ret_descr */
02617   /*-------------------------------------------------------------*/
02618   if ((xdes_get_state(descr, mtr) == XDES_FSEG)
02619       && mach_read_from_8(descr + XDES_ID) == seg_id
02620       && (xdes_get_bit(descr, XDES_FREE_BIT,
02621            hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
02622 
02623     /* 1. We can take the hinted page
02624     =================================*/
02625     ret_descr = descr;
02626     ret_page = hint;
02627     /*-----------------------------------------------------------*/
02628   } else if ((xdes_get_state(descr, mtr) == XDES_FREE)
02629        && ((reserved - used) < reserved / FSEG_FILLFACTOR)
02630        && (used >= FSEG_FRAG_LIMIT)) {
02631 
02632     /* 2. We allocate the free extent from space and can take
02633     =========================================================
02634     the hinted page
02635     ===============*/
02636     ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
02637 
02638     ut_a(ret_descr == descr);
02639 
02640     xdes_set_state(ret_descr, XDES_FSEG, mtr);
02641     mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
02642     flst_add_last(seg_inode + FSEG_FREE,
02643             ret_descr + XDES_FLST_NODE, mtr);
02644 
02645     /* Try to fill the segment free list */
02646     fseg_fill_free_list(seg_inode, space, zip_size,
02647             hint + FSP_EXTENT_SIZE, mtr);
02648     ret_page = hint;
02649     /*-----------------------------------------------------------*/
02650   } else if ((direction != FSP_NO_DIR)
02651        && ((reserved - used) < reserved / FSEG_FILLFACTOR)
02652        && (used >= FSEG_FRAG_LIMIT)
02653        && (!!(ret_descr
02654         = fseg_alloc_free_extent(seg_inode,
02655                space, zip_size, mtr)))) {
02656 
02657     /* 3. We take any free extent (which was already assigned above
02658     ===============================================================
02659     in the if-condition to ret_descr) and take the lowest or
02660     ========================================================
02661     highest page in it, depending on the direction
02662     ==============================================*/
02663     ret_page = xdes_get_offset(ret_descr);
02664 
02665     if (direction == FSP_DOWN) {
02666       ret_page += FSP_EXTENT_SIZE - 1;
02667     }
02668     /*-----------------------------------------------------------*/
02669   } else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
02670        && mach_read_from_8(descr + XDES_ID) == seg_id
02671        && (!xdes_is_full(descr, mtr))) {
02672 
02673     /* 4. We can take the page from the same extent as the
02674     ======================================================
02675     hinted page (and the extent already belongs to the
02676     ==================================================
02677     segment)
02678     ========*/
02679     ret_descr = descr;
02680     ret_page = xdes_get_offset(ret_descr)
02681       + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
02682           hint % FSP_EXTENT_SIZE, mtr);
02683     /*-----------------------------------------------------------*/
02684   } else if (reserved - used > 0) {
02685     /* 5. We take any unused page from the segment
02686     ==============================================*/
02687     fil_addr_t  first;
02688 
02689     if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
02690       first = flst_get_first(seg_inode + FSEG_NOT_FULL,
02691                  mtr);
02692     } else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
02693       first = flst_get_first(seg_inode + FSEG_FREE, mtr);
02694     } else {
02695       ut_error;
02696       return(FIL_NULL);
02697     }
02698 
02699     ret_descr = xdes_lst_get_descriptor(space, zip_size,
02700                 first, mtr);
02701     ret_page = xdes_get_offset(ret_descr)
02702       + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
02703           0, mtr);
02704     /*-----------------------------------------------------------*/
02705   } else if (used < FSEG_FRAG_LIMIT) {
02706     /* 6. We allocate an individual page from the space
02707     ===================================================*/
02708     ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
02709     ret_descr = NULL;
02710 
02711     frag_page_allocated = TRUE;
02712 
02713     if (ret_page != FIL_NULL) {
02714       /* Put the page in the fragment page array of the
02715       segment */
02716       n = fseg_find_free_frag_page_slot(seg_inode, mtr);
02717       ut_a(n != FIL_NULL);
02718 
02719       fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
02720               mtr);
02721     }
02722     /*-----------------------------------------------------------*/
02723   } else {
02724     /* 7. We allocate a new extent and take its first page
02725     ======================================================*/
02726     ret_descr = fseg_alloc_free_extent(seg_inode,
02727                space, zip_size, mtr);
02728 
02729     if (ret_descr == NULL) {
02730       ret_page = FIL_NULL;
02731     } else {
02732       ret_page = xdes_get_offset(ret_descr);
02733     }
02734   }
02735 
02736   if (ret_page == FIL_NULL) {
02737     /* Page could not be allocated */
02738 
02739     return(FIL_NULL);
02740   }
02741 
02742   if (space != 0) {
02743     space_size = fil_space_get_size(space);
02744 
02745     if (space_size <= ret_page) {
02746       /* It must be that we are extending a single-table
02747       tablespace whose size is still < 64 pages */
02748 
02749       if (ret_page >= FSP_EXTENT_SIZE) {
02750         fprintf(stderr,
02751           "InnoDB: Error (2): trying to extend"
02752           " a single-table tablespace %lu\n"
02753           "InnoDB: by single page(s) though"
02754           " the space size %lu. Page no %lu.\n",
02755           (ulong) space, (ulong) space_size,
02756           (ulong) ret_page);
02757         return(FIL_NULL);
02758       }
02759 
02760       success = fsp_try_extend_data_file_with_pages(
02761         space, ret_page, space_header, mtr);
02762       if (!success) {
02763         /* No disk space left */
02764         return(FIL_NULL);
02765       }
02766     }
02767   }
02768 
02769   if (!frag_page_allocated) {
02770     /* Initialize the allocated page to buffer pool, so that it
02771     can be obtained immediately with buf_page_get without need
02772     for a disk read */
02773     buf_block_t*  block;
02774     ulint   page_zip_size = dict_table_flags_to_zip_size(
02775       mach_read_from_4(FSP_SPACE_FLAGS + space_header));
02776 
02777     block = buf_page_create(space, ret_page, page_zip_size, mtr);
02778     buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
02779 
02780     if (UNIV_UNLIKELY(block != buf_page_get(space, page_zip_size,
02781               ret_page, RW_X_LATCH,
02782               mtr))) {
02783       ut_error;
02784     }
02785 
02786     /* The prior contents of the page should be ignored */
02787     fsp_init_file_page(block, mtr);
02788 
02789     /* At this point we know the extent and the page offset.
02790     The extent is still in the appropriate list (FSEG_NOT_FULL
02791     or FSEG_FREE), and the page is not yet marked as used. */
02792 
02793     ut_ad(xdes_get_descriptor(space, page_zip_size, ret_page, mtr)
02794           == ret_descr);
02795     ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
02796            ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
02797 
02798     fseg_mark_page_used(seg_inode, space, page_zip_size, ret_page, mtr);
02799   }
02800 
02801   buf_reset_check_index_page_at_flush(space, ret_page);
02802 
02803   return(ret_page);
02804 }
02805 
02806 /**********************************************************************/
02811 UNIV_INTERN
02812 ulint
02813 fseg_alloc_free_page_general(
02814 /*=========================*/
02815   fseg_header_t*  seg_header,
02816   ulint   hint, 
02817   byte    direction,
02822   ibool   has_done_reservation, 
02827   mtr_t*    mtr)  
02828 {
02829   fseg_inode_t* inode;
02830   ulint   space;
02831   ulint   flags;
02832   ulint   zip_size;
02833   rw_lock_t*  latch;
02834   ibool   success;
02835   ulint   page_no;
02836   ulint   n_reserved;
02837 
02838   space = page_get_space_id(page_align(seg_header));
02839 
02840   latch = fil_space_get_latch(space, &flags);
02841 
02842   zip_size = dict_table_flags_to_zip_size(flags);
02843 
02844   ut_ad(!mutex_own(&kernel_mutex)
02845         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02846 
02847   mtr_x_lock(latch, mtr);
02848 
02849   if (rw_lock_get_x_lock_count(latch) == 1) {
02850     /* This thread did not own the latch before this call: free
02851     excess pages from the insert buffer free list */
02852 
02853     if (space == IBUF_SPACE_ID) {
02854       ibuf_free_excess_pages();
02855     }
02856   }
02857 
02858   inode = fseg_inode_get(seg_header, space, zip_size, mtr);
02859 
02860   if (!has_done_reservation) {
02861     success = fsp_reserve_free_extents(&n_reserved, space, 2,
02862                FSP_NORMAL, mtr);
02863     if (!success) {
02864       return(FIL_NULL);
02865     }
02866   }
02867 
02868   page_no = fseg_alloc_free_page_low(space, zip_size,
02869              inode, hint, direction, mtr);
02870   if (!has_done_reservation) {
02871     fil_space_release_free_extents(space, n_reserved);
02872   }
02873 
02874   return(page_no);
02875 }
02876 
02877 /**********************************************************************/
02882 UNIV_INTERN
02883 ulint
02884 fseg_alloc_free_page(
02885 /*=================*/
02886   fseg_header_t*  seg_header,
02887   ulint   hint, 
02888   byte    direction,
02893   mtr_t*    mtr)  
02894 {
02895   return(fseg_alloc_free_page_general(seg_header, hint, direction,
02896               FALSE, mtr));
02897 }
02898 
02899 /**********************************************************************/
02906 static
02907 ibool
02908 fsp_reserve_free_pages(
02909 /*===================*/
02910   ulint   space,    
02911   fsp_header_t* space_header, 
02913   ulint   size,   
02915   mtr_t*    mtr)    
02916 {
02917   xdes_t* descr;
02918   ulint n_used;
02919 
02920   ut_a(space != 0);
02921   ut_a(size < FSP_EXTENT_SIZE / 2);
02922 
02923   descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
02924                mtr);
02925   n_used = xdes_get_n_used(descr, mtr);
02926 
02927   ut_a(n_used <= size);
02928 
02929   if (size >= n_used + 2) {
02930 
02931     return(TRUE);
02932   }
02933 
02934   return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
02935                space_header, mtr));
02936 }
02937 
02938 /**********************************************************************/
02964 UNIV_INTERN
02965 ibool
02966 fsp_reserve_free_extents(
02967 /*=====================*/
02968   ulint*  n_reserved,
02971   ulint space,  
02972   ulint n_ext,  
02973   ulint alloc_type,
02974   mtr_t*  mtr)  
02975 {
02976   fsp_header_t* space_header;
02977   rw_lock_t*  latch;
02978   ulint   n_free_list_ext;
02979   ulint   free_limit;
02980   ulint   size;
02981   ulint   flags;
02982   ulint   zip_size;
02983   ulint   n_free;
02984   ulint   n_free_up;
02985   ulint   reserve;
02986   ibool   success;
02987   ulint   n_pages_added;
02988 
02989   ut_ad(mtr);
02990   *n_reserved = n_ext;
02991 
02992   latch = fil_space_get_latch(space, &flags);
02993   zip_size = dict_table_flags_to_zip_size(flags);
02994 
02995   ut_ad(!mutex_own(&kernel_mutex)
02996         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
02997 
02998   mtr_x_lock(latch, mtr);
02999 
03000   space_header = fsp_get_space_header(space, zip_size, mtr);
03001 try_again:
03002   size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
03003 
03004   if (size < FSP_EXTENT_SIZE / 2) {
03005     /* Use different rules for small single-table tablespaces */
03006     *n_reserved = 0;
03007     return(fsp_reserve_free_pages(space, space_header, size, mtr));
03008   }
03009 
03010   n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
03011 
03012   free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
03013             MLOG_4BYTES, mtr);
03014 
03015   /* Below we play safe when counting free extents above the free limit:
03016   some of them will contain extent descriptor pages, and therefore
03017   will not be free extents */
03018 
03019   n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
03020 
03021   if (n_free_up > 0) {
03022     n_free_up--;
03023     if (!zip_size) {
03024       n_free_up -= n_free_up
03025         / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
03026     } else {
03027       n_free_up -= n_free_up
03028         / (zip_size / FSP_EXTENT_SIZE);
03029     }
03030   }
03031 
03032   n_free = n_free_list_ext + n_free_up;
03033 
03034   if (alloc_type == FSP_NORMAL) {
03035     /* We reserve 1 extent + 0.5 % of the space size to undo logs
03036     and 1 extent + 0.5 % to cleaning operations; NOTE: this source
03037     code is duplicated in the function below! */
03038 
03039     reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
03040 
03041     if (n_free <= reserve + n_ext) {
03042 
03043       goto try_to_extend;
03044     }
03045   } else if (alloc_type == FSP_UNDO) {
03046     /* We reserve 0.5 % of the space size to cleaning operations */
03047 
03048     reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
03049 
03050     if (n_free <= reserve + n_ext) {
03051 
03052       goto try_to_extend;
03053     }
03054   } else {
03055     ut_a(alloc_type == FSP_CLEANING);
03056   }
03057 
03058   success = fil_space_reserve_free_extents(space, n_free, n_ext);
03059 
03060   if (success) {
03061     return(TRUE);
03062   }
03063 try_to_extend:
03064   success = fsp_try_extend_data_file(&n_pages_added, space,
03065              space_header, mtr);
03066   if (success && n_pages_added > 0) {
03067 
03068     goto try_again;
03069   }
03070 
03071   return(FALSE);
03072 }
03073 
03074 /**********************************************************************/
03080 UNIV_INTERN
03081 ullint
03082 fsp_get_available_space_in_free_extents(
03083 /*====================================*/
03084   ulint space)  
03085 {
03086   fsp_header_t* space_header;
03087   ulint   n_free_list_ext;
03088   ulint   free_limit;
03089   ulint   size;
03090   ulint   flags;
03091   ulint   zip_size;
03092   ulint   n_free;
03093   ulint   n_free_up;
03094   ulint   reserve;
03095   rw_lock_t*  latch;
03096   mtr_t   mtr;
03097 
03098   ut_ad(!mutex_own(&kernel_mutex));
03099 
03100   /* The convoluted mutex acquire is to overcome latching order
03101   issues: The problem is that the fil_mutex is at a lower level
03102   than the tablespace latch and the buffer pool mutex. We have to
03103   first prevent any operations on the file system by acquiring the
03104   dictionary mutex. Then acquire the tablespace latch to obey the
03105   latching order and then release the dictionary mutex. That way we
03106   ensure that the tablespace instance can't be freed while we are
03107   examining its contents (see fil_space_free()).
03108 
03109   However, there is one further complication, we release the fil_mutex
03110   when we need to invalidate the the pages in the buffer pool and we
03111   reacquire the fil_mutex when deleting and freeing the tablespace
03112   instance in fil0fil.c. Here we need to account for that situation
03113   too. */
03114 
03115   mutex_enter(&dict_sys->mutex);
03116 
03117   /* At this stage there is no guarantee that the tablespace even
03118   exists in the cache. */
03119 
03120   if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
03121 
03122     mutex_exit(&dict_sys->mutex);
03123 
03124     return(ULLINT_UNDEFINED);
03125   }
03126 
03127   mtr_start(&mtr);
03128 
03129   latch = fil_space_get_latch(space, &flags);
03130 
03131   /* This should ensure that the tablespace instance can't be freed
03132   by another thread. However, the tablespace pages can still be freed
03133   from the buffer pool. We need to check for that again. */
03134 
03135   zip_size = dict_table_flags_to_zip_size(flags);
03136 
03137   mtr_x_lock(latch, &mtr);
03138 
03139   mutex_exit(&dict_sys->mutex);
03140 
03141   /* At this point it is possible for the tablespace to be deleted and
03142   its pages removed from the buffer pool. We need to check for that
03143   situation. However, the tablespace instance can't be deleted because
03144   our latching above should ensure that. */
03145 
03146   if (fil_tablespace_is_being_deleted(space)) {
03147 
03148     mtr_commit(&mtr);
03149 
03150     return(ULLINT_UNDEFINED);
03151   }
03152 
03153   /* From here on even if the user has dropped the tablespace, the
03154   pages _must_ still exist in the buffer pool and the tablespace
03155   instance _must_ be in the file system hash table. */
03156 
03157   space_header = fsp_get_space_header(space, zip_size, &mtr);
03158 
03159   size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
03160 
03161   n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
03162 
03163   free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
03164             MLOG_4BYTES, &mtr);
03165   mtr_commit(&mtr);
03166 
03167   if (size < FSP_EXTENT_SIZE) {
03168     ut_a(space != 0); /* This must be a single-table
03169           tablespace */
03170 
03171     return(0);    /* TODO: count free frag pages and
03172           return a value based on that */
03173   }
03174 
03175   /* Below we play safe when counting free extents above the free limit:
03176   some of them will contain extent descriptor pages, and therefore
03177   will not be free extents */
03178 
03179   n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
03180 
03181   if (n_free_up > 0) {
03182     n_free_up--;
03183     if (!zip_size) {
03184       n_free_up -= n_free_up
03185         / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
03186     } else {
03187       n_free_up -= n_free_up
03188         / (zip_size / FSP_EXTENT_SIZE);
03189     }
03190   }
03191 
03192   n_free = n_free_list_ext + n_free_up;
03193 
03194   /* We reserve 1 extent + 0.5 % of the space size to undo logs
03195   and 1 extent + 0.5 % to cleaning operations; NOTE: this source
03196   code is duplicated in the function above! */
03197 
03198   reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
03199 
03200   if (reserve > n_free) {
03201     return(0);
03202   }
03203 
03204   if (!zip_size) {
03205     return((ullint) (n_free - reserve)
03206            * FSP_EXTENT_SIZE
03207            * (UNIV_PAGE_SIZE / 1024));
03208   } else {
03209     return((ullint) (n_free - reserve)
03210            * FSP_EXTENT_SIZE
03211            * (zip_size / 1024));
03212   }
03213 }
03214 
03215 /********************************************************************/
03218 static
03219 void
03220 fseg_mark_page_used(
03221 /*================*/
03222   fseg_inode_t* seg_inode,
03223   ulint   space,  
03224   ulint   zip_size,
03226   ulint   page, 
03227   mtr_t*    mtr)  
03228 {
03229   xdes_t* descr;
03230   ulint not_full_n_used;
03231 
03232   ut_ad(seg_inode && mtr);
03233   ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
03234   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
03235         == FSEG_MAGIC_N_VALUE);
03236 
03237   descr = xdes_get_descriptor(space, zip_size, page, mtr);
03238 
03239   ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
03240         == mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
03241 
03242   if (xdes_is_free(descr, mtr)) {
03243     /* We move the extent from the free list to the
03244     NOT_FULL list */
03245     flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
03246           mtr);
03247     flst_add_last(seg_inode + FSEG_NOT_FULL,
03248             descr + XDES_FLST_NODE, mtr);
03249   }
03250 
03251   ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
03252         == TRUE);
03253   /* We mark the page as used */
03254   xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
03255 
03256   not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03257            MLOG_4BYTES, mtr);
03258   not_full_n_used++;
03259   mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
03260        MLOG_4BYTES, mtr);
03261   if (xdes_is_full(descr, mtr)) {
03262     /* We move the extent from the NOT_FULL list to the
03263     FULL list */
03264     flst_remove(seg_inode + FSEG_NOT_FULL,
03265           descr + XDES_FLST_NODE, mtr);
03266     flst_add_last(seg_inode + FSEG_FULL,
03267             descr + XDES_FLST_NODE, mtr);
03268 
03269     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03270          not_full_n_used - FSP_EXTENT_SIZE,
03271          MLOG_4BYTES, mtr);
03272   }
03273 }
03274 
03275 /**********************************************************************/
03277 static
03278 void
03279 fseg_free_page_low(
03280 /*===============*/
03281   fseg_inode_t* seg_inode, 
03282   ulint   space,  
03283   ulint   zip_size,
03285   ulint   page, 
03286   mtr_t*    mtr)  
03287 {
03288   xdes_t* descr;
03289   ulint not_full_n_used;
03290   ulint state;
03291   ib_id_t descr_id;
03292   ib_id_t seg_id;
03293   ulint i;
03294 
03295   ut_ad(seg_inode && mtr);
03296   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
03297         == FSEG_MAGIC_N_VALUE);
03298   ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
03299 
03300   /* Drop search system page hash index if the page is found in
03301   the pool and is hashed */
03302 
03303   btr_search_drop_page_hash_when_freed(space, zip_size, page);
03304 
03305   descr = xdes_get_descriptor(space, zip_size, page, mtr);
03306 
03307   ut_a(descr);
03308   if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
03309     fputs("InnoDB: Dump of the tablespace extent descriptor: ",
03310           stderr);
03311     ut_print_buf(stderr, descr, 40);
03312 
03313     fprintf(stderr, "\n"
03314       "InnoDB: Serious error! InnoDB is trying to"
03315       " free page %lu\n"
03316       "InnoDB: though it is already marked as free"
03317       " in the tablespace!\n"
03318       "InnoDB: The tablespace free space info is corrupt.\n"
03319       "InnoDB: You may need to dump your"
03320       " InnoDB tables and recreate the whole\n"
03321       "InnoDB: database!\n", (ulong) page);
03322 crash:
03323     fputs("InnoDB: Please refer to\n"
03324           "InnoDB: " REFMAN "forcing-recovery.html\n"
03325           "InnoDB: about forcing recovery.\n", stderr);
03326     ut_error;
03327   }
03328 
03329   state = xdes_get_state(descr, mtr);
03330 
03331   if (state != XDES_FSEG) {
03332     /* The page is in the fragment pages of the segment */
03333 
03334     for (i = 0;; i++) {
03335       if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
03336           == page) {
03337 
03338         fseg_set_nth_frag_page_no(seg_inode, i,
03339                 FIL_NULL, mtr);
03340         break;
03341       }
03342     }
03343 
03344     fsp_free_page(space, zip_size, page, mtr);
03345 
03346     return;
03347   }
03348 
03349   /* If we get here, the page is in some extent of the segment */
03350 
03351   descr_id = mach_read_from_8(descr + XDES_ID);
03352   seg_id = mach_read_from_8(seg_inode + FSEG_ID);
03353 #if 0
03354   fprintf(stderr,
03355     "InnoDB: InnoDB is freeing space %lu page %lu,\n"
03356     "InnoDB: which belongs to descr seg %llu\n"
03357     "InnoDB: segment %llu.\n",
03358     (ulong) space, (ulong) page,
03359     (ullint) descr_id,
03360     (ullint) seg_id);
03361 #endif /* 0 */
03362   if (UNIV_UNLIKELY(descr_id != seg_id)) {
03363     fputs("InnoDB: Dump of the tablespace extent descriptor: ",
03364           stderr);
03365     ut_print_buf(stderr, descr, 40);
03366     fputs("\nInnoDB: Dump of the segment inode: ", stderr);
03367     ut_print_buf(stderr, seg_inode, 40);
03368     putc('\n', stderr);
03369 
03370     fprintf(stderr,
03371       "InnoDB: Serious error: InnoDB is trying to"
03372       " free space %lu page %lu,\n"
03373       "InnoDB: which does not belong to"
03374       " segment %llu but belongs\n"
03375       "InnoDB: to segment %llu.\n",
03376       (ulong) space, (ulong) page,
03377       (ullint) descr_id,
03378       (ullint) seg_id);
03379     goto crash;
03380   }
03381 
03382   not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03383            MLOG_4BYTES, mtr);
03384   if (xdes_is_full(descr, mtr)) {
03385     /* The fragment is full: move it to another list */
03386     flst_remove(seg_inode + FSEG_FULL,
03387           descr + XDES_FLST_NODE, mtr);
03388     flst_add_last(seg_inode + FSEG_NOT_FULL,
03389             descr + XDES_FLST_NODE, mtr);
03390     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03391          not_full_n_used + FSP_EXTENT_SIZE - 1,
03392          MLOG_4BYTES, mtr);
03393   } else {
03394     ut_a(not_full_n_used > 0);
03395     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03396          not_full_n_used - 1, MLOG_4BYTES, mtr);
03397   }
03398 
03399   xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
03400   xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
03401 
03402   if (xdes_is_free(descr, mtr)) {
03403     /* The extent has become free: free it to space */
03404     flst_remove(seg_inode + FSEG_NOT_FULL,
03405           descr + XDES_FLST_NODE, mtr);
03406     fsp_free_extent(space, zip_size, page, mtr);
03407   }
03408 }
03409 
03410 /**********************************************************************/
03412 UNIV_INTERN
03413 void
03414 fseg_free_page(
03415 /*===========*/
03416   fseg_header_t*  seg_header, 
03417   ulint   space,  
03418   ulint   page, 
03419   mtr_t*    mtr)  
03420 {
03421   ulint   flags;
03422   ulint   zip_size;
03423   fseg_inode_t* seg_inode;
03424   rw_lock_t*  latch;
03425 
03426   latch = fil_space_get_latch(space, &flags);
03427   zip_size = dict_table_flags_to_zip_size(flags);
03428 
03429   ut_ad(!mutex_own(&kernel_mutex)
03430         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
03431 
03432   mtr_x_lock(latch, mtr);
03433 
03434   seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
03435 
03436   fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
03437 
03438 #ifdef UNIV_DEBUG_FILE_ACCESSES
03439   buf_page_set_file_page_was_freed(space, page);
03440 #endif
03441 }
03442 
03443 /**********************************************************************/
03445 static
03446 void
03447 fseg_free_extent(
03448 /*=============*/
03449   fseg_inode_t* seg_inode, 
03450   ulint   space,  
03451   ulint   zip_size,
03453   ulint   page, 
03454   mtr_t*    mtr)  
03455 {
03456   ulint first_page_in_extent;
03457   xdes_t* descr;
03458   ulint not_full_n_used;
03459   ulint descr_n_used;
03460   ulint i;
03461 
03462   ut_ad(seg_inode && mtr);
03463 
03464   descr = xdes_get_descriptor(space, zip_size, page, mtr);
03465 
03466   ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
03467   ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
03468   ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
03469         == FSEG_MAGIC_N_VALUE);
03470 
03471   first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
03472 
03473   for (i = 0; i < FSP_EXTENT_SIZE; i++) {
03474     if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
03475 
03476       /* Drop search system page hash index if the page is
03477       found in the pool and is hashed */
03478 
03479       btr_search_drop_page_hash_when_freed(
03480         space, zip_size, first_page_in_extent + i);
03481     }
03482   }
03483 
03484   if (xdes_is_full(descr, mtr)) {
03485     flst_remove(seg_inode + FSEG_FULL,
03486           descr + XDES_FLST_NODE, mtr);
03487   } else if (xdes_is_free(descr, mtr)) {
03488     flst_remove(seg_inode + FSEG_FREE,
03489           descr + XDES_FLST_NODE, mtr);
03490   } else {
03491     flst_remove(seg_inode + FSEG_NOT_FULL,
03492           descr + XDES_FLST_NODE, mtr);
03493 
03494     not_full_n_used = mtr_read_ulint(
03495       seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
03496 
03497     descr_n_used = xdes_get_n_used(descr, mtr);
03498     ut_a(not_full_n_used >= descr_n_used);
03499     mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
03500          not_full_n_used - descr_n_used,
03501          MLOG_4BYTES, mtr);
03502   }
03503 
03504   fsp_free_extent(space, zip_size, page, mtr);
03505 
03506 #ifdef UNIV_DEBUG_FILE_ACCESSES
03507   for (i = 0; i < FSP_EXTENT_SIZE; i++) {
03508 
03509     buf_page_set_file_page_was_freed(space,
03510              first_page_in_extent + i);
03511   }
03512 #endif
03513 }
03514 
03515 /**********************************************************************/
03521 UNIV_INTERN
03522 ibool
03523 fseg_free_step(
03524 /*===========*/
03525   fseg_header_t*  header, 
03529   mtr_t*    mtr)  
03530 {
03531   ulint   n;
03532   ulint   page;
03533   xdes_t*   descr;
03534   fseg_inode_t* inode;
03535   ulint   space;
03536   ulint   flags;
03537   ulint   zip_size;
03538   ulint   header_page;
03539   rw_lock_t*  latch;
03540 
03541   space = page_get_space_id(page_align(header));
03542   header_page = page_get_page_no(page_align(header));
03543 
03544   latch = fil_space_get_latch(space, &flags);
03545   zip_size = dict_table_flags_to_zip_size(flags);
03546 
03547   ut_ad(!mutex_own(&kernel_mutex)
03548         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
03549 
03550   mtr_x_lock(latch, mtr);
03551 
03552   descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
03553 
03554   /* Check that the header resides on a page which has not been
03555   freed yet */
03556 
03557   ut_a(descr);
03558   ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
03559         header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
03560   inode = fseg_inode_try_get(header, space, zip_size, mtr);
03561 
03562   if (UNIV_UNLIKELY(inode == NULL)) {
03563     fprintf(stderr, "double free of inode from %u:%u\n",
03564       (unsigned) space, (unsigned) header_page);
03565     return(TRUE);
03566   }
03567 
03568   descr = fseg_get_first_extent(inode, space, zip_size, mtr);
03569 
03570   if (descr != NULL) {
03571     /* Free the extent held by the segment */
03572     page = xdes_get_offset(descr);
03573 
03574     fseg_free_extent(inode, space, zip_size, page, mtr);
03575 
03576     return(FALSE);
03577   }
03578 
03579   /* Free a frag page */
03580   n = fseg_find_last_used_frag_page_slot(inode, mtr);
03581 
03582   if (n == ULINT_UNDEFINED) {
03583     /* Freeing completed: free the segment inode */
03584     fsp_free_seg_inode(space, zip_size, inode, mtr);
03585 
03586     return(TRUE);
03587   }
03588 
03589   fseg_free_page_low(inode, space, zip_size,
03590          fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
03591 
03592   n = fseg_find_last_used_frag_page_slot(inode, mtr);
03593 
03594   if (n == ULINT_UNDEFINED) {
03595     /* Freeing completed: free the segment inode */
03596     fsp_free_seg_inode(space, zip_size, inode, mtr);
03597 
03598     return(TRUE);
03599   }
03600 
03601   return(FALSE);
03602 }
03603 
03604 /**********************************************************************/
03608 UNIV_INTERN
03609 ibool
03610 fseg_free_step_not_header(
03611 /*======================*/
03612   fseg_header_t*  header, 
03614   mtr_t*    mtr)  
03615 {
03616   ulint   n;
03617   ulint   page;
03618   xdes_t*   descr;
03619   fseg_inode_t* inode;
03620   ulint   space;
03621   ulint   flags;
03622   ulint   zip_size;
03623   ulint   page_no;
03624   rw_lock_t*  latch;
03625 
03626   space = page_get_space_id(page_align(header));
03627 
03628   latch = fil_space_get_latch(space, &flags);
03629   zip_size = dict_table_flags_to_zip_size(flags);
03630 
03631   ut_ad(!mutex_own(&kernel_mutex)
03632         || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
03633 
03634   mtr_x_lock(latch, mtr);
03635 
03636   inode = fseg_inode_get(header, space, zip_size, mtr);
03637 
03638   descr = fseg_get_first_extent(inode, space, zip_size, mtr);
03639 
03640   if (descr != NULL) {
03641     /* Free the extent held by the segment */
03642     page = xdes_get_offset(descr);
03643 
03644     fseg_free_extent(inode, space, zip_size, page, mtr);
03645 
03646     return(FALSE);
03647   }
03648 
03649   /* Free a frag page */
03650 
03651   n = fseg_find_last_used_frag_page_slot(inode, mtr);
03652 
03653   if (n == ULINT_UNDEFINED) {
03654     ut_error;
03655   }
03656 
03657   page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
03658 
03659   if (page_no == page_get_page_no(page_align(header))) {
03660 
03661     return(TRUE);
03662   }
03663 
03664   fseg_free_page_low(inode, space, zip_size, page_no, mtr);
03665 
03666   return(FALSE);
03667 }
03668 
03669 /**********************************************************************/
03674 static
03675 xdes_t*
03676 fseg_get_first_extent(
03677 /*==================*/
03678   fseg_inode_t* inode,  
03679   ulint   space,  
03680   ulint   zip_size,
03682   mtr_t*    mtr)  
03683 {
03684   fil_addr_t  first;
03685   xdes_t*   descr;
03686 
03687   ut_ad(inode && mtr);
03688 
03689   ut_ad(space == page_get_space_id(page_align(inode)));
03690   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
03691 
03692   first = fil_addr_null;
03693 
03694   if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
03695 
03696     first = flst_get_first(inode + FSEG_FULL, mtr);
03697 
03698   } else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
03699 
03700     first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
03701 
03702   } else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
03703 
03704     first = flst_get_first(inode + FSEG_FREE, mtr);
03705   }
03706 
03707   if (first.page == FIL_NULL) {
03708 
03709     return(NULL);
03710   }
03711   descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
03712 
03713   return(descr);
03714 }
03715 
03716 /*******************************************************************/
03719 static
03720 ibool
03721 fseg_validate_low(
03722 /*==============*/
03723   fseg_inode_t* inode, 
03724   mtr_t*    mtr2) 
03725 {
03726   ulint   space;
03727   ib_id_t   seg_id;
03728   mtr_t   mtr;
03729   xdes_t*   descr;
03730   fil_addr_t  node_addr;
03731   ulint   n_used    = 0;
03732   ulint   n_used2   = 0;
03733 
03734   ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
03735   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
03736 
03737   space = page_get_space_id(page_align(inode));
03738 
03739   seg_id = mach_read_from_8(inode + FSEG_ID);
03740   n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
03741         MLOG_4BYTES, mtr2);
03742   flst_validate(inode + FSEG_FREE, mtr2);
03743   flst_validate(inode + FSEG_NOT_FULL, mtr2);
03744   flst_validate(inode + FSEG_FULL, mtr2);
03745 
03746   /* Validate FSEG_FREE list */
03747   node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
03748 
03749   while (!fil_addr_is_null(node_addr)) {
03750     ulint flags;
03751     ulint zip_size;
03752 
03753     mtr_start(&mtr);
03754     mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
03755     zip_size = dict_table_flags_to_zip_size(flags);
03756 
03757     descr = xdes_lst_get_descriptor(space, zip_size,
03758             node_addr, &mtr);
03759 
03760     ut_a(xdes_get_n_used(descr, &mtr) == 0);
03761     ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
03762     ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
03763 
03764     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
03765     mtr_commit(&mtr);
03766   }
03767 
03768   /* Validate FSEG_NOT_FULL list */
03769 
03770   node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
03771 
03772   while (!fil_addr_is_null(node_addr)) {
03773     ulint flags;
03774     ulint zip_size;
03775 
03776     mtr_start(&mtr);
03777     mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
03778     zip_size = dict_table_flags_to_zip_size(flags);
03779 
03780     descr = xdes_lst_get_descriptor(space, zip_size,
03781             node_addr, &mtr);
03782 
03783     ut_a(xdes_get_n_used(descr, &mtr) > 0);
03784     ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
03785     ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
03786     ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
03787 
03788     n_used2 += xdes_get_n_used(descr, &mtr);
03789 
03790     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
03791     mtr_commit(&mtr);
03792   }
03793 
03794   /* Validate FSEG_FULL list */
03795 
03796   node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
03797 
03798   while (!fil_addr_is_null(node_addr)) {
03799     ulint flags;
03800     ulint zip_size;
03801 
03802     mtr_start(&mtr);
03803     mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
03804     zip_size = dict_table_flags_to_zip_size(flags);
03805 
03806     descr = xdes_lst_get_descriptor(space, zip_size,
03807             node_addr, &mtr);
03808 
03809     ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
03810     ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
03811     ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
03812 
03813     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
03814     mtr_commit(&mtr);
03815   }
03816 
03817   ut_a(n_used == n_used2);
03818 
03819   return(TRUE);
03820 }
03821 
03822 #ifdef UNIV_DEBUG
03823 /*******************************************************************/
03826 UNIV_INTERN
03827 ibool
03828 fseg_validate(
03829 /*==========*/
03830   fseg_header_t*  header, 
03831   mtr_t*    mtr)  
03832 {
03833   fseg_inode_t* inode;
03834   ibool   ret;
03835   ulint   space;
03836   ulint   flags;
03837   ulint   zip_size;
03838 
03839   space = page_get_space_id(page_align(header));
03840 
03841   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
03842   zip_size = dict_table_flags_to_zip_size(flags);
03843 
03844   inode = fseg_inode_get(header, space, zip_size, mtr);
03845 
03846   ret = fseg_validate_low(inode, mtr);
03847 
03848   return(ret);
03849 }
03850 #endif /* UNIV_DEBUG */
03851 
03852 /*******************************************************************/
03854 static
03855 void
03856 fseg_print_low(
03857 /*===========*/
03858   fseg_inode_t* inode, 
03859   mtr_t*    mtr)  
03860 {
03861   ulint space;
03862   ulint n_used;
03863   ulint n_frag;
03864   ulint n_free;
03865   ulint n_not_full;
03866   ulint n_full;
03867   ulint reserved;
03868   ulint used;
03869   ulint page_no;
03870   ib_id_t seg_id;
03871 
03872   ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
03873   space = page_get_space_id(page_align(inode));
03874   page_no = page_get_page_no(page_align(inode));
03875 
03876   reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
03877 
03878   seg_id = mach_read_from_8(inode + FSEG_ID);
03879 
03880   n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
03881         MLOG_4BYTES, mtr);
03882   n_frag = fseg_get_n_frag_pages(inode, mtr);
03883   n_free = flst_get_len(inode + FSEG_FREE, mtr);
03884   n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
03885   n_full = flst_get_len(inode + FSEG_FULL, mtr);
03886 
03887   fprintf(stderr,
03888     "SEGMENT id %llu space %lu; page %lu;"
03889     " res %lu used %lu; full ext %lu\n"
03890     "fragm pages %lu; free extents %lu;"
03891     " not full extents %lu: pages %lu\n",
03892     (ullint) seg_id,
03893     (ulong) space, (ulong) page_no,
03894     (ulong) reserved, (ulong) used, (ulong) n_full,
03895     (ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
03896     (ulong) n_used);
03897   ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
03898 }
03899 
03900 #ifdef UNIV_BTR_PRINT
03901 /*******************************************************************/
03903 UNIV_INTERN
03904 void
03905 fseg_print(
03906 /*=======*/
03907   fseg_header_t*  header, 
03908   mtr_t*    mtr)  
03909 {
03910   fseg_inode_t* inode;
03911   ulint   space;
03912   ulint   flags;
03913   ulint   zip_size;
03914 
03915   space = page_get_space_id(page_align(header));
03916 
03917   mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
03918   zip_size = dict_table_flags_to_zip_size(flags);
03919 
03920   inode = fseg_inode_get(header, space, zip_size, mtr);
03921 
03922   fseg_print_low(inode, mtr);
03923 }
03924 #endif /* UNIV_BTR_PRINT */
03925 
03926 /*******************************************************************/
03929 UNIV_INTERN
03930 ibool
03931 fsp_validate(
03932 /*=========*/
03933   ulint space)  
03934 {
03935   fsp_header_t* header;
03936   fseg_inode_t* seg_inode;
03937   page_t*   seg_inode_page;
03938   rw_lock_t*  latch;
03939   ulint   size;
03940   ulint   flags;
03941   ulint   zip_size;
03942   ulint   free_limit;
03943   ulint   frag_n_used;
03944   mtr_t   mtr;
03945   mtr_t   mtr2;
03946   xdes_t*   descr;
03947   fil_addr_t  node_addr;
03948   fil_addr_t  next_node_addr;
03949   ulint   descr_count = 0;
03950   ulint   n_used    = 0;
03951   ulint   n_used2   = 0;
03952   ulint   n_full_frag_pages;
03953   ulint   n;
03954   ulint   seg_inode_len_free;
03955   ulint   seg_inode_len_full;
03956 
03957   latch = fil_space_get_latch(space, &flags);
03958   zip_size = dict_table_flags_to_zip_size(flags);
03959   ut_a(ut_is_2pow(zip_size));
03960   ut_a(zip_size <= UNIV_PAGE_SIZE);
03961   ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
03962 
03963   /* Start first a mini-transaction mtr2 to lock out all other threads
03964   from the fsp system */
03965   mtr_start(&mtr2);
03966   mtr_x_lock(latch, &mtr2);
03967 
03968   mtr_start(&mtr);
03969   mtr_x_lock(latch, &mtr);
03970 
03971   header = fsp_get_space_header(space, zip_size, &mtr);
03972 
03973   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
03974   free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
03975             MLOG_4BYTES, &mtr);
03976   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
03977              MLOG_4BYTES, &mtr);
03978 
03979   n_full_frag_pages = FSP_EXTENT_SIZE
03980     * flst_get_len(header + FSP_FULL_FRAG, &mtr);
03981 
03982   if (UNIV_UNLIKELY(free_limit > size)) {
03983 
03984     ut_a(space != 0);
03985     ut_a(size < FSP_EXTENT_SIZE);
03986   }
03987 
03988   flst_validate(header + FSP_FREE, &mtr);
03989   flst_validate(header + FSP_FREE_FRAG, &mtr);
03990   flst_validate(header + FSP_FULL_FRAG, &mtr);
03991 
03992   mtr_commit(&mtr);
03993 
03994   /* Validate FSP_FREE list */
03995   mtr_start(&mtr);
03996   mtr_x_lock(latch, &mtr);
03997 
03998   header = fsp_get_space_header(space, zip_size, &mtr);
03999   node_addr = flst_get_first(header + FSP_FREE, &mtr);
04000 
04001   mtr_commit(&mtr);
04002 
04003   while (!fil_addr_is_null(node_addr)) {
04004     mtr_start(&mtr);
04005     mtr_x_lock(latch, &mtr);
04006 
04007     descr_count++;
04008     descr = xdes_lst_get_descriptor(space, zip_size,
04009             node_addr, &mtr);
04010 
04011     ut_a(xdes_get_n_used(descr, &mtr) == 0);
04012     ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
04013 
04014     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
04015     mtr_commit(&mtr);
04016   }
04017 
04018   /* Validate FSP_FREE_FRAG list */
04019   mtr_start(&mtr);
04020   mtr_x_lock(latch, &mtr);
04021 
04022   header = fsp_get_space_header(space, zip_size, &mtr);
04023   node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
04024 
04025   mtr_commit(&mtr);
04026 
04027   while (!fil_addr_is_null(node_addr)) {
04028     mtr_start(&mtr);
04029     mtr_x_lock(latch, &mtr);
04030 
04031     descr_count++;
04032     descr = xdes_lst_get_descriptor(space, zip_size,
04033             node_addr, &mtr);
04034 
04035     ut_a(xdes_get_n_used(descr, &mtr) > 0);
04036     ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
04037     ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
04038 
04039     n_used += xdes_get_n_used(descr, &mtr);
04040     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
04041 
04042     mtr_commit(&mtr);
04043   }
04044 
04045   /* Validate FSP_FULL_FRAG list */
04046   mtr_start(&mtr);
04047   mtr_x_lock(latch, &mtr);
04048 
04049   header = fsp_get_space_header(space, zip_size, &mtr);
04050   node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
04051 
04052   mtr_commit(&mtr);
04053 
04054   while (!fil_addr_is_null(node_addr)) {
04055     mtr_start(&mtr);
04056     mtr_x_lock(latch, &mtr);
04057 
04058     descr_count++;
04059     descr = xdes_lst_get_descriptor(space, zip_size,
04060             node_addr, &mtr);
04061 
04062     ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
04063     ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
04064 
04065     node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
04066     mtr_commit(&mtr);
04067   }
04068 
04069   /* Validate segments */
04070   mtr_start(&mtr);
04071   mtr_x_lock(latch, &mtr);
04072 
04073   header = fsp_get_space_header(space, zip_size, &mtr);
04074 
04075   node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
04076 
04077   seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
04078 
04079   mtr_commit(&mtr);
04080 
04081   while (!fil_addr_is_null(node_addr)) {
04082 
04083     n = 0;
04084     do {
04085       mtr_start(&mtr);
04086       mtr_x_lock(latch, &mtr);
04087 
04088       seg_inode_page = fut_get_ptr(
04089         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04090         - FSEG_INODE_PAGE_NODE;
04091 
04092       seg_inode = fsp_seg_inode_page_get_nth_inode(
04093         seg_inode_page, n, zip_size, &mtr);
04094       ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
04095       fseg_validate_low(seg_inode, &mtr);
04096 
04097       descr_count += flst_get_len(seg_inode + FSEG_FREE,
04098                 &mtr);
04099       descr_count += flst_get_len(seg_inode + FSEG_FULL,
04100                 &mtr);
04101       descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
04102                 &mtr);
04103 
04104       n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
04105 
04106       next_node_addr = flst_get_next_addr(
04107         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04108       mtr_commit(&mtr);
04109     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04110 
04111     node_addr = next_node_addr;
04112   }
04113 
04114   mtr_start(&mtr);
04115   mtr_x_lock(latch, &mtr);
04116 
04117   header = fsp_get_space_header(space, zip_size, &mtr);
04118 
04119   node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
04120 
04121   seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
04122 
04123   mtr_commit(&mtr);
04124 
04125   while (!fil_addr_is_null(node_addr)) {
04126 
04127     n = 0;
04128 
04129     do {
04130       mtr_start(&mtr);
04131       mtr_x_lock(latch, &mtr);
04132 
04133       seg_inode_page = fut_get_ptr(
04134         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04135         - FSEG_INODE_PAGE_NODE;
04136 
04137       seg_inode = fsp_seg_inode_page_get_nth_inode(
04138         seg_inode_page, n, zip_size, &mtr);
04139       if (mach_read_from_8(seg_inode + FSEG_ID)) {
04140         fseg_validate_low(seg_inode, &mtr);
04141 
04142         descr_count += flst_get_len(
04143           seg_inode + FSEG_FREE, &mtr);
04144         descr_count += flst_get_len(
04145           seg_inode + FSEG_FULL, &mtr);
04146         descr_count += flst_get_len(
04147           seg_inode + FSEG_NOT_FULL, &mtr);
04148         n_used2 += fseg_get_n_frag_pages(
04149           seg_inode, &mtr);
04150       }
04151 
04152       next_node_addr = flst_get_next_addr(
04153         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04154       mtr_commit(&mtr);
04155     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04156 
04157     node_addr = next_node_addr;
04158   }
04159 
04160   ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
04161   if (!zip_size) {
04162     ut_a(n_used + n_full_frag_pages
04163          == n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
04164                / UNIV_PAGE_SIZE)
04165          + seg_inode_len_full + seg_inode_len_free);
04166   } else {
04167     ut_a(n_used + n_full_frag_pages
04168          == n_used2 + 2 * ((free_limit + (zip_size - 1))
04169                / zip_size)
04170          + seg_inode_len_full + seg_inode_len_free);
04171   }
04172   ut_a(frag_n_used == n_used);
04173 
04174   mtr_commit(&mtr2);
04175 
04176   return(TRUE);
04177 }
04178 
04179 /*******************************************************************/
04181 UNIV_INTERN
04182 void
04183 fsp_print(
04184 /*======*/
04185   ulint space)  
04186 {
04187   fsp_header_t* header;
04188   fseg_inode_t* seg_inode;
04189   page_t*   seg_inode_page;
04190   rw_lock_t*  latch;
04191   ulint   flags;
04192   ulint   zip_size;
04193   ulint   size;
04194   ulint   free_limit;
04195   ulint   frag_n_used;
04196   fil_addr_t  node_addr;
04197   fil_addr_t  next_node_addr;
04198   ulint   n_free;
04199   ulint   n_free_frag;
04200   ulint   n_full_frag;
04201   ib_id_t   seg_id;
04202   ulint   n;
04203   ulint   n_segs    = 0;
04204   mtr_t   mtr;
04205   mtr_t   mtr2;
04206 
04207   latch = fil_space_get_latch(space, &flags);
04208   zip_size = dict_table_flags_to_zip_size(flags);
04209 
04210   /* Start first a mini-transaction mtr2 to lock out all other threads
04211   from the fsp system */
04212 
04213   mtr_start(&mtr2);
04214 
04215   mtr_x_lock(latch, &mtr2);
04216 
04217   mtr_start(&mtr);
04218 
04219   mtr_x_lock(latch, &mtr);
04220 
04221   header = fsp_get_space_header(space, zip_size, &mtr);
04222 
04223   size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
04224 
04225   free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
04226             &mtr);
04227   frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
04228              &mtr);
04229   n_free = flst_get_len(header + FSP_FREE, &mtr);
04230   n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
04231   n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
04232 
04233   seg_id = mach_read_from_8(header + FSP_SEG_ID);
04234 
04235   fprintf(stderr,
04236     "FILE SPACE INFO: id %lu\n"
04237     "size %lu, free limit %lu, free extents %lu\n"
04238     "not full frag extents %lu: used pages %lu,"
04239     " full frag extents %lu\n"
04240     "first seg id not used %llu\n",
04241     (ulong) space,
04242     (ulong) size, (ulong) free_limit, (ulong) n_free,
04243     (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
04244     (ullint) seg_id);
04245 
04246   mtr_commit(&mtr);
04247 
04248   /* Print segments */
04249 
04250   mtr_start(&mtr);
04251   mtr_x_lock(latch, &mtr);
04252 
04253   header = fsp_get_space_header(space, zip_size, &mtr);
04254 
04255   node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
04256 
04257   mtr_commit(&mtr);
04258 
04259   while (!fil_addr_is_null(node_addr)) {
04260 
04261     n = 0;
04262 
04263     do {
04264 
04265       mtr_start(&mtr);
04266       mtr_x_lock(latch, &mtr);
04267 
04268       seg_inode_page = fut_get_ptr(
04269         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04270         - FSEG_INODE_PAGE_NODE;
04271 
04272       seg_inode = fsp_seg_inode_page_get_nth_inode(
04273         seg_inode_page, n, zip_size, &mtr);
04274       ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
04275       fseg_print_low(seg_inode, &mtr);
04276 
04277       n_segs++;
04278 
04279       next_node_addr = flst_get_next_addr(
04280         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04281       mtr_commit(&mtr);
04282     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04283 
04284     node_addr = next_node_addr;
04285   }
04286 
04287   mtr_start(&mtr);
04288   mtr_x_lock(latch, &mtr);
04289 
04290   header = fsp_get_space_header(space, zip_size, &mtr);
04291 
04292   node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
04293 
04294   mtr_commit(&mtr);
04295 
04296   while (!fil_addr_is_null(node_addr)) {
04297 
04298     n = 0;
04299 
04300     do {
04301 
04302       mtr_start(&mtr);
04303       mtr_x_lock(latch, &mtr);
04304 
04305       seg_inode_page = fut_get_ptr(
04306         space, zip_size, node_addr, RW_X_LATCH, &mtr)
04307         - FSEG_INODE_PAGE_NODE;
04308 
04309       seg_inode = fsp_seg_inode_page_get_nth_inode(
04310         seg_inode_page, n, zip_size, &mtr);
04311       if (mach_read_from_8(seg_inode + FSEG_ID)) {
04312 
04313         fseg_print_low(seg_inode, &mtr);
04314         n_segs++;
04315       }
04316 
04317       next_node_addr = flst_get_next_addr(
04318         seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
04319       mtr_commit(&mtr);
04320     } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
04321 
04322     node_addr = next_node_addr;
04323   }
04324 
04325   mtr_commit(&mtr2);
04326 
04327   fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
04328 }
04329 #endif /* !UNIV_HOTBACKUP */