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

