Drizzled Public API Documentation

fsp0fsp.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /******************************************************************/
26 #include "fsp0fsp.h"
27 
28 #ifdef UNIV_NONINL
29 #include "fsp0fsp.ic"
30 #endif
31 
32 #include "buf0buf.h"
33 #include "fil0fil.h"
34 #include "mtr0log.h"
35 #include "ut0byte.h"
36 #include "page0page.h"
37 #include "page0zip.h"
38 #ifdef UNIV_HOTBACKUP
39 # include "fut0lst.h"
40 #else /* UNIV_HOTBACKUP */
41 # include "sync0sync.h"
42 # include "fut0fut.h"
43 # include "srv0srv.h"
44 # include "ibuf0ibuf.h"
45 # include "btr0btr.h"
46 # include "btr0sea.h"
47 # include "dict0boot.h"
48 # include "log0log.h"
49 #endif /* UNIV_HOTBACKUP */
50 #include "dict0mem.h"
51 
52 
53 #define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
54  within a file page */
55 
56 /* The data structures in files are defined just as byte strings in C */
57 typedef byte fsp_header_t;
58 typedef byte xdes_t;
59 
60 /* SPACE HEADER
61  ============
62 
63 File space header data structure: this data structure is contained in the
64 first page of a space. The space for this header is reserved in every extent
65 descriptor page, but used only in the first. */
66 
67 /*-------------------------------------*/
68 #define FSP_SPACE_ID 0 /* space id */
69 #define FSP_NOT_USED 4 /* this field contained a value up to
70  which we know that the modifications
71  in the database have been flushed to
72  the file space; not used now */
73 #define FSP_SIZE 8 /* Current size of the space in
74  pages */
75 #define FSP_FREE_LIMIT 12 /* Minimum page number for which the
76  free list has not been initialized:
77  the pages >= this limit are, by
78  definition, free; note that in a
79  single-table tablespace where size
80  < 64 pages, this number is 64, i.e.,
81  we have initialized the space
82  about the first extent, but have not
83  physically allocted those pages to the
84  file */
85 #define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */
86 #define FSP_FRAG_N_USED 20 /* number of used pages in the
87  FSP_FREE_FRAG list */
88 #define FSP_FREE 24 /* list of free extents */
89 #define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
90  /* list of partially free extents not
91  belonging to any segment */
92 #define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
93  /* list of full extents not belonging
94  to any segment */
95 #define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
96  /* 8 bytes which give the first unused
97  segment id */
98 #define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
99  /* list of pages containing segment
100  headers, where all the segment inode
101  slots are reserved */
102 #define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
103  /* list of pages containing segment
104  headers, where not all the segment
105  header slots are reserved */
106 /*-------------------------------------*/
107 /* File space header size */
108 #define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
109 
110 #define FSP_FREE_ADD 4 /* this many free extents are added
111  to the free list from above
112  FSP_FREE_LIMIT at a time */
113 
114 /* FILE SEGMENT INODE
115  ==================
116 
117 Segment inode which is created for each segment in a tablespace. NOTE: in
118 purge we assume that a segment having only one currently used page can be
119 freed in a few steps, so that the freeing cannot fill the file buffer with
120 bufferfixed file pages. */
121 
122 typedef byte fseg_inode_t;
123 
124 #define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
125  /* the list node for linking
126  segment inode pages */
127 
128 #define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
129 /*-------------------------------------*/
130 #define FSEG_ID 0 /* 8 bytes of segment id: if this is 0,
131  it means that the header is unused */
132 #define FSEG_NOT_FULL_N_USED 8
133  /* number of used segment pages in
134  the FSEG_NOT_FULL list */
135 #define FSEG_FREE 12
136  /* list of free extents of this
137  segment */
138 #define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
139  /* list of partially free extents */
140 #define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
141  /* list of full extents */
142 #define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
143  /* magic number used in debugging */
144 #define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
145  /* array of individual pages
146  belonging to this segment in fsp
147  fragment extent lists */
148 #define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
149  /* number of slots in the array for
150  the fragment pages */
151 #define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
152  page number within space, FIL_NULL
153  means that the slot is not in use */
154 /*-------------------------------------*/
155 #define FSEG_INODE_SIZE \
156  (16 + 3 * FLST_BASE_NODE_SIZE \
157  + FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
158 
159 #define FSP_SEG_INODES_PER_PAGE(zip_size) \
160  (((zip_size ? zip_size : UNIV_PAGE_SIZE) \
161  - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
162  /* Number of segment inodes which fit on a
163  single page */
164 
165 #define FSEG_MAGIC_N_VALUE 97937874
166 
167 #define FSEG_FILLFACTOR 8 /* If this value is x, then if
168  the number of unused but reserved
169  pages in a segment is less than
170  reserved pages * 1/x, and there are
171  at least FSEG_FRAG_LIMIT used pages,
172  then we allow a new empty extent to
173  be added to the segment in
174  fseg_alloc_free_page. Otherwise, we
175  use unused pages of the segment. */
176 
177 #define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
178  /* If the segment has >= this many
179  used pages, it may be expanded by
180  allocating extents to the segment;
181  until that only individual fragment
182  pages are allocated from the space */
183 
184 #define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
185  is at least this many extents, we
186  allow extents to be put to the free
187  list of the extent: at most
188  FSEG_FREE_LIST_MAX_LEN many */
189 #define FSEG_FREE_LIST_MAX_LEN 4
190 
191 
192 /* EXTENT DESCRIPTOR
193  =================
194 
195 File extent descriptor data structure: contains bits to tell which pages in
196 the extent are free and which contain old tuple version to clean. */
197 
198 /*-------------------------------------*/
199 #define XDES_ID 0 /* The identifier of the segment
200  to which this extent belongs */
201 #define XDES_FLST_NODE 8 /* The list node data structure
202  for the descriptors */
203 #define XDES_STATE (FLST_NODE_SIZE + 8)
204  /* contains state information
205  of the extent */
206 #define XDES_BITMAP (FLST_NODE_SIZE + 12)
207  /* Descriptor bitmap of the pages
208  in the extent */
209 /*-------------------------------------*/
210 
211 #define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
212 #define XDES_FREE_BIT 0 /* Index of the bit which tells if
213  the page is free */
214 #define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
215  Index of the bit which tells if
216  there are old versions of tuples
217  on the page */
218 /* States of a descriptor */
219 #define XDES_FREE 1 /* extent is in free list of space */
220 #define XDES_FREE_FRAG 2 /* extent is in free fragment list of
221  space */
222 #define XDES_FULL_FRAG 3 /* extent is in full fragment list of
223  space */
224 #define XDES_FSEG 4 /* extent belongs to a segment */
225 
226 /* File extent data structure size in bytes. */
227 #define XDES_SIZE \
228  (XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
229 
230 /* Offset of the descriptor array on a descriptor page */
231 #define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
232 
233 #ifndef UNIV_HOTBACKUP
234 /* Flag to indicate if we have printed the tablespace full error. */
235 static ibool fsp_tbs_full_error_printed = FALSE;
236 
237 /**********************************************************************/
239 static
240 void
241 fsp_free_extent(
242 /*============*/
243  ulint space,
244  ulint zip_size,
246  ulint page,
247  mtr_t* mtr);
248 /**********************************************************************/
250 static
251 void
252 fseg_free_extent(
253 /*=============*/
254  fseg_inode_t* seg_inode,
255  ulint space,
256  ulint zip_size,
258  ulint page,
259  mtr_t* mtr);
260 /**********************************************************************/
264 static
265 ulint
266 fseg_n_reserved_pages_low(
267 /*======================*/
268  fseg_inode_t* header,
269  ulint* used,
271  mtr_t* mtr);
272 /********************************************************************/
275 static
276 void
277 fseg_mark_page_used(
278 /*================*/
279  fseg_inode_t* seg_inode,
280  ulint space,
281  ulint zip_size,
283  ulint page,
284  mtr_t* mtr);
285 /**********************************************************************/
290 static
291 xdes_t*
292 fseg_get_first_extent(
293 /*==================*/
294  fseg_inode_t* inode,
295  ulint space,
296  ulint zip_size,
298  mtr_t* mtr);
299 /**********************************************************************/
304 static
305 void
306 fsp_fill_free_list(
307 /*===============*/
308  ibool init_space,
313  ulint space,
314  fsp_header_t* header,
315  mtr_t* mtr);
316 /**********************************************************************/
321 static
322 ulint
323 fseg_alloc_free_page_low(
324 /*=====================*/
325  ulint space,
326  ulint zip_size,
328  fseg_inode_t* seg_inode,
329  ulint hint,
330  byte direction,
335  mtr_t* mtr);
336 #endif /* !UNIV_HOTBACKUP */
337 
338 /**********************************************************************/
341 UNIV_INTERN
342 ulint
343 fsp_get_size_low(
344 /*=============*/
345  page_t* page)
346 {
347  return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
348 }
349 
350 #ifndef UNIV_HOTBACKUP
351 /**********************************************************************/
354 UNIV_INLINE
355 fsp_header_t*
356 fsp_get_space_header(
357 /*=================*/
358  ulint id,
359  ulint zip_size,
361  mtr_t* mtr)
362 {
363  buf_block_t* block;
364  fsp_header_t* header;
365 
366  ut_ad(ut_is_2pow(zip_size));
367  ut_ad(zip_size <= UNIV_PAGE_SIZE);
368  ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
369  ut_ad(id || !zip_size);
370 
371  block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
372  header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
373  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
374 
375  ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
377  mach_read_from_4(FSP_SPACE_FLAGS + header)));
378  return(header);
379 }
380 
381 /**********************************************************************/
384 UNIV_INLINE
385 ibool
386 xdes_get_bit(
387 /*=========*/
388  const xdes_t* descr,
389  ulint bit,
390  ulint offset,
392  mtr_t* mtr)
393 {
394  ulint index;
395  ulint byte_index;
396  ulint bit_index;
397 
398  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
399  ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
400  ut_ad(offset < FSP_EXTENT_SIZE);
401 
402  index = bit + XDES_BITS_PER_PAGE * offset;
403 
404  byte_index = index / 8;
405  bit_index = index % 8;
406 
407  return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
408  MLOG_1BYTE, mtr),
409  bit_index));
410 }
411 
412 /**********************************************************************/
414 UNIV_INLINE
415 void
416 xdes_set_bit(
417 /*=========*/
418  xdes_t* descr,
419  ulint bit,
420  ulint offset,
422  ibool val,
423  mtr_t* mtr)
424 {
425  ulint index;
426  ulint byte_index;
427  ulint bit_index;
428  ulint descr_byte;
429 
430  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
431  ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
432  ut_ad(offset < FSP_EXTENT_SIZE);
433 
434  index = bit + XDES_BITS_PER_PAGE * offset;
435 
436  byte_index = index / 8;
437  bit_index = index % 8;
438 
439  descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
440  MLOG_1BYTE, mtr);
441  descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
442 
443  mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
444  MLOG_1BYTE, mtr);
445 }
446 
447 /**********************************************************************/
452 UNIV_INLINE
453 ulint
454 xdes_find_bit(
455 /*==========*/
456  xdes_t* descr,
457  ulint bit,
458  ibool val,
459  ulint hint,
460  mtr_t* mtr)
461 {
462  ulint i;
463 
464  ut_ad(descr && mtr);
465  ut_ad(val <= TRUE);
466  ut_ad(hint < FSP_EXTENT_SIZE);
467  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
468  for (i = hint; i < FSP_EXTENT_SIZE; i++) {
469  if (val == xdes_get_bit(descr, bit, i, mtr)) {
470 
471  return(i);
472  }
473  }
474 
475  for (i = 0; i < hint; i++) {
476  if (val == xdes_get_bit(descr, bit, i, mtr)) {
477 
478  return(i);
479  }
480  }
481 
482  return(ULINT_UNDEFINED);
483 }
484 
485 /**********************************************************************/
489 UNIV_INLINE
490 ulint
491 xdes_find_bit_downward(
492 /*===================*/
493  xdes_t* descr,
494  ulint bit,
495  ibool val,
496  ulint hint,
497  mtr_t* mtr)
498 {
499  ulint i;
500 
501  ut_ad(descr && mtr);
502  ut_ad(val <= TRUE);
503  ut_ad(hint < FSP_EXTENT_SIZE);
504  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
505  for (i = hint + 1; i > 0; i--) {
506  if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
507 
508  return(i - 1);
509  }
510  }
511 
512  for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
513  if (val == xdes_get_bit(descr, bit, i, mtr)) {
514 
515  return(i);
516  }
517  }
518 
519  return(ULINT_UNDEFINED);
520 }
521 
522 /**********************************************************************/
525 UNIV_INLINE
526 ulint
527 xdes_get_n_used(
528 /*============*/
529  const xdes_t* descr,
530  mtr_t* mtr)
531 {
532  ulint i;
533  ulint count = 0;
534 
535  ut_ad(descr && mtr);
536  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
537  for (i = 0; i < FSP_EXTENT_SIZE; i++) {
538  if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
539  count++;
540  }
541  }
542 
543  return(count);
544 }
545 
546 /**********************************************************************/
549 UNIV_INLINE
550 ibool
551 xdes_is_free(
552 /*=========*/
553  const xdes_t* descr,
554  mtr_t* mtr)
555 {
556  if (0 == xdes_get_n_used(descr, mtr)) {
557 
558  return(TRUE);
559  }
560 
561  return(FALSE);
562 }
563 
564 /**********************************************************************/
567 UNIV_INLINE
568 ibool
569 xdes_is_full(
570 /*=========*/
571  const xdes_t* descr,
572  mtr_t* mtr)
573 {
574  if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
575 
576  return(TRUE);
577  }
578 
579  return(FALSE);
580 }
581 
582 /**********************************************************************/
584 UNIV_INLINE
585 void
586 xdes_set_state(
587 /*===========*/
588  xdes_t* descr,
589  ulint state,
590  mtr_t* mtr)
591 {
592  ut_ad(descr && mtr);
593  ut_ad(state >= XDES_FREE);
594  ut_ad(state <= XDES_FSEG);
595  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
596 
597  mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
598 }
599 
600 /**********************************************************************/
603 UNIV_INLINE
604 ulint
605 xdes_get_state(
606 /*===========*/
607  const xdes_t* descr,
608  mtr_t* mtr)
609 {
610  ulint state;
611 
612  ut_ad(descr && mtr);
613  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
614 
615  state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
616  ut_ad(state - 1 < XDES_FSEG);
617  return(state);
618 }
619 
620 /**********************************************************************/
622 UNIV_INLINE
623 void
624 xdes_init(
625 /*======*/
626  xdes_t* descr,
627  mtr_t* mtr)
628 {
629  ulint i;
630 
631  ut_ad(descr && mtr);
632  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
633  ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
634 
635  for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
636  mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
637  }
638 
639  xdes_set_state(descr, XDES_FREE, mtr);
640 }
641 
642 /********************************************************************/
645 UNIV_INLINE
646 ulint
647 xdes_calc_descriptor_page(
648 /*======================*/
649  ulint zip_size,
651  ulint offset)
652 {
653  ut_a(UNIV_PAGE_SIZE >
654  XDES_ARR_OFFSET + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE);
656  XDES_ARR_OFFSET +
657  (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE);
658 
659  ut_ad(ut_is_2pow(zip_size));
660 
661  if (!zip_size) {
662  return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
663  } else {
664  ut_ad(zip_size > XDES_ARR_OFFSET
665  + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
666  return(ut_2pow_round(offset, zip_size));
667  }
668 }
669 
670 /********************************************************************/
673 UNIV_INLINE
674 ulint
675 xdes_calc_descriptor_index(
676 /*=======================*/
677  ulint zip_size,
679  ulint offset)
680 {
681  ut_ad(ut_is_2pow(zip_size));
682 
683  if (!zip_size) {
684  return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
685  / FSP_EXTENT_SIZE);
686  } else {
687  return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
688  }
689 }
690 
691 /********************************************************************/
699 UNIV_INLINE
700 xdes_t*
701 xdes_get_descriptor_with_space_hdr(
702 /*===============================*/
703  fsp_header_t* sp_header,
704  ulint space,
705  ulint offset,
709  mtr_t* mtr)
710 {
711  ulint limit;
712  ulint size;
713  ulint zip_size;
714  ulint descr_page_no;
715  page_t* descr_page;
716 
717  ut_ad(mtr);
718  ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
719  MTR_MEMO_X_LOCK));
720  ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
721  || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
722  ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
723  /* Read free limit and space size */
724  limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
725  size = mach_read_from_4(sp_header + FSP_SIZE);
726  zip_size = dict_table_flags_to_zip_size(
727  mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
728 
729  /* If offset is >= size or > limit, return NULL */
730 
731  if ((offset >= size) || (offset > limit)) {
732 
733  return(NULL);
734  }
735 
736  /* If offset is == limit, fill free list of the space. */
737 
738  if (offset == limit) {
739  fsp_fill_free_list(FALSE, space, sp_header, mtr);
740  }
741 
742  descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
743 
744  if (descr_page_no == 0) {
745  /* It is on the space header page */
746 
747  descr_page = page_align(sp_header);
748  } else {
749  buf_block_t* block;
750 
751  block = buf_page_get(space, zip_size, descr_page_no,
752  RW_X_LATCH, mtr);
753  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
754 
755  descr_page = buf_block_get_frame(block);
756  }
757 
758  return(descr_page + XDES_ARR_OFFSET
759  + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
760 }
761 
762 /********************************************************************/
771 static
772 xdes_t*
773 xdes_get_descriptor(
774 /*================*/
775  ulint space,
776  ulint zip_size,
778  ulint offset,
780  mtr_t* mtr)
781 {
782  buf_block_t* block;
783  fsp_header_t* sp_header;
784 
785  block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
786  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
787 
788  sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
789  return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
790  mtr));
791 }
792 
793 /********************************************************************/
798 UNIV_INLINE
799 xdes_t*
800 xdes_lst_get_descriptor(
801 /*====================*/
802  ulint space,
803  ulint zip_size,
805  fil_addr_t lst_node,
807  mtr_t* mtr)
808 {
809  xdes_t* descr;
810 
811  ut_ad(mtr);
812  ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
813  MTR_MEMO_X_LOCK));
814  descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
815  - XDES_FLST_NODE;
816 
817  return(descr);
818 }
819 
820 /********************************************************************/
823 UNIV_INLINE
824 ulint
825 xdes_get_offset(
826 /*============*/
827  xdes_t* descr)
828 {
829  ut_ad(descr);
830 
831  return(page_get_page_no(page_align(descr))
832  + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
833  * FSP_EXTENT_SIZE);
834 }
835 #endif /* !UNIV_HOTBACKUP */
836 
837 /***********************************************************/
839 static
840 void
841 fsp_init_file_page_low(
842 /*===================*/
843  buf_block_t* block)
844 {
845  page_t* page = buf_block_get_frame(block);
846  page_zip_des_t* page_zip= buf_block_get_page_zip(block);
847 
848 #ifndef UNIV_HOTBACKUP
849  block->check_index_page_at_flush = FALSE;
850 #endif /* !UNIV_HOTBACKUP */
851 
852  if (UNIV_LIKELY_NULL(page_zip)) {
853  memset(page, 0, UNIV_PAGE_SIZE);
854  memset(page_zip->data, 0, page_zip_get_size(page_zip));
856  buf_block_get_page_no(block));
857  mach_write_to_4(page
859  buf_block_get_space(block));
860  memcpy(page_zip->data + FIL_PAGE_OFFSET,
861  page + FIL_PAGE_OFFSET, 4);
862  memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
864  return;
865  }
866 
867  memset(page, 0, UNIV_PAGE_SIZE);
870  buf_block_get_space(block));
871 }
872 
873 #ifndef UNIV_HOTBACKUP
874 /***********************************************************/
876 static
877 void
878 fsp_init_file_page(
879 /*===============*/
880  buf_block_t* block,
881  mtr_t* mtr)
882 {
883  fsp_init_file_page_low(block);
884 
885  mlog_write_initial_log_record(buf_block_get_frame(block),
886  MLOG_INIT_FILE_PAGE, mtr);
887 }
888 #endif /* !UNIV_HOTBACKUP */
889 
890 /***********************************************************/
893 UNIV_INTERN
894 byte*
895 fsp_parse_init_file_page(
896 /*=====================*/
897  byte* ptr,
898  byte* /*end_ptr __attribute__((unused))*/,
899  buf_block_t* block)
900 {
901  ut_ad(ptr && end_ptr);
902 
903  if (block) {
904  fsp_init_file_page_low(block);
905  }
906 
907  return(ptr);
908 }
909 
910 /**********************************************************************/
912 UNIV_INTERN
913 void
914 fsp_init(void)
915 /*==========*/
916 {
917  /* Does nothing at the moment */
918 }
919 
920 /**********************************************************************/
924 UNIV_INTERN
925 void
926 fsp_header_init_fields(
927 /*===================*/
928  page_t* page,
929  ulint space_id,
930  ulint flags)
932 {
933  /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
934  ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
935  ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
936  format, the tablespace flags should equal table->flags. */
937  ut_a(flags != DICT_TF_COMPACT);
938 
939  mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
940  space_id);
941  mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
942  flags);
943 }
944 
945 #ifndef UNIV_HOTBACKUP
946 /**********************************************************************/
949 UNIV_INTERN
950 void
951 fsp_header_init(
952 /*============*/
953  ulint space,
954  ulint size,
955  mtr_t* mtr)
956 {
957  fsp_header_t* header;
958  buf_block_t* block;
959  page_t* page;
960  ulint flags;
961  ulint zip_size;
962 
963  ut_ad(mtr);
964 
965  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
966 
967  zip_size = dict_table_flags_to_zip_size(flags);
968  block = buf_page_create(space, 0, zip_size, mtr);
969  buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
970  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
971 
972  /* The prior contents of the file page should be ignored */
973 
974  fsp_init_file_page(block, mtr);
975  page = buf_block_get_frame(block);
976 
978  MLOG_2BYTES, mtr);
979 
980  header = FSP_HEADER_OFFSET + page;
981 
982  mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
983  mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
984 
985  mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
986  mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
987  mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
988  MLOG_4BYTES, mtr);
989  mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
990 
991  flst_init(header + FSP_FREE, mtr);
992  flst_init(header + FSP_FREE_FRAG, mtr);
993  flst_init(header + FSP_FULL_FRAG, mtr);
994  flst_init(header + FSP_SEG_INODES_FULL, mtr);
995  flst_init(header + FSP_SEG_INODES_FREE, mtr);
996 
997  mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
998  if (space == 0) {
999  fsp_fill_free_list(FALSE, space, header, mtr);
1000  btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
1001  0, 0, DICT_IBUF_ID_MIN + space,
1002  dict_ind_redundant, mtr);
1003  } else {
1004  fsp_fill_free_list(TRUE, space, header, mtr);
1005  }
1006 }
1007 #endif /* !UNIV_HOTBACKUP */
1008 
1009 /**********************************************************************/
1012 UNIV_INTERN
1013 ulint
1014 fsp_header_get_space_id(
1015 /*====================*/
1016  const page_t* page)
1017 {
1018  ulint fsp_id;
1019  ulint id;
1020 
1021  fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
1022 
1024 
1025  if (id != fsp_id) {
1026  fprintf(stderr,
1027  "InnoDB: Error: space id in fsp header %lu,"
1028  " but in the page header %lu\n",
1029  (ulong) fsp_id, (ulong) id);
1030 
1031  return(ULINT_UNDEFINED);
1032  }
1033 
1034  return(id);
1035 }
1036 
1037 /**********************************************************************/
1040 UNIV_INTERN
1041 ulint
1042 fsp_header_get_flags(
1043 /*=================*/
1044  const page_t* page)
1045 {
1046  ut_ad(!page_offset(page));
1047 
1048  return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
1049 }
1050 
1051 /**********************************************************************/
1054 UNIV_INTERN
1055 ulint
1056 fsp_header_get_zip_size(
1057 /*====================*/
1058  const page_t* page)
1059 {
1060  ulint flags = fsp_header_get_flags(page);
1061 
1062  return(dict_table_flags_to_zip_size(flags));
1063 }
1064 
1065 #ifndef UNIV_HOTBACKUP
1066 /**********************************************************************/
1068 UNIV_INTERN
1069 void
1070 fsp_header_inc_size(
1071 /*================*/
1072  ulint space,
1073  ulint size_inc,
1074  mtr_t* mtr)
1075 {
1076  fsp_header_t* header;
1077  ulint size;
1078  ulint flags;
1079 
1080  ut_ad(mtr);
1081 
1082  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
1083 
1084  header = fsp_get_space_header(space,
1086  mtr);
1087 
1088  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1089 
1090  mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
1091  mtr);
1092 }
1093 
1094 /**********************************************************************/
1100 UNIV_INTERN
1101 ulint
1102 fsp_header_get_free_limit(void)
1103 /*===========================*/
1104 {
1105  fsp_header_t* header;
1106  ulint limit;
1107  mtr_t mtr;
1108 
1109  mtr_start(&mtr);
1110 
1111  mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1112 
1113  header = fsp_get_space_header(0, 0, &mtr);
1114 
1115  limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1116 
1117  limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
1118 
1120 
1121  mtr_commit(&mtr);
1122 
1123  return(limit);
1124 }
1125 
1126 /**********************************************************************/
1132 UNIV_INTERN
1133 ulint
1134 fsp_header_get_tablespace_size(void)
1135 /*================================*/
1136 {
1137  fsp_header_t* header;
1138  ulint size;
1139  mtr_t mtr;
1140 
1141  mtr_start(&mtr);
1142 
1143  mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1144 
1145  header = fsp_get_space_header(0, 0, &mtr);
1146 
1147  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1148 
1149  mtr_commit(&mtr);
1150 
1151  return(size);
1152 }
1153 
1154 /***********************************************************************/
1158 static
1159 ibool
1160 fsp_try_extend_data_file_with_pages(
1161 /*================================*/
1162  ulint space,
1163  ulint page_no,
1164  fsp_header_t* header,
1165  mtr_t* mtr)
1166 {
1167  ibool success;
1168  ulint actual_size;
1169  ulint size;
1170 
1171  ut_a(space != 0);
1172 
1173  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1174 
1175  ut_a(page_no >= size);
1176 
1177  success = fil_extend_space_to_desired_size(&actual_size, space,
1178  page_no + 1);
1179  /* actual_size now has the space size in pages; it may be less than
1180  we wanted if we ran out of disk space */
1181 
1182  mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1183 
1184  return(success);
1185 }
1186 
1187 /***********************************************************************/
1190 static
1191 ibool
1192 fsp_try_extend_data_file(
1193 /*=====================*/
1194  ulint* actual_increase,
1199  ulint space,
1200  fsp_header_t* header,
1201  mtr_t* mtr)
1202 {
1203  ulint size;
1204  ulint zip_size;
1205  ulint new_size;
1206  ulint old_size;
1207  ulint size_increase;
1208  ulint actual_size;
1209  ibool success;
1210 
1211  *actual_increase = 0;
1212 
1213  if (space == 0 && !srv_auto_extend_last_data_file) {
1214 
1215  /* We print the error message only once to avoid
1216  spamming the error log. Note that we don't need
1217  to reset the flag to FALSE as dealing with this
1218  error requires server restart. */
1219  if (fsp_tbs_full_error_printed == FALSE) {
1220  fprintf(stderr,
1221  "InnoDB: Error: Data file(s) ran"
1222  " out of space.\n"
1223  "Please add another data file or"
1224  " use \'autoextend\' for the last"
1225  " data file.\n");
1226  fsp_tbs_full_error_printed = TRUE;
1227  }
1228  return(FALSE);
1229  }
1230 
1231  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1232  zip_size = dict_table_flags_to_zip_size(
1233  mach_read_from_4(header + FSP_SPACE_FLAGS));
1234 
1235  old_size = size;
1236 
1237  if (space == 0) {
1238  if (!srv_last_file_size_max) {
1239  size_increase = SRV_AUTO_EXTEND_INCREMENT;
1240  } else {
1241  if (srv_last_file_size_max
1242  < srv_data_file_sizes[srv_n_data_files - 1]) {
1243 
1244  fprintf(stderr,
1245  "InnoDB: Error: Last data file size"
1246  " is %lu, max size allowed %lu\n",
1247  (ulong) srv_data_file_sizes[
1248  srv_n_data_files - 1],
1249  (ulong) srv_last_file_size_max);
1250  }
1251 
1252  size_increase = srv_last_file_size_max
1253  - srv_data_file_sizes[srv_n_data_files - 1];
1254  if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1255  size_increase = SRV_AUTO_EXTEND_INCREMENT;
1256  }
1257  }
1258  } else {
1259  /* We extend single-table tablespaces first one extent
1260  at a time, but for bigger tablespaces more. It is not
1261  enough to extend always by one extent, because some
1262  extents are frag page extents. */
1263  ulint extent_size;
1265  if (!zip_size) {
1266  extent_size = FSP_EXTENT_SIZE;
1267  } else {
1268  extent_size = FSP_EXTENT_SIZE
1269  * UNIV_PAGE_SIZE / zip_size;
1270  }
1271 
1272  if (size < extent_size) {
1273  /* Let us first extend the file to extent_size */
1274  success = fsp_try_extend_data_file_with_pages(
1275  space, extent_size - 1, header, mtr);
1276  if (!success) {
1277  new_size = mtr_read_ulint(header + FSP_SIZE,
1278  MLOG_4BYTES, mtr);
1279 
1280  *actual_increase = new_size - old_size;
1281 
1282  return(FALSE);
1283  }
1284 
1285  size = extent_size;
1286  }
1287 
1288  if (size < 32 * extent_size) {
1289  size_increase = extent_size;
1290  } else {
1291  /* Below in fsp_fill_free_list() we assume
1292  that we add at most FSP_FREE_ADD extents at
1293  a time */
1294  size_increase = FSP_FREE_ADD * extent_size;
1295  }
1296  }
1297 
1298  if (size_increase == 0) {
1299 
1300  return(TRUE);
1301  }
1302 
1303  success = fil_extend_space_to_desired_size(&actual_size, space,
1304  size + size_increase);
1305  /* We ignore any fragments of a full megabyte when storing the size
1306  to the space header */
1307 
1308  if (!zip_size) {
1309  new_size = ut_calc_align_down(actual_size,
1310  (1024 * 1024) / UNIV_PAGE_SIZE);
1311  } else {
1312  new_size = ut_calc_align_down(actual_size,
1313  (1024 * 1024) / zip_size);
1314  }
1315  mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1316 
1317  *actual_increase = new_size - old_size;
1318 
1319  return(TRUE);
1320 }
1321 
1322 /**********************************************************************/
1326 static
1327 void
1328 fsp_fill_free_list(
1329 /*===============*/
1330  ibool init_space,
1335  ulint space,
1336  fsp_header_t* header,
1337  mtr_t* mtr)
1338 {
1339  ulint limit;
1340  ulint size;
1341  ulint zip_size;
1342  xdes_t* descr;
1343  ulint count = 0;
1344  ulint frag_n_used;
1345  ulint actual_increase;
1346  ulint i;
1347  mtr_t ibuf_mtr;
1348 
1349  ut_ad(header && mtr);
1350  ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
1351 
1352  /* Check if we can fill free list from above the free list limit */
1353  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1354  limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1355 
1356  zip_size = dict_table_flags_to_zip_size(
1357  mach_read_from_4(FSP_SPACE_FLAGS + header));
1358  ut_a(ut_is_2pow(zip_size));
1359  ut_a(zip_size <= UNIV_PAGE_SIZE);
1360  ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
1361 
1362  if (space == 0 && srv_auto_extend_last_data_file
1363  && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1364 
1365  /* Try to increase the last data file size */
1366  fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1367  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1368  }
1369 
1370  if (space != 0 && !init_space
1371  && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1372 
1373  /* Try to increase the .ibd file size */
1374  fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1375  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1376  }
1377 
1378  i = limit;
1379 
1380  while ((init_space && i < 1)
1381  || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1382 
1383  ibool init_xdes;
1384  if (zip_size) {
1385  init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1386  } else {
1387  init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1388  }
1389 
1390  mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1391  MLOG_4BYTES, mtr);
1392 
1393  /* Update the free limit info in the log system and make
1394  a checkpoint */
1395  if (space == 0) {
1396  ut_a(!zip_size);
1398  (i + FSP_EXTENT_SIZE)
1399  / ((1024 * 1024) / UNIV_PAGE_SIZE));
1400  }
1401 
1402  if (UNIV_UNLIKELY(init_xdes)) {
1403 
1404  buf_block_t* block;
1405 
1406  /* We are going to initialize a new descriptor page
1407  and a new ibuf bitmap page: the prior contents of the
1408  pages should be ignored. */
1409 
1410  if (i > 0) {
1411  block = buf_page_create(
1412  space, i, zip_size, mtr);
1413  buf_page_get(space, zip_size, i,
1414  RW_X_LATCH, mtr);
1415  buf_block_dbg_add_level(block,
1416  SYNC_FSP_PAGE);
1417 
1418  fsp_init_file_page(block, mtr);
1419  mlog_write_ulint(buf_block_get_frame(block)
1420  + FIL_PAGE_TYPE,
1422  MLOG_2BYTES, mtr);
1423  }
1424 
1425  /* Initialize the ibuf bitmap page in a separate
1426  mini-transaction because it is low in the latching
1427  order, and we must be able to release its latch
1428  before returning from the fsp routine */
1429 
1430  mtr_start(&ibuf_mtr);
1431 
1432  block = buf_page_create(space,
1433  i + FSP_IBUF_BITMAP_OFFSET,
1434  zip_size, &ibuf_mtr);
1435  buf_page_get(space, zip_size,
1436  i + FSP_IBUF_BITMAP_OFFSET,
1437  RW_X_LATCH, &ibuf_mtr);
1438  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1439 
1440  fsp_init_file_page(block, &ibuf_mtr);
1441 
1442  ibuf_bitmap_page_init(block, &ibuf_mtr);
1443 
1444  mtr_commit(&ibuf_mtr);
1445  }
1446 
1447  descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1448  mtr);
1449  xdes_init(descr, mtr);
1450 
1451  if (UNIV_UNLIKELY(init_xdes)) {
1452 
1453  /* The first page in the extent is a descriptor page
1454  and the second is an ibuf bitmap page: mark them
1455  used */
1456 
1457  xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1458  xdes_set_bit(descr, XDES_FREE_BIT,
1459  FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1460  xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1461 
1462  flst_add_last(header + FSP_FREE_FRAG,
1463  descr + XDES_FLST_NODE, mtr);
1464  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1465  MLOG_4BYTES, mtr);
1466  mlog_write_ulint(header + FSP_FRAG_N_USED,
1467  frag_n_used + 2, MLOG_4BYTES, mtr);
1468  } else {
1469  flst_add_last(header + FSP_FREE,
1470  descr + XDES_FLST_NODE, mtr);
1471  count++;
1472  }
1473 
1474  i += FSP_EXTENT_SIZE;
1475  }
1476 }
1477 
1478 /**********************************************************************/
1481 static
1482 xdes_t*
1483 fsp_alloc_free_extent(
1484 /*==================*/
1485  ulint space,
1486  ulint zip_size,
1488  ulint hint,
1491  mtr_t* mtr)
1492 {
1493  fsp_header_t* header;
1494  fil_addr_t first;
1495  xdes_t* descr;
1496 
1497  ut_ad(mtr);
1498 
1499  header = fsp_get_space_header(space, zip_size, mtr);
1500 
1501  descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1502 
1503  if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1504  /* Ok, we can take this extent */
1505  } else {
1506  /* Take the first extent in the free list */
1507  first = flst_get_first(header + FSP_FREE, mtr);
1508 
1509  if (fil_addr_is_null(first)) {
1510  fsp_fill_free_list(FALSE, space, header, mtr);
1511 
1512  first = flst_get_first(header + FSP_FREE, mtr);
1513  }
1514 
1515  if (fil_addr_is_null(first)) {
1516 
1517  return(NULL); /* No free extents left */
1518  }
1519 
1520  descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1521  }
1522 
1523  flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1524 
1525  return(descr);
1526 }
1527 
1528 /**********************************************************************/
1531 static
1532 ulint
1533 fsp_alloc_free_page(
1534 /*================*/
1535  ulint space,
1536  ulint zip_size,
1538  ulint hint,
1539  mtr_t* mtr)
1540 {
1541  fsp_header_t* header;
1542  fil_addr_t first;
1543  xdes_t* descr;
1544  buf_block_t* block;
1545  ulint free;
1546  ulint frag_n_used;
1547  ulint page_no;
1548  ulint space_size;
1549  ibool success;
1550 
1551  ut_ad(mtr);
1552 
1553  header = fsp_get_space_header(space, zip_size, mtr);
1554 
1555  /* Get the hinted descriptor */
1556  descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1557 
1558  if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1559  /* Ok, we can take this extent */
1560  } else {
1561  /* Else take the first extent in free_frag list */
1562  first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1563 
1564  if (fil_addr_is_null(first)) {
1565  /* There are no partially full fragments: allocate
1566  a free extent and add it to the FREE_FRAG list. NOTE
1567  that the allocation may have as a side-effect that an
1568  extent containing a descriptor page is added to the
1569  FREE_FRAG list. But we will allocate our page from the
1570  the free extent anyway. */
1571 
1572  descr = fsp_alloc_free_extent(space, zip_size,
1573  hint, mtr);
1574 
1575  if (descr == NULL) {
1576  /* No free space left */
1577 
1578  return(FIL_NULL);
1579  }
1580 
1581  xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1582  flst_add_last(header + FSP_FREE_FRAG,
1583  descr + XDES_FLST_NODE, mtr);
1584  } else {
1585  descr = xdes_lst_get_descriptor(space, zip_size,
1586  first, mtr);
1587  }
1588 
1589  /* Reset the hint */
1590  hint = 0;
1591  }
1592 
1593  /* Now we have in descr an extent with at least one free page. Look
1594  for a free page in the extent. */
1595 
1596  free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1597  hint % FSP_EXTENT_SIZE, mtr);
1598  if (free == ULINT_UNDEFINED) {
1599 
1600  ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1601  putc('\n', stderr);
1602 
1603  ut_error;
1604  }
1605 
1606  page_no = xdes_get_offset(descr) + free;
1607 
1608  space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1609 
1610  if (space_size <= page_no) {
1611  /* It must be that we are extending a single-table tablespace
1612  whose size is still < 64 pages */
1613 
1614  ut_a(space != 0);
1615  if (page_no >= FSP_EXTENT_SIZE) {
1616  fprintf(stderr,
1617  "InnoDB: Error: trying to extend a"
1618  " single-table tablespace %lu\n"
1619  "InnoDB: by single page(s) though the"
1620  " space size %lu. Page no %lu.\n",
1621  (ulong) space, (ulong) space_size,
1622  (ulong) page_no);
1623  return(FIL_NULL);
1624  }
1625  success = fsp_try_extend_data_file_with_pages(space, page_no,
1626  header, mtr);
1627  if (!success) {
1628  /* No disk space left */
1629  return(FIL_NULL);
1630  }
1631  }
1632 
1633  xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1634 
1635  /* Update the FRAG_N_USED field */
1636  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1637  mtr);
1638  frag_n_used++;
1639  mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1640  mtr);
1641  if (xdes_is_full(descr, mtr)) {
1642  /* The fragment is full: move it to another list */
1643  flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1644  mtr);
1645  xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1646 
1647  flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1648  mtr);
1649  mlog_write_ulint(header + FSP_FRAG_N_USED,
1650  frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1651  mtr);
1652  }
1653 
1654  /* Initialize the allocated page to the buffer pool, so that it can
1655  be obtained immediately with buf_page_get without need for a disk
1656  read. */
1657 
1658  buf_page_create(space, page_no, zip_size, mtr);
1659 
1660  block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1661  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1662 
1663  /* Prior contents of the page should be ignored */
1664  fsp_init_file_page(block, mtr);
1665 
1666  return(page_no);
1667 }
1668 
1669 /**********************************************************************/
1671 static
1672 void
1673 fsp_free_page(
1674 /*==========*/
1675  ulint space,
1676  ulint zip_size,
1678  ulint page,
1679  mtr_t* mtr)
1680 {
1681  fsp_header_t* header;
1682  xdes_t* descr;
1683  ulint state;
1684  ulint frag_n_used;
1685 
1686  ut_ad(mtr);
1687 
1688  /* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1689 
1690  header = fsp_get_space_header(space, zip_size, mtr);
1691 
1692  descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1693 
1694  state = xdes_get_state(descr, mtr);
1695 
1696  if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1697  fprintf(stderr,
1698  "InnoDB: Error: File space extent descriptor"
1699  " of page %lu has state %lu\n",
1700  (ulong) page,
1701  (ulong) state);
1702  fputs("InnoDB: Dump of descriptor: ", stderr);
1703  ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1704  putc('\n', stderr);
1705 
1706  if (state == XDES_FREE) {
1707  /* We put here some fault tolerance: if the page
1708  is already free, return without doing anything! */
1709 
1710  return;
1711  }
1712 
1713  ut_error;
1714  }
1715 
1716  if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1717  fprintf(stderr,
1718  "InnoDB: Error: File space extent descriptor"
1719  " of page %lu says it is free\n"
1720  "InnoDB: Dump of descriptor: ", (ulong) page);
1721  ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1722  putc('\n', stderr);
1723 
1724  /* We put here some fault tolerance: if the page
1725  is already free, return without doing anything! */
1726 
1727  return;
1728  }
1729 
1730  xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1731  xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1732 
1733  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1734  mtr);
1735  if (state == XDES_FULL_FRAG) {
1736  /* The fragment was full: move it to another list */
1737  flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1738  mtr);
1739  xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1740  flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1741  mtr);
1742  mlog_write_ulint(header + FSP_FRAG_N_USED,
1743  frag_n_used + FSP_EXTENT_SIZE - 1,
1744  MLOG_4BYTES, mtr);
1745  } else {
1746  ut_a(frag_n_used > 0);
1747  mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1748  MLOG_4BYTES, mtr);
1749  }
1750 
1751  if (xdes_is_free(descr, mtr)) {
1752  /* The extent has become free: move it to another list */
1753  flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1754  mtr);
1755  fsp_free_extent(space, zip_size, page, mtr);
1756  }
1757 }
1758 
1759 /**********************************************************************/
1761 static
1762 void
1763 fsp_free_extent(
1764 /*============*/
1765  ulint space,
1766  ulint zip_size,
1768  ulint page,
1769  mtr_t* mtr)
1770 {
1771  fsp_header_t* header;
1772  xdes_t* descr;
1773 
1774  ut_ad(mtr);
1775 
1776  header = fsp_get_space_header(space, zip_size, mtr);
1777 
1778  descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1779 
1780  if (xdes_get_state(descr, mtr) == XDES_FREE) {
1781 
1782  ut_print_buf(stderr, (byte*)descr - 500, 1000);
1783  putc('\n', stderr);
1784 
1785  ut_error;
1786  }
1787 
1788  xdes_init(descr, mtr);
1789 
1790  flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1791 }
1792 
1793 /**********************************************************************/
1796 UNIV_INLINE
1797 fseg_inode_t*
1798 fsp_seg_inode_page_get_nth_inode(
1799 /*=============================*/
1800  page_t* page,
1801  ulint i,
1802  ulint /*zip_size __attribute__((unused))*/,
1804  mtr_t* /*mtr __attribute__((unused))*/)
1806 {
1807  ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1808  ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1809 
1810  return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1811 }
1812 
1813 /**********************************************************************/
1816 static
1817 ulint
1818 fsp_seg_inode_page_find_used(
1819 /*=========================*/
1820  page_t* page,
1821  ulint zip_size,
1822  mtr_t* mtr)
1823 {
1824  ulint i;
1825  fseg_inode_t* inode;
1826 
1827  for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1828 
1829  inode = fsp_seg_inode_page_get_nth_inode(
1830  page, i, zip_size, mtr);
1831 
1832  if (mach_read_from_8(inode + FSEG_ID)) {
1833  /* This is used */
1834 
1835  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1836  == FSEG_MAGIC_N_VALUE);
1837  return(i);
1838  }
1839  }
1840 
1841  return(ULINT_UNDEFINED);
1842 }
1843 
1844 /**********************************************************************/
1847 static
1848 ulint
1849 fsp_seg_inode_page_find_free(
1850 /*=========================*/
1851  page_t* page,
1852  ulint i,
1853  ulint zip_size,
1854  mtr_t* mtr)
1855 {
1856  fseg_inode_t* inode;
1857 
1858  for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1859 
1860  inode = fsp_seg_inode_page_get_nth_inode(
1861  page, i, zip_size, mtr);
1862 
1863  if (!mach_read_from_8(inode + FSEG_ID)) {
1864  /* This is unused */
1865 
1866  return(i);
1867  }
1868 
1869  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1870  == FSEG_MAGIC_N_VALUE);
1871  }
1872 
1873  return(ULINT_UNDEFINED);
1874 }
1875 
1876 /**********************************************************************/
1879 static
1880 ibool
1881 fsp_alloc_seg_inode_page(
1882 /*=====================*/
1883  fsp_header_t* space_header,
1884  mtr_t* mtr)
1885 {
1886  fseg_inode_t* inode;
1887  buf_block_t* block;
1888  page_t* page;
1889  ulint page_no;
1890  ulint space;
1891  ulint zip_size;
1892  ulint i;
1893 
1894  ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1895 
1896  space = page_get_space_id(page_align(space_header));
1897  zip_size = dict_table_flags_to_zip_size(
1898  mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1899 
1900  page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
1901 
1902  if (page_no == FIL_NULL) {
1903 
1904  return(FALSE);
1905  }
1906 
1907  block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1908  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1909 
1910  block->check_index_page_at_flush = FALSE;
1911 
1912  page = buf_block_get_frame(block);
1913 
1915  MLOG_2BYTES, mtr);
1916 
1917  for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1918 
1919  inode = fsp_seg_inode_page_get_nth_inode(page, i,
1920  zip_size, mtr);
1921 
1922  mlog_write_ull(inode + FSEG_ID, 0, mtr);
1923  }
1924 
1925  flst_add_last(space_header + FSP_SEG_INODES_FREE,
1926  page + FSEG_INODE_PAGE_NODE, mtr);
1927  return(TRUE);
1928 }
1929 
1930 /**********************************************************************/
1933 static
1934 fseg_inode_t*
1935 fsp_alloc_seg_inode(
1936 /*================*/
1937  fsp_header_t* space_header,
1938  mtr_t* mtr)
1939 {
1940  ulint page_no;
1941  buf_block_t* block;
1942  page_t* page;
1943  fseg_inode_t* inode;
1944  ibool success;
1945  ulint zip_size;
1946  ulint n;
1947 
1948  ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1949 
1950  if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1951  /* Allocate a new segment inode page */
1952 
1953  success = fsp_alloc_seg_inode_page(space_header, mtr);
1954 
1955  if (!success) {
1956 
1957  return(NULL);
1958  }
1959  }
1960 
1961  page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1962 
1963  zip_size = dict_table_flags_to_zip_size(
1964  mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1965  block = buf_page_get(page_get_space_id(page_align(space_header)),
1966  zip_size, page_no, RW_X_LATCH, mtr);
1967  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1968 
1969  page = buf_block_get_frame(block);
1970 
1971  n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1972 
1973  ut_a(n != ULINT_UNDEFINED);
1974 
1975  inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1976 
1977  if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1978  zip_size, mtr)) {
1979  /* There are no other unused headers left on the page: move it
1980  to another list */
1981 
1982  flst_remove(space_header + FSP_SEG_INODES_FREE,
1983  page + FSEG_INODE_PAGE_NODE, mtr);
1984 
1985  flst_add_last(space_header + FSP_SEG_INODES_FULL,
1986  page + FSEG_INODE_PAGE_NODE, mtr);
1987  }
1988 
1989  ut_ad(!mach_read_from_8(inode + FSEG_ID)
1990  || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1991  return(inode);
1992 }
1993 
1994 /**********************************************************************/
1996 static
1997 void
1998 fsp_free_seg_inode(
1999 /*===============*/
2000  ulint space,
2001  ulint zip_size,
2003  fseg_inode_t* inode,
2004  mtr_t* mtr)
2005 {
2006  page_t* page;
2007  fsp_header_t* space_header;
2008 
2009  page = page_align(inode);
2010 
2011  space_header = fsp_get_space_header(space, zip_size, mtr);
2012 
2013  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2014 
2015  if (ULINT_UNDEFINED
2016  == fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
2017 
2018  /* Move the page to another list */
2019 
2020  flst_remove(space_header + FSP_SEG_INODES_FULL,
2021  page + FSEG_INODE_PAGE_NODE, mtr);
2022 
2023  flst_add_last(space_header + FSP_SEG_INODES_FREE,
2024  page + FSEG_INODE_PAGE_NODE, mtr);
2025  }
2026 
2027  mlog_write_ull(inode + FSEG_ID, 0, mtr);
2028  mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
2029 
2030  if (ULINT_UNDEFINED
2031  == fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
2032 
2033  /* There are no other used headers left on the page: free it */
2034 
2035  flst_remove(space_header + FSP_SEG_INODES_FREE,
2036  page + FSEG_INODE_PAGE_NODE, mtr);
2037 
2038  fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
2039  }
2040 }
2041 
2042 /**********************************************************************/
2045 static
2046 fseg_inode_t*
2047 fseg_inode_try_get(
2048 /*===============*/
2049  fseg_header_t* header,
2050  ulint space,
2051  ulint zip_size,
2053  mtr_t* mtr)
2054 {
2055  fil_addr_t inode_addr;
2056  fseg_inode_t* inode;
2057 
2058  inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
2059  inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
2060  ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
2061 
2062  inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
2063 
2064  if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
2065 
2066  inode = NULL;
2067  } else {
2068  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2069  == FSEG_MAGIC_N_VALUE);
2070  }
2071 
2072  return(inode);
2073 }
2074 
2075 /**********************************************************************/
2078 static
2079 fseg_inode_t*
2080 fseg_inode_get(
2081 /*===========*/
2082  fseg_header_t* header,
2083  ulint space,
2084  ulint zip_size,
2086  mtr_t* mtr)
2087 {
2088  fseg_inode_t* inode
2089  = fseg_inode_try_get(header, space, zip_size, mtr);
2090  ut_a(inode);
2091  return(inode);
2092 }
2093 
2094 /**********************************************************************/
2097 UNIV_INLINE
2098 ulint
2099 fseg_get_nth_frag_page_no(
2100 /*======================*/
2101  fseg_inode_t* inode,
2102  ulint n,
2103  mtr_t* /*mtr __attribute__((unused))*/)
2104 {
2105  ut_ad(inode && mtr);
2106  ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2107  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2108  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2109  return(mach_read_from_4(inode + FSEG_FRAG_ARR
2110  + n * FSEG_FRAG_SLOT_SIZE));
2111 }
2112 
2113 /**********************************************************************/
2115 UNIV_INLINE
2116 void
2117 fseg_set_nth_frag_page_no(
2118 /*======================*/
2119  fseg_inode_t* inode,
2120  ulint n,
2121  ulint page_no,
2122  mtr_t* mtr)
2123 {
2124  ut_ad(inode && mtr);
2125  ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2126  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2127  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2128 
2129  mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
2130  page_no, MLOG_4BYTES, mtr);
2131 }
2132 
2133 /**********************************************************************/
2136 static
2137 ulint
2138 fseg_find_free_frag_page_slot(
2139 /*==========================*/
2140  fseg_inode_t* inode,
2141  mtr_t* mtr)
2142 {
2143  ulint i;
2144  ulint page_no;
2145 
2146  ut_ad(inode && mtr);
2147 
2148  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2149  page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
2150 
2151  if (page_no == FIL_NULL) {
2152 
2153  return(i);
2154  }
2155  }
2156 
2157  return(ULINT_UNDEFINED);
2158 }
2159 
2160 /**********************************************************************/
2163 static
2164 ulint
2165 fseg_find_last_used_frag_page_slot(
2166 /*===============================*/
2167  fseg_inode_t* inode,
2168  mtr_t* mtr)
2169 {
2170  ulint i;
2171  ulint page_no;
2172 
2173  ut_ad(inode && mtr);
2174 
2175  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2176  page_no = fseg_get_nth_frag_page_no(
2177  inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
2178 
2179  if (page_no != FIL_NULL) {
2180 
2181  return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
2182  }
2183  }
2184 
2185  return(ULINT_UNDEFINED);
2186 }
2187 
2188 /**********************************************************************/
2191 static
2192 ulint
2193 fseg_get_n_frag_pages(
2194 /*==================*/
2195  fseg_inode_t* inode,
2196  mtr_t* mtr)
2197 {
2198  ulint i;
2199  ulint count = 0;
2200 
2201  ut_ad(inode && mtr);
2202 
2203  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2204  if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2205  count++;
2206  }
2207  }
2208 
2209  return(count);
2210 }
2211 
2212 /**********************************************************************/
2216 UNIV_INTERN
2217 buf_block_t*
2218 fseg_create_general(
2219 /*================*/
2220  ulint space,
2221  ulint page,
2225  ulint byte_offset,
2227  ibool has_done_reservation,
2233  mtr_t* mtr)
2234 {
2235  ulint flags;
2236  ulint zip_size;
2237  fsp_header_t* space_header;
2238  fseg_inode_t* inode;
2239  ib_id_t seg_id;
2240  buf_block_t* block = 0; /* remove warning */
2241  fseg_header_t* header = 0; /* remove warning */
2242  rw_lock_t* latch;
2243  ibool success;
2244  ulint n_reserved;
2245  ulint i;
2246 
2247  ut_ad(mtr);
2248  ut_ad(byte_offset + FSEG_HEADER_SIZE
2249  <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2250 
2251  latch = fil_space_get_latch(space, &flags);
2252  zip_size = dict_table_flags_to_zip_size(flags);
2253 
2254  if (page != 0) {
2255  block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2256  header = byte_offset + buf_block_get_frame(block);
2257  }
2258 
2259  ut_ad(!mutex_own(&kernel_mutex)
2260  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2261 
2262  mtr_x_lock(latch, mtr);
2263 
2264  if (rw_lock_get_x_lock_count(latch) == 1) {
2265  /* This thread did not own the latch before this call: free
2266  excess pages from the insert buffer free list */
2267 
2268  if (space == IBUF_SPACE_ID) {
2269  ibuf_free_excess_pages();
2270  }
2271  }
2272 
2273  if (!has_done_reservation) {
2274  success = fsp_reserve_free_extents(&n_reserved, space, 2,
2275  FSP_NORMAL, mtr);
2276  if (!success) {
2277  return(NULL);
2278  }
2279  }
2280 
2281  space_header = fsp_get_space_header(space, zip_size, mtr);
2282 
2283  inode = fsp_alloc_seg_inode(space_header, mtr);
2284 
2285  if (inode == NULL) {
2286 
2287  goto funct_exit;
2288  }
2289 
2290  /* Read the next segment id from space header and increment the
2291  value in space header */
2292 
2293  seg_id = mach_read_from_8(space_header + FSP_SEG_ID);
2294 
2295  mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr);
2296 
2297  mlog_write_ull(inode + FSEG_ID, seg_id, mtr);
2298  mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2299 
2300  flst_init(inode + FSEG_FREE, mtr);
2301  flst_init(inode + FSEG_NOT_FULL, mtr);
2302  flst_init(inode + FSEG_FULL, mtr);
2303 
2304  mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2305  MLOG_4BYTES, mtr);
2306  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2307  fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2308  }
2309 
2310  if (page == 0) {
2311  page = fseg_alloc_free_page_low(space, zip_size,
2312  inode, 0, FSP_UP, mtr);
2313 
2314  if (page == FIL_NULL) {
2315 
2316  fsp_free_seg_inode(space, zip_size, inode, mtr);
2317 
2318  goto funct_exit;
2319  }
2320 
2321  block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2322  header = byte_offset + buf_block_get_frame(block);
2323  mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2325  }
2326 
2327  mlog_write_ulint(header + FSEG_HDR_OFFSET,
2328  page_offset(inode), MLOG_2BYTES, mtr);
2329 
2330  mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2331  page_get_page_no(page_align(inode)),
2332  MLOG_4BYTES, mtr);
2333 
2334  mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2335 
2336 funct_exit:
2337  if (!has_done_reservation) {
2338 
2339  fil_space_release_free_extents(space, n_reserved);
2340  }
2341 
2342  return(block);
2343 }
2344 
2345 /**********************************************************************/
2349 UNIV_INTERN
2350 buf_block_t*
2351 fseg_create(
2352 /*========*/
2353  ulint space,
2354  ulint page,
2358  ulint byte_offset,
2360  mtr_t* mtr)
2361 {
2362  return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2363 }
2364 
2365 /**********************************************************************/
2369 static
2370 ulint
2371 fseg_n_reserved_pages_low(
2372 /*======================*/
2373  fseg_inode_t* inode,
2374  ulint* used,
2376  mtr_t* mtr)
2377 {
2378  ulint ret;
2379 
2380  ut_ad(inode && used && mtr);
2381  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2382 
2383  *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2384  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2385  + fseg_get_n_frag_pages(inode, mtr);
2386 
2387  ret = fseg_get_n_frag_pages(inode, mtr)
2388  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2389  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2390  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2391 
2392  return(ret);
2393 }
2394 
2395 /**********************************************************************/
2399 UNIV_INTERN
2400 ulint
2401 fseg_n_reserved_pages(
2402 /*==================*/
2403  fseg_header_t* header,
2404  ulint* used,
2405  mtr_t* mtr)
2406 {
2407  ulint ret;
2408  fseg_inode_t* inode;
2409  ulint space;
2410  ulint flags;
2411  ulint zip_size;
2412  rw_lock_t* latch;
2413 
2414  space = page_get_space_id(page_align(header));
2415  latch = fil_space_get_latch(space, &flags);
2416  zip_size = dict_table_flags_to_zip_size(flags);
2417 
2418  ut_ad(!mutex_own(&kernel_mutex)
2419  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2420 
2421  mtr_x_lock(latch, mtr);
2422 
2423  inode = fseg_inode_get(header, space, zip_size, mtr);
2424 
2425  ret = fseg_n_reserved_pages_low(inode, used, mtr);
2426 
2427  return(ret);
2428 }
2429 
2430 /*********************************************************************/
2435 static
2436 void
2437 fseg_fill_free_list(
2438 /*================*/
2439  fseg_inode_t* inode,
2440  ulint space,
2441  ulint zip_size,
2443  ulint hint,
2445  mtr_t* mtr)
2446 {
2447  xdes_t* descr;
2448  ulint i;
2449  ib_id_t seg_id;
2450  ulint reserved;
2451  ulint used;
2452 
2453  ut_ad(inode && mtr);
2454  ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2455 
2456  reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2457 
2458  if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2459 
2460  /* The segment is too small to allow extents in free list */
2461 
2462  return;
2463  }
2464 
2465  if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2466  /* Free list is not empty */
2467 
2468  return;
2469  }
2470 
2471  for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2472  descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2473 
2474  if ((descr == NULL)
2475  || (XDES_FREE != xdes_get_state(descr, mtr))) {
2476 
2477  /* We cannot allocate the desired extent: stop */
2478 
2479  return;
2480  }
2481 
2482  descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2483 
2484  xdes_set_state(descr, XDES_FSEG, mtr);
2485 
2486  seg_id = mach_read_from_8(inode + FSEG_ID);
2487  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2488  == FSEG_MAGIC_N_VALUE);
2489  mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2490 
2491  flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2492  hint += FSP_EXTENT_SIZE;
2493  }
2494 }
2495 
2496 /*********************************************************************/
2502 static
2503 xdes_t*
2504 fseg_alloc_free_extent(
2505 /*===================*/
2506  fseg_inode_t* inode,
2507  ulint space,
2508  ulint zip_size,
2510  mtr_t* mtr)
2511 {
2512  xdes_t* descr;
2513  ib_id_t seg_id;
2514  fil_addr_t first;
2515 
2516  ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2517  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2518 
2519  if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2520  /* Segment free list is not empty, allocate from it */
2521 
2522  first = flst_get_first(inode + FSEG_FREE, mtr);
2523 
2524  descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2525  } else {
2526  /* Segment free list was empty, allocate from space */
2527  descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2528 
2529  if (descr == NULL) {
2530 
2531  return(NULL);
2532  }
2533 
2534  seg_id = mach_read_from_8(inode + FSEG_ID);
2535 
2536  xdes_set_state(descr, XDES_FSEG, mtr);
2537  mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2538  flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2539 
2540  /* Try to fill the segment free list */
2541  fseg_fill_free_list(inode, space, zip_size,
2542  xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2543  mtr);
2544  }
2545 
2546  return(descr);
2547 }
2548 
2549 /**********************************************************************/
2554 static
2555 ulint
2556 fseg_alloc_free_page_low(
2557 /*=====================*/
2558  ulint space,
2559  ulint zip_size,
2561  fseg_inode_t* seg_inode,
2562  ulint hint,
2563  byte direction,
2568  mtr_t* mtr)
2569 {
2570  fsp_header_t* space_header;
2571  ulint space_size;
2572  ib_id_t seg_id;
2573  ulint used;
2574  ulint reserved;
2575  xdes_t* descr;
2576  ulint ret_page;
2578  xdes_t* ret_descr;
2579  ibool frag_page_allocated = FALSE;
2580  ibool success;
2581  ulint n;
2582 
2583  ut_ad(mtr);
2584  ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2585  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2586  == FSEG_MAGIC_N_VALUE);
2587  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2588  seg_id = mach_read_from_8(seg_inode + FSEG_ID);
2589 
2590  ut_ad(seg_id);
2591 
2592  reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2593 
2594  space_header = fsp_get_space_header(space, zip_size, mtr);
2595 
2596  descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2597  hint, mtr);
2598  if (descr == NULL) {
2599  /* Hint outside space or too high above free limit: reset
2600  hint */
2601  hint = 0;
2602  descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2603  }
2604 
2605  /* In the big if-else below we look for ret_page and ret_descr */
2606  /*-------------------------------------------------------------*/
2607  if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2608  && mach_read_from_8(descr + XDES_ID) == seg_id
2609  && (xdes_get_bit(descr, XDES_FREE_BIT,
2610  hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2611 
2612  /* 1. We can take the hinted page
2613  =================================*/
2614  ret_descr = descr;
2615  ret_page = hint;
2616  /*-----------------------------------------------------------*/
2617  } else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2618  && ((reserved - used) < reserved / FSEG_FILLFACTOR)
2619  && (used >= FSEG_FRAG_LIMIT)) {
2620 
2621  /* 2. We allocate the free extent from space and can take
2622  =========================================================
2623  the hinted page
2624  ===============*/
2625  ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2626 
2627  ut_a(ret_descr == descr);
2628 
2629  xdes_set_state(ret_descr, XDES_FSEG, mtr);
2630  mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
2631  flst_add_last(seg_inode + FSEG_FREE,
2632  ret_descr + XDES_FLST_NODE, mtr);
2633 
2634  /* Try to fill the segment free list */
2635  fseg_fill_free_list(seg_inode, space, zip_size,
2636  hint + FSP_EXTENT_SIZE, mtr);
2637  ret_page = hint;
2638  /*-----------------------------------------------------------*/
2639  } else if ((direction != FSP_NO_DIR)
2640  && ((reserved - used) < reserved / FSEG_FILLFACTOR)
2641  && (used >= FSEG_FRAG_LIMIT)
2642  && (!!(ret_descr
2643  = fseg_alloc_free_extent(seg_inode,
2644  space, zip_size, mtr)))) {
2645 
2646  /* 3. We take any free extent (which was already assigned above
2647  ===============================================================
2648  in the if-condition to ret_descr) and take the lowest or
2649  ========================================================
2650  highest page in it, depending on the direction
2651  ==============================================*/
2652  ret_page = xdes_get_offset(ret_descr);
2653 
2654  if (direction == FSP_DOWN) {
2655  ret_page += FSP_EXTENT_SIZE - 1;
2656  }
2657  /*-----------------------------------------------------------*/
2658  } else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2659  && mach_read_from_8(descr + XDES_ID) == seg_id
2660  && (!xdes_is_full(descr, mtr))) {
2661 
2662  /* 4. We can take the page from the same extent as the
2663  ======================================================
2664  hinted page (and the extent already belongs to the
2665  ==================================================
2666  segment)
2667  ========*/
2668  ret_descr = descr;
2669  ret_page = xdes_get_offset(ret_descr)
2670  + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2671  hint % FSP_EXTENT_SIZE, mtr);
2672  /*-----------------------------------------------------------*/
2673  } else if (reserved - used > 0) {
2674  /* 5. We take any unused page from the segment
2675  ==============================================*/
2676  fil_addr_t first;
2677 
2678  if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2679  first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2680  mtr);
2681  } else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2682  first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2683  } else {
2684  ut_error;
2685  return(FIL_NULL);
2686  }
2687 
2688  ret_descr = xdes_lst_get_descriptor(space, zip_size,
2689  first, mtr);
2690  ret_page = xdes_get_offset(ret_descr)
2691  + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2692  0, mtr);
2693  /*-----------------------------------------------------------*/
2694  } else if (used < FSEG_FRAG_LIMIT) {
2695  /* 6. We allocate an individual page from the space
2696  ===================================================*/
2697  ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
2698  ret_descr = NULL;
2699 
2700  frag_page_allocated = TRUE;
2701 
2702  if (ret_page != FIL_NULL) {
2703  /* Put the page in the fragment page array of the
2704  segment */
2705  n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2706  ut_a(n != FIL_NULL);
2707 
2708  fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2709  mtr);
2710  }
2711  /*-----------------------------------------------------------*/
2712  } else {
2713  /* 7. We allocate a new extent and take its first page
2714  ======================================================*/
2715  ret_descr = fseg_alloc_free_extent(seg_inode,
2716  space, zip_size, mtr);
2717 
2718  if (ret_descr == NULL) {
2719  ret_page = FIL_NULL;
2720  } else {
2721  ret_page = xdes_get_offset(ret_descr);
2722  }
2723  }
2724 
2725  if (ret_page == FIL_NULL) {
2726  /* Page could not be allocated */
2727 
2728  return(FIL_NULL);
2729  }
2730 
2731  if (space != 0) {
2732  space_size = fil_space_get_size(space);
2733 
2734  if (space_size <= ret_page) {
2735  /* It must be that we are extending a single-table
2736  tablespace whose size is still < 64 pages */
2737 
2738  if (ret_page >= FSP_EXTENT_SIZE) {
2739  fprintf(stderr,
2740  "InnoDB: Error (2): trying to extend"
2741  " a single-table tablespace %lu\n"
2742  "InnoDB: by single page(s) though"
2743  " the space size %lu. Page no %lu.\n",
2744  (ulong) space, (ulong) space_size,
2745  (ulong) ret_page);
2746  return(FIL_NULL);
2747  }
2748 
2749  success = fsp_try_extend_data_file_with_pages(
2750  space, ret_page, space_header, mtr);
2751  if (!success) {
2752  /* No disk space left */
2753  return(FIL_NULL);
2754  }
2755  }
2756  }
2757 
2758  if (!frag_page_allocated) {
2759  /* Initialize the allocated page to buffer pool, so that it
2760  can be obtained immediately with buf_page_get without need
2761  for a disk read */
2762  buf_block_t* block;
2763  ulint page_zip_size = dict_table_flags_to_zip_size(
2764  mach_read_from_4(FSP_SPACE_FLAGS + space_header));
2765 
2766  block = buf_page_create(space, ret_page, page_zip_size, mtr);
2767  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
2768 
2769  if (UNIV_UNLIKELY(block != buf_page_get(space, page_zip_size,
2770  ret_page, RW_X_LATCH,
2771  mtr))) {
2772  ut_error;
2773  }
2774 
2775  /* The prior contents of the page should be ignored */
2776  fsp_init_file_page(block, mtr);
2777 
2778  /* At this point we know the extent and the page offset.
2779  The extent is still in the appropriate list (FSEG_NOT_FULL
2780  or FSEG_FREE), and the page is not yet marked as used. */
2781 
2782  ut_ad(xdes_get_descriptor(space, page_zip_size, ret_page, mtr)
2783  == ret_descr);
2784  ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2785  ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2786 
2787  fseg_mark_page_used(seg_inode, space, page_zip_size, ret_page, mtr);
2788  }
2789 
2790  buf_reset_check_index_page_at_flush(space, ret_page);
2791 
2792  return(ret_page);
2793 }
2794 
2795 /**********************************************************************/
2800 UNIV_INTERN
2801 ulint
2802 fseg_alloc_free_page_general(
2803 /*=========================*/
2804  fseg_header_t* seg_header,
2805  ulint hint,
2806  byte direction,
2811  ibool has_done_reservation,
2816  mtr_t* mtr)
2817 {
2818  fseg_inode_t* inode;
2819  ulint space;
2820  ulint flags;
2821  ulint zip_size;
2822  rw_lock_t* latch;
2823  ibool success;
2824  ulint page_no;
2825  ulint n_reserved;
2826 
2827  space = page_get_space_id(page_align(seg_header));
2828 
2829  latch = fil_space_get_latch(space, &flags);
2830 
2831  zip_size = dict_table_flags_to_zip_size(flags);
2832 
2833  ut_ad(!mutex_own(&kernel_mutex)
2834  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2835 
2836  mtr_x_lock(latch, mtr);
2837 
2838  if (rw_lock_get_x_lock_count(latch) == 1) {
2839  /* This thread did not own the latch before this call: free
2840  excess pages from the insert buffer free list */
2841 
2842  if (space == IBUF_SPACE_ID) {
2843  ibuf_free_excess_pages();
2844  }
2845  }
2846 
2847  inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2848 
2849  if (!has_done_reservation) {
2850  success = fsp_reserve_free_extents(&n_reserved, space, 2,
2851  FSP_NORMAL, mtr);
2852  if (!success) {
2853  return(FIL_NULL);
2854  }
2855  }
2856 
2857  page_no = fseg_alloc_free_page_low(space, zip_size,
2858  inode, hint, direction, mtr);
2859  if (!has_done_reservation) {
2860  fil_space_release_free_extents(space, n_reserved);
2861  }
2862 
2863  return(page_no);
2864 }
2865 
2866 /**********************************************************************/
2871 UNIV_INTERN
2872 ulint
2873 fseg_alloc_free_page(
2874 /*=================*/
2875  fseg_header_t* seg_header,
2876  ulint hint,
2877  byte direction,
2882  mtr_t* mtr)
2883 {
2884  return(fseg_alloc_free_page_general(seg_header, hint, direction,
2885  FALSE, mtr));
2886 }
2887 
2888 /**********************************************************************/
2895 static
2896 ibool
2897 fsp_reserve_free_pages(
2898 /*===================*/
2899  ulint space,
2900  fsp_header_t* space_header,
2902  ulint size,
2904  mtr_t* mtr)
2905 {
2906  xdes_t* descr;
2907  ulint n_used;
2908 
2909  ut_a(space != 0);
2910  ut_a(size < FSP_EXTENT_SIZE / 2);
2911 
2912  descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2913  mtr);
2914  n_used = xdes_get_n_used(descr, mtr);
2915 
2916  ut_a(n_used <= size);
2917 
2918  if (size >= n_used + 2) {
2919 
2920  return(TRUE);
2921  }
2922 
2923  return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2924  space_header, mtr));
2925 }
2926 
2927 /**********************************************************************/
2953 UNIV_INTERN
2954 ibool
2955 fsp_reserve_free_extents(
2956 /*=====================*/
2957  ulint* n_reserved,
2960  ulint space,
2961  ulint n_ext,
2962  ulint alloc_type,
2963  mtr_t* mtr)
2964 {
2965  fsp_header_t* space_header;
2966  rw_lock_t* latch;
2967  ulint n_free_list_ext;
2968  ulint free_limit;
2969  ulint size;
2970  ulint flags;
2971  ulint zip_size;
2972  ulint n_free;
2973  ulint n_free_up;
2974  ulint reserve;
2975  ibool success;
2976  ulint n_pages_added;
2977 
2978  ut_ad(mtr);
2979  *n_reserved = n_ext;
2980 
2981  latch = fil_space_get_latch(space, &flags);
2982  zip_size = dict_table_flags_to_zip_size(flags);
2983 
2984  ut_ad(!mutex_own(&kernel_mutex)
2985  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2986 
2987  mtr_x_lock(latch, mtr);
2988 
2989  space_header = fsp_get_space_header(space, zip_size, mtr);
2990 try_again:
2991  size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
2992 
2993  if (size < FSP_EXTENT_SIZE / 2) {
2994  /* Use different rules for small single-table tablespaces */
2995  *n_reserved = 0;
2996  return(fsp_reserve_free_pages(space, space_header, size, mtr));
2997  }
2998 
2999  n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
3000 
3001  free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3002  MLOG_4BYTES, mtr);
3003 
3004  /* Below we play safe when counting free extents above the free limit:
3005  some of them will contain extent descriptor pages, and therefore
3006  will not be free extents */
3007 
3008  n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3009 
3010  if (n_free_up > 0) {
3011  n_free_up--;
3012  if (!zip_size) {
3013  n_free_up -= n_free_up
3014  / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3015  } else {
3016  n_free_up -= n_free_up
3017  / (zip_size / FSP_EXTENT_SIZE);
3018  }
3019  }
3020 
3021  n_free = n_free_list_ext + n_free_up;
3022 
3023  if (alloc_type == FSP_NORMAL) {
3024  /* We reserve 1 extent + 0.5 % of the space size to undo logs
3025  and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3026  code is duplicated in the function below! */
3027 
3028  reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3029 
3030  if (n_free <= reserve + n_ext) {
3031 
3032  goto try_to_extend;
3033  }
3034  } else if (alloc_type == FSP_UNDO) {
3035  /* We reserve 0.5 % of the space size to cleaning operations */
3036 
3037  reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
3038 
3039  if (n_free <= reserve + n_ext) {
3040 
3041  goto try_to_extend;
3042  }
3043  } else {
3044  ut_a(alloc_type == FSP_CLEANING);
3045  }
3046 
3047  success = fil_space_reserve_free_extents(space, n_free, n_ext);
3048 
3049  if (success) {
3050  return(TRUE);
3051  }
3052 try_to_extend:
3053  success = fsp_try_extend_data_file(&n_pages_added, space,
3054  space_header, mtr);
3055  if (success && n_pages_added > 0) {
3056 
3057  goto try_again;
3058  }
3059 
3060  return(FALSE);
3061 }
3062 
3063 /**********************************************************************/
3069 UNIV_INTERN
3070 ullint
3071 fsp_get_available_space_in_free_extents(
3072 /*====================================*/
3073  ulint space)
3074 {
3075  fsp_header_t* space_header;
3076  ulint n_free_list_ext;
3077  ulint free_limit;
3078  ulint size;
3079  ulint flags;
3080  ulint zip_size;
3081  ulint n_free;
3082  ulint n_free_up;
3083  ulint reserve;
3084  rw_lock_t* latch;
3085  mtr_t mtr;
3086 
3087  ut_ad(!mutex_own(&kernel_mutex));
3088 
3089  /* The convoluted mutex acquire is to overcome latching order
3090  issues: The problem is that the fil_mutex is at a lower level
3091  than the tablespace latch and the buffer pool mutex. We have to
3092  first prevent any operations on the file system by acquiring the
3093  dictionary mutex. Then acquire the tablespace latch to obey the
3094  latching order and then release the dictionary mutex. That way we
3095  ensure that the tablespace instance can't be freed while we are
3096  examining its contents (see fil_space_free()).
3097 
3098  However, there is one further complication, we release the fil_mutex
3099  when we need to invalidate the the pages in the buffer pool and we
3100  reacquire the fil_mutex when deleting and freeing the tablespace
3101  instance in fil0fil.c. Here we need to account for that situation
3102  too. */
3103 
3104  mutex_enter(&dict_sys->mutex);
3105 
3106  /* At this stage there is no guarantee that the tablespace even
3107  exists in the cache. */
3108 
3109  if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
3110 
3111  mutex_exit(&dict_sys->mutex);
3112 
3113  return(ULLINT_UNDEFINED);
3114  }
3115 
3116  mtr_start(&mtr);
3117 
3118  latch = fil_space_get_latch(space, &flags);
3119 
3120  /* This should ensure that the tablespace instance can't be freed
3121  by another thread. However, the tablespace pages can still be freed
3122  from the buffer pool. We need to check for that again. */
3123 
3124  zip_size = dict_table_flags_to_zip_size(flags);
3125 
3126  mtr_x_lock(latch, &mtr);
3127 
3128  mutex_exit(&dict_sys->mutex);
3129 
3130  /* At this point it is possible for the tablespace to be deleted and
3131  its pages removed from the buffer pool. We need to check for that
3132  situation. However, the tablespace instance can't be deleted because
3133  our latching above should ensure that. */
3134 
3135  if (fil_tablespace_is_being_deleted(space)) {
3136 
3137  mtr_commit(&mtr);
3138 
3139  return(ULLINT_UNDEFINED);
3140  }
3141 
3142  /* From here on even if the user has dropped the tablespace, the
3143  pages _must_ still exist in the buffer pool and the tablespace
3144  instance _must_ be in the file system hash table. */
3145 
3146  space_header = fsp_get_space_header(space, zip_size, &mtr);
3147 
3148  size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
3149 
3150  n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
3151 
3152  free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3153  MLOG_4BYTES, &mtr);
3154  mtr_commit(&mtr);
3155 
3156  if (size < FSP_EXTENT_SIZE) {
3157  ut_a(space != 0); /* This must be a single-table
3158  tablespace */
3159 
3160  return(0); /* TODO: count free frag pages and
3161  return a value based on that */
3162  }
3163 
3164  /* Below we play safe when counting free extents above the free limit:
3165  some of them will contain extent descriptor pages, and therefore
3166  will not be free extents */
3167 
3168  n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3169 
3170  if (n_free_up > 0) {
3171  n_free_up--;
3172  if (!zip_size) {
3173  n_free_up -= n_free_up
3174  / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3175  } else {
3176  n_free_up -= n_free_up
3177  / (zip_size / FSP_EXTENT_SIZE);
3178  }
3179  }
3180 
3181  n_free = n_free_list_ext + n_free_up;
3182 
3183  /* We reserve 1 extent + 0.5 % of the space size to undo logs
3184  and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3185  code is duplicated in the function above! */
3186 
3187  reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3188 
3189  if (reserve > n_free) {
3190  return(0);
3191  }
3192 
3193  if (!zip_size) {
3194  return((ullint) (n_free - reserve)
3195  * FSP_EXTENT_SIZE
3196  * (UNIV_PAGE_SIZE / 1024));
3197  } else {
3198  return((ullint) (n_free - reserve)
3199  * FSP_EXTENT_SIZE
3200  * (zip_size / 1024));
3201  }
3202 }
3203 
3204 /********************************************************************/
3207 static
3208 void
3209 fseg_mark_page_used(
3210 /*================*/
3211  fseg_inode_t* seg_inode,
3212  ulint space,
3213  ulint zip_size,
3215  ulint page,
3216  mtr_t* mtr)
3217 {
3218  xdes_t* descr;
3219  ulint not_full_n_used;
3220 
3221  ut_ad(seg_inode && mtr);
3222  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3223  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3224  == FSEG_MAGIC_N_VALUE);
3225 
3226  descr = xdes_get_descriptor(space, zip_size, page, mtr);
3227 
3228  ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
3229  == mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
3230 
3231  if (xdes_is_free(descr, mtr)) {
3232  /* We move the extent from the free list to the
3233  NOT_FULL list */
3234  flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3235  mtr);
3236  flst_add_last(seg_inode + FSEG_NOT_FULL,
3237  descr + XDES_FLST_NODE, mtr);
3238  }
3239 
3240  ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
3241  == TRUE);
3242  /* We mark the page as used */
3243  xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3244 
3245  not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3246  MLOG_4BYTES, mtr);
3247  not_full_n_used++;
3248  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3249  MLOG_4BYTES, mtr);
3250  if (xdes_is_full(descr, mtr)) {
3251  /* We move the extent from the NOT_FULL list to the
3252  FULL list */
3253  flst_remove(seg_inode + FSEG_NOT_FULL,
3254  descr + XDES_FLST_NODE, mtr);
3255  flst_add_last(seg_inode + FSEG_FULL,
3256  descr + XDES_FLST_NODE, mtr);
3257 
3258  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3259  not_full_n_used - FSP_EXTENT_SIZE,
3260  MLOG_4BYTES, mtr);
3261  }
3262 }
3263 
3264 /**********************************************************************/
3266 static
3267 void
3268 fseg_free_page_low(
3269 /*===============*/
3270  fseg_inode_t* seg_inode,
3271  ulint space,
3272  ulint zip_size,
3274  ulint page,
3275  mtr_t* mtr)
3276 {
3277  xdes_t* descr;
3278  ulint not_full_n_used;
3279  ulint state;
3280  ib_id_t descr_id;
3281  ib_id_t seg_id;
3282  ulint i;
3283 
3284  ut_ad(seg_inode && mtr);
3285  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3286  == FSEG_MAGIC_N_VALUE);
3287  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3288 
3289  /* Drop search system page hash index if the page is found in
3290  the pool and is hashed */
3291 
3292  btr_search_drop_page_hash_when_freed(space, zip_size, page);
3293 
3294  descr = xdes_get_descriptor(space, zip_size, page, mtr);
3295 
3296  ut_a(descr);
3297  if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
3298  fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3299  stderr);
3300  ut_print_buf(stderr, descr, 40);
3301 
3302  fprintf(stderr, "\n"
3303  "InnoDB: Serious error! InnoDB is trying to"
3304  " free page %lu\n"
3305  "InnoDB: though it is already marked as free"
3306  " in the tablespace!\n"
3307  "InnoDB: The tablespace free space info is corrupt.\n"
3308  "InnoDB: You may need to dump your"
3309  " InnoDB tables and recreate the whole\n"
3310  "InnoDB: database!\n", (ulong) page);
3311 crash:
3312  fputs("InnoDB: Please refer to\n"
3313  "InnoDB: " REFMAN "forcing-recovery.html\n"
3314  "InnoDB: about forcing recovery.\n", stderr);
3315  ut_error;
3316  }
3317 
3318  state = xdes_get_state(descr, mtr);
3319 
3320  if (state != XDES_FSEG) {
3321  /* The page is in the fragment pages of the segment */
3322 
3323  for (i = 0;; i++) {
3324  if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3325  == page) {
3326 
3327  fseg_set_nth_frag_page_no(seg_inode, i,
3328  FIL_NULL, mtr);
3329  break;
3330  }
3331  }
3332 
3333  fsp_free_page(space, zip_size, page, mtr);
3334 
3335  return;
3336  }
3337 
3338  /* If we get here, the page is in some extent of the segment */
3339 
3340  descr_id = mach_read_from_8(descr + XDES_ID);
3341  seg_id = mach_read_from_8(seg_inode + FSEG_ID);
3342 #if 0
3343  fprintf(stderr,
3344  "InnoDB: InnoDB is freeing space %lu page %lu,\n"
3345  "InnoDB: which belongs to descr seg %llu\n"
3346  "InnoDB: segment %llu.\n",
3347  (ulong) space, (ulong) page,
3348  (ullint) descr_id,
3349  (ullint) seg_id);
3350 #endif /* 0 */
3351  if (UNIV_UNLIKELY(descr_id != seg_id)) {
3352  fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3353  stderr);
3354  ut_print_buf(stderr, descr, 40);
3355  fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3356  ut_print_buf(stderr, seg_inode, 40);
3357  putc('\n', stderr);
3358 
3359  fprintf(stderr,
3360  "InnoDB: Serious error: InnoDB is trying to"
3361  " free space %lu page %lu,\n"
3362  "InnoDB: which does not belong to"
3363  " segment %llu but belongs\n"
3364  "InnoDB: to segment %llu.\n",
3365  (ulong) space, (ulong) page,
3366  (ullint) descr_id,
3367  (ullint) seg_id);
3368  goto crash;
3369  }
3370 
3371  not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3372  MLOG_4BYTES, mtr);
3373  if (xdes_is_full(descr, mtr)) {
3374  /* The fragment is full: move it to another list */
3375  flst_remove(seg_inode + FSEG_FULL,
3376  descr + XDES_FLST_NODE, mtr);
3377  flst_add_last(seg_inode + FSEG_NOT_FULL,
3378  descr + XDES_FLST_NODE, mtr);
3379  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3380  not_full_n_used + FSP_EXTENT_SIZE - 1,
3381  MLOG_4BYTES, mtr);
3382  } else {
3383  ut_a(not_full_n_used > 0);
3384  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3385  not_full_n_used - 1, MLOG_4BYTES, mtr);
3386  }
3387 
3388  xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3389  xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3390 
3391  if (xdes_is_free(descr, mtr)) {
3392  /* The extent has become free: free it to space */
3393  flst_remove(seg_inode + FSEG_NOT_FULL,
3394  descr + XDES_FLST_NODE, mtr);
3395  fsp_free_extent(space, zip_size, page, mtr);
3396  }
3397 }
3398 
3399 /**********************************************************************/
3401 UNIV_INTERN
3402 void
3403 fseg_free_page(
3404 /*===========*/
3405  fseg_header_t* seg_header,
3406  ulint space,
3407  ulint page,
3408  mtr_t* mtr)
3409 {
3410  ulint flags;
3411  ulint zip_size;
3412  fseg_inode_t* seg_inode;
3413  rw_lock_t* latch;
3414 
3415  latch = fil_space_get_latch(space, &flags);
3416  zip_size = dict_table_flags_to_zip_size(flags);
3417 
3418  ut_ad(!mutex_own(&kernel_mutex)
3419  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3420 
3421  mtr_x_lock(latch, mtr);
3422 
3423  seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3424 
3425  fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3426 
3427 #ifdef UNIV_DEBUG_FILE_ACCESSES
3428  buf_page_set_file_page_was_freed(space, page);
3429 #endif
3430 }
3431 
3432 /**********************************************************************/
3434 static
3435 void
3436 fseg_free_extent(
3437 /*=============*/
3438  fseg_inode_t* seg_inode,
3439  ulint space,
3440  ulint zip_size,
3442  ulint page,
3443  mtr_t* mtr)
3444 {
3445  ulint first_page_in_extent;
3446  xdes_t* descr;
3447  ulint not_full_n_used;
3448  ulint descr_n_used;
3449  ulint i;
3450 
3451  ut_ad(seg_inode && mtr);
3452 
3453  descr = xdes_get_descriptor(space, zip_size, page, mtr);
3454 
3455  ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3456  ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
3457  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3458  == FSEG_MAGIC_N_VALUE);
3459 
3460  first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3461 
3462  for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3463  if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3464 
3465  /* Drop search system page hash index if the page is
3466  found in the pool and is hashed */
3467 
3468  btr_search_drop_page_hash_when_freed(
3469  space, zip_size, first_page_in_extent + i);
3470  }
3471  }
3472 
3473  if (xdes_is_full(descr, mtr)) {
3474  flst_remove(seg_inode + FSEG_FULL,
3475  descr + XDES_FLST_NODE, mtr);
3476  } else if (xdes_is_free(descr, mtr)) {
3477  flst_remove(seg_inode + FSEG_FREE,
3478  descr + XDES_FLST_NODE, mtr);
3479  } else {
3480  flst_remove(seg_inode + FSEG_NOT_FULL,
3481  descr + XDES_FLST_NODE, mtr);
3482 
3483  not_full_n_used = mtr_read_ulint(
3484  seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3485 
3486  descr_n_used = xdes_get_n_used(descr, mtr);
3487  ut_a(not_full_n_used >= descr_n_used);
3488  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3489  not_full_n_used - descr_n_used,
3490  MLOG_4BYTES, mtr);
3491  }
3492 
3493  fsp_free_extent(space, zip_size, page, mtr);
3494 
3495 #ifdef UNIV_DEBUG_FILE_ACCESSES
3496  for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3497 
3498  buf_page_set_file_page_was_freed(space,
3499  first_page_in_extent + i);
3500  }
3501 #endif
3502 }
3503 
3504 /**********************************************************************/
3510 UNIV_INTERN
3511 ibool
3512 fseg_free_step(
3513 /*===========*/
3514  fseg_header_t* header,
3518  mtr_t* mtr)
3519 {
3520  ulint n;
3521  ulint page;
3522  xdes_t* descr;
3523  fseg_inode_t* inode;
3524  ulint space;
3525  ulint flags;
3526  ulint zip_size;
3527  ulint header_page;
3528  rw_lock_t* latch;
3529 
3530  space = page_get_space_id(page_align(header));
3531  header_page = page_get_page_no(page_align(header));
3532 
3533  latch = fil_space_get_latch(space, &flags);
3534  zip_size = dict_table_flags_to_zip_size(flags);
3535 
3536  ut_ad(!mutex_own(&kernel_mutex)
3537  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3538 
3539  mtr_x_lock(latch, mtr);
3540 
3541  descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3542 
3543  /* Check that the header resides on a page which has not been
3544  freed yet */
3545 
3546  ut_a(descr);
3547  ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
3548  header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3549  inode = fseg_inode_try_get(header, space, zip_size, mtr);
3550 
3551  if (UNIV_UNLIKELY(inode == NULL)) {
3552  fprintf(stderr, "double free of inode from %u:%u\n",
3553  (unsigned) space, (unsigned) header_page);
3554  return(TRUE);
3555  }
3556 
3557  descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3558 
3559  if (descr != NULL) {
3560  /* Free the extent held by the segment */
3561  page = xdes_get_offset(descr);
3562 
3563  fseg_free_extent(inode, space, zip_size, page, mtr);
3564 
3565  return(FALSE);
3566  }
3567 
3568  /* Free a frag page */
3569  n = fseg_find_last_used_frag_page_slot(inode, mtr);
3570 
3571  if (n == ULINT_UNDEFINED) {
3572  /* Freeing completed: free the segment inode */
3573  fsp_free_seg_inode(space, zip_size, inode, mtr);
3574 
3575  return(TRUE);
3576  }
3577 
3578  fseg_free_page_low(inode, space, zip_size,
3579  fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3580 
3581  n = fseg_find_last_used_frag_page_slot(inode, mtr);
3582 
3583  if (n == ULINT_UNDEFINED) {
3584  /* Freeing completed: free the segment inode */
3585  fsp_free_seg_inode(space, zip_size, inode, mtr);
3586 
3587  return(TRUE);
3588  }
3589 
3590  return(FALSE);
3591 }
3592 
3593 /**********************************************************************/
3597 UNIV_INTERN
3598 ibool
3599 fseg_free_step_not_header(
3600 /*======================*/
3601  fseg_header_t* header,
3603  mtr_t* mtr)
3604 {
3605  ulint n;
3606  ulint page;
3607  xdes_t* descr;
3608  fseg_inode_t* inode;
3609  ulint space;
3610  ulint flags;
3611  ulint zip_size;
3612  ulint page_no;
3613  rw_lock_t* latch;
3614 
3615  space = page_get_space_id(page_align(header));
3616 
3617  latch = fil_space_get_latch(space, &flags);
3618  zip_size = dict_table_flags_to_zip_size(flags);
3619 
3620  ut_ad(!mutex_own(&kernel_mutex)
3621  || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3622 
3623  mtr_x_lock(latch, mtr);
3624 
3625  inode = fseg_inode_get(header, space, zip_size, mtr);
3626 
3627  descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3628 
3629  if (descr != NULL) {
3630  /* Free the extent held by the segment */
3631  page = xdes_get_offset(descr);
3632 
3633  fseg_free_extent(inode, space, zip_size, page, mtr);
3634 
3635  return(FALSE);
3636  }
3637 
3638  /* Free a frag page */
3639 
3640  n = fseg_find_last_used_frag_page_slot(inode, mtr);
3641 
3642  if (n == ULINT_UNDEFINED) {
3643  ut_error;
3644  }
3645 
3646  page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3647 
3648  if (page_no == page_get_page_no(page_align(header))) {
3649 
3650  return(TRUE);
3651  }
3652 
3653  fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3654 
3655  return(FALSE);
3656 }
3657 
3658 /**********************************************************************/
3663 static
3664 xdes_t*
3665 fseg_get_first_extent(
3666 /*==================*/
3667  fseg_inode_t* inode,
3668  ulint space,
3669  ulint zip_size,
3671  mtr_t* mtr)
3672 {
3673  fil_addr_t first;
3674  xdes_t* descr;
3675 
3676  ut_ad(inode && mtr);
3677 
3678  ut_ad(space == page_get_space_id(page_align(inode)));
3679  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3680 
3681  first = fil_addr_null;
3682 
3683  if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3684 
3685  first = flst_get_first(inode + FSEG_FULL, mtr);
3686 
3687  } else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3688 
3689  first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3690 
3691  } else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3692 
3693  first = flst_get_first(inode + FSEG_FREE, mtr);
3694  }
3695 
3696  if (first.page == FIL_NULL) {
3697 
3698  return(NULL);
3699  }
3700  descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3701 
3702  return(descr);
3703 }
3704 
3705 /*******************************************************************/
3708 static
3709 ibool
3710 fseg_validate_low(
3711 /*==============*/
3712  fseg_inode_t* inode,
3713  mtr_t* mtr2)
3714 {
3715  ulint space;
3716  ib_id_t seg_id;
3717  mtr_t mtr;
3718  xdes_t* descr;
3719  fil_addr_t node_addr;
3720  ulint n_used = 0;
3721  ulint n_used2 = 0;
3722 
3723  ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3724  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3725 
3726  space = page_get_space_id(page_align(inode));
3727 
3728  seg_id = mach_read_from_8(inode + FSEG_ID);
3729  n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3730  MLOG_4BYTES, mtr2);
3731  flst_validate(inode + FSEG_FREE, mtr2);
3732  flst_validate(inode + FSEG_NOT_FULL, mtr2);
3733  flst_validate(inode + FSEG_FULL, mtr2);
3734 
3735  /* Validate FSEG_FREE list */
3736  node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3737 
3738  while (!fil_addr_is_null(node_addr)) {
3739  ulint flags;
3740  ulint zip_size;
3741 
3742  mtr_start(&mtr);
3743  mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3744  zip_size = dict_table_flags_to_zip_size(flags);
3745 
3746  descr = xdes_lst_get_descriptor(space, zip_size,
3747  node_addr, &mtr);
3748 
3749  ut_a(xdes_get_n_used(descr, &mtr) == 0);
3750  ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3751  ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3752 
3753  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3754  mtr_commit(&mtr);
3755  }
3756 
3757  /* Validate FSEG_NOT_FULL list */
3758 
3759  node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3760 
3761  while (!fil_addr_is_null(node_addr)) {
3762  ulint flags;
3763  ulint zip_size;
3764 
3765  mtr_start(&mtr);
3766  mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3767  zip_size = dict_table_flags_to_zip_size(flags);
3768 
3769  descr = xdes_lst_get_descriptor(space, zip_size,
3770  node_addr, &mtr);
3771 
3772  ut_a(xdes_get_n_used(descr, &mtr) > 0);
3773  ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3774  ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3775  ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3776 
3777  n_used2 += xdes_get_n_used(descr, &mtr);
3778 
3779  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3780  mtr_commit(&mtr);
3781  }
3782 
3783  /* Validate FSEG_FULL list */
3784 
3785  node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3786 
3787  while (!fil_addr_is_null(node_addr)) {
3788  ulint flags;
3789  ulint zip_size;
3790 
3791  mtr_start(&mtr);
3792  mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3793  zip_size = dict_table_flags_to_zip_size(flags);
3794 
3795  descr = xdes_lst_get_descriptor(space, zip_size,
3796  node_addr, &mtr);
3797 
3798  ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3799  ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3800  ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3801 
3802  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3803  mtr_commit(&mtr);
3804  }
3805 
3806  ut_a(n_used == n_used2);
3807 
3808  return(TRUE);
3809 }
3810 
3811 #ifdef UNIV_DEBUG
3812 /*******************************************************************/
3815 UNIV_INTERN
3816 ibool
3817 fseg_validate(
3818 /*==========*/
3819  fseg_header_t* header,
3820  mtr_t* mtr)
3821 {
3822  fseg_inode_t* inode;
3823  ibool ret;
3824  ulint space;
3825  ulint flags;
3826  ulint zip_size;
3827 
3828  space = page_get_space_id(page_align(header));
3829 
3830  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3831  zip_size = dict_table_flags_to_zip_size(flags);
3832 
3833  inode = fseg_inode_get(header, space, zip_size, mtr);
3834 
3835  ret = fseg_validate_low(inode, mtr);
3836 
3837  return(ret);
3838 }
3839 #endif /* UNIV_DEBUG */
3840 
3841 /*******************************************************************/
3843 static
3844 void
3845 fseg_print_low(
3846 /*===========*/
3847  fseg_inode_t* inode,
3848  mtr_t* mtr)
3849 {
3850  ulint space;
3851  ulint n_used;
3852  ulint n_frag;
3853  ulint n_free;
3854  ulint n_not_full;
3855  ulint n_full;
3856  ulint reserved;
3857  ulint used;
3858  ulint page_no;
3859  ib_id_t seg_id;
3860 
3861  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3862  space = page_get_space_id(page_align(inode));
3863  page_no = page_get_page_no(page_align(inode));
3864 
3865  reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3866 
3867  seg_id = mach_read_from_8(inode + FSEG_ID);
3868 
3869  n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3870  MLOG_4BYTES, mtr);
3871  n_frag = fseg_get_n_frag_pages(inode, mtr);
3872  n_free = flst_get_len(inode + FSEG_FREE, mtr);
3873  n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3874  n_full = flst_get_len(inode + FSEG_FULL, mtr);
3875 
3876  fprintf(stderr,
3877  "SEGMENT id %llu space %lu; page %lu;"
3878  " res %lu used %lu; full ext %lu\n"
3879  "fragm pages %lu; free extents %lu;"
3880  " not full extents %lu: pages %lu\n",
3881  (ullint) seg_id,
3882  (ulong) space, (ulong) page_no,
3883  (ulong) reserved, (ulong) used, (ulong) n_full,
3884  (ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3885  (ulong) n_used);
3886  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3887 }
3888 
3889 #ifdef UNIV_BTR_PRINT
3890 /*******************************************************************/
3892 UNIV_INTERN
3893 void
3894 fseg_print(
3895 /*=======*/
3896  fseg_header_t* header,
3897  mtr_t* mtr)
3898 {
3899  fseg_inode_t* inode;
3900  ulint space;
3901  ulint flags;
3902  ulint zip_size;
3903 
3904  space = page_get_space_id(page_align(header));
3905 
3906  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3907  zip_size = dict_table_flags_to_zip_size(flags);
3908 
3909  inode = fseg_inode_get(header, space, zip_size, mtr);
3910 
3911  fseg_print_low(inode, mtr);
3912 }
3913 #endif /* UNIV_BTR_PRINT */
3914 
3915 /*******************************************************************/
3918 UNIV_INTERN
3919 ibool
3920 fsp_validate(
3921 /*=========*/
3922  ulint space)
3923 {
3924  fsp_header_t* header;
3925  fseg_inode_t* seg_inode;
3926  page_t* seg_inode_page;
3927  rw_lock_t* latch;
3928  ulint size;
3929  ulint flags;
3930  ulint zip_size;
3931  ulint free_limit;
3932  ulint frag_n_used;
3933  mtr_t mtr;
3934  mtr_t mtr2;
3935  xdes_t* descr;
3936  fil_addr_t node_addr;
3937  fil_addr_t next_node_addr;
3938  ulint descr_count = 0;
3939  ulint n_used = 0;
3940  ulint n_used2 = 0;
3941  ulint n_full_frag_pages;
3942  ulint n;
3943  ulint seg_inode_len_free;
3944  ulint seg_inode_len_full;
3945 
3946  latch = fil_space_get_latch(space, &flags);
3947  zip_size = dict_table_flags_to_zip_size(flags);
3948  ut_a(ut_is_2pow(zip_size));
3949  ut_a(zip_size <= UNIV_PAGE_SIZE);
3950  ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
3951 
3952  /* Start first a mini-transaction mtr2 to lock out all other threads
3953  from the fsp system */
3954  mtr_start(&mtr2);
3955  mtr_x_lock(latch, &mtr2);
3956 
3957  mtr_start(&mtr);
3958  mtr_x_lock(latch, &mtr);
3959 
3960  header = fsp_get_space_header(space, zip_size, &mtr);
3961 
3962  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3963  free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3964  MLOG_4BYTES, &mtr);
3965  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3966  MLOG_4BYTES, &mtr);
3967 
3968  n_full_frag_pages = FSP_EXTENT_SIZE
3969  * flst_get_len(header + FSP_FULL_FRAG, &mtr);
3970 
3971  if (UNIV_UNLIKELY(free_limit > size)) {
3972 
3973  ut_a(space != 0);
3974  ut_a(size < FSP_EXTENT_SIZE);
3975  }
3976 
3977  flst_validate(header + FSP_FREE, &mtr);
3978  flst_validate(header + FSP_FREE_FRAG, &mtr);
3979  flst_validate(header + FSP_FULL_FRAG, &mtr);
3980 
3981  mtr_commit(&mtr);
3982 
3983  /* Validate FSP_FREE list */
3984  mtr_start(&mtr);
3985  mtr_x_lock(latch, &mtr);
3986 
3987  header = fsp_get_space_header(space, zip_size, &mtr);
3988  node_addr = flst_get_first(header + FSP_FREE, &mtr);
3989 
3990  mtr_commit(&mtr);
3991 
3992  while (!fil_addr_is_null(node_addr)) {
3993  mtr_start(&mtr);
3994  mtr_x_lock(latch, &mtr);
3995 
3996  descr_count++;
3997  descr = xdes_lst_get_descriptor(space, zip_size,
3998  node_addr, &mtr);
3999 
4000  ut_a(xdes_get_n_used(descr, &mtr) == 0);
4001  ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
4002 
4003  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4004  mtr_commit(&mtr);
4005  }
4006 
4007  /* Validate FSP_FREE_FRAG list */
4008  mtr_start(&mtr);
4009  mtr_x_lock(latch, &mtr);
4010 
4011  header = fsp_get_space_header(space, zip_size, &mtr);
4012  node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
4013 
4014  mtr_commit(&mtr);
4015 
4016  while (!fil_addr_is_null(node_addr)) {
4017  mtr_start(&mtr);
4018  mtr_x_lock(latch, &mtr);
4019 
4020  descr_count++;
4021  descr = xdes_lst_get_descriptor(space, zip_size,
4022  node_addr, &mtr);
4023 
4024  ut_a(xdes_get_n_used(descr, &mtr) > 0);
4025  ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
4026  ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
4027 
4028  n_used += xdes_get_n_used(descr, &mtr);
4029  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4030 
4031  mtr_commit(&mtr);
4032  }
4033 
4034  /* Validate FSP_FULL_FRAG list */
4035  mtr_start(&mtr);
4036  mtr_x_lock(latch, &mtr);
4037 
4038  header = fsp_get_space_header(space, zip_size, &mtr);
4039  node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
4040 
4041  mtr_commit(&mtr);
4042 
4043  while (!fil_addr_is_null(node_addr)) {
4044  mtr_start(&mtr);
4045  mtr_x_lock(latch, &mtr);
4046 
4047  descr_count++;
4048  descr = xdes_lst_get_descriptor(space, zip_size,
4049  node_addr, &mtr);
4050 
4051  ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
4052  ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
4053 
4054  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4055  mtr_commit(&mtr);
4056  }
4057 
4058  /* Validate segments */
4059  mtr_start(&mtr);
4060  mtr_x_lock(latch, &mtr);
4061 
4062  header = fsp_get_space_header(space, zip_size, &mtr);
4063 
4064  node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4065 
4066  seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
4067 
4068  mtr_commit(&mtr);
4069 
4070  while (!fil_addr_is_null(node_addr)) {
4071 
4072  n = 0;
4073  do {
4074  mtr_start(&mtr);
4075  mtr_x_lock(latch, &mtr);
4076 
4077  seg_inode_page = fut_get_ptr(
4078  space, zip_size, node_addr, RW_X_LATCH, &mtr)
4079  - FSEG_INODE_PAGE_NODE;
4080 
4081  seg_inode = fsp_seg_inode_page_get_nth_inode(
4082  seg_inode_page, n, zip_size, &mtr);
4083  ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4084  fseg_validate_low(seg_inode, &mtr);
4085 
4086  descr_count += flst_get_len(seg_inode + FSEG_FREE,
4087  &mtr);
4088  descr_count += flst_get_len(seg_inode + FSEG_FULL,
4089  &mtr);
4090  descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
4091  &mtr);
4092 
4093  n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
4094 
4095  next_node_addr = flst_get_next_addr(
4096  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4097  mtr_commit(&mtr);
4098  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4099 
4100  node_addr = next_node_addr;
4101  }
4102 
4103  mtr_start(&mtr);
4104  mtr_x_lock(latch, &mtr);
4105 
4106  header = fsp_get_space_header(space, zip_size, &mtr);
4107 
4108  node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4109 
4110  seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
4111 
4112  mtr_commit(&mtr);
4113 
4114  while (!fil_addr_is_null(node_addr)) {
4115 
4116  n = 0;
4117 
4118  do {
4119  mtr_start(&mtr);
4120  mtr_x_lock(latch, &mtr);
4121 
4122  seg_inode_page = fut_get_ptr(
4123  space, zip_size, node_addr, RW_X_LATCH, &mtr)
4124  - FSEG_INODE_PAGE_NODE;
4125 
4126  seg_inode = fsp_seg_inode_page_get_nth_inode(
4127  seg_inode_page, n, zip_size, &mtr);
4128  if (mach_read_from_8(seg_inode + FSEG_ID)) {
4129  fseg_validate_low(seg_inode, &mtr);
4130 
4131  descr_count += flst_get_len(
4132  seg_inode + FSEG_FREE, &mtr);
4133  descr_count += flst_get_len(
4134  seg_inode + FSEG_FULL, &mtr);
4135  descr_count += flst_get_len(
4136  seg_inode + FSEG_NOT_FULL, &mtr);
4137  n_used2 += fseg_get_n_frag_pages(
4138  seg_inode, &mtr);
4139  }
4140 
4141  next_node_addr = flst_get_next_addr(
4142  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4143  mtr_commit(&mtr);
4144  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4145 
4146  node_addr = next_node_addr;
4147  }
4148 
4149  ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
4150  if (!zip_size) {
4151  ut_a(n_used + n_full_frag_pages
4152  == n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
4153  / UNIV_PAGE_SIZE)
4154  + seg_inode_len_full + seg_inode_len_free);
4155  } else {
4156  ut_a(n_used + n_full_frag_pages
4157  == n_used2 + 2 * ((free_limit + (zip_size - 1))
4158  / zip_size)
4159  + seg_inode_len_full + seg_inode_len_free);
4160  }
4161  ut_a(frag_n_used == n_used);
4162 
4163  mtr_commit(&mtr2);
4164 
4165  return(TRUE);
4166 }
4167 
4168 /*******************************************************************/
4170 UNIV_INTERN
4171 void
4172 fsp_print(
4173 /*======*/
4174  ulint space)
4175 {
4176  fsp_header_t* header;
4177  fseg_inode_t* seg_inode;
4178  page_t* seg_inode_page;
4179  rw_lock_t* latch;
4180  ulint flags;
4181  ulint zip_size;
4182  ulint size;
4183  ulint free_limit;
4184  ulint frag_n_used;
4185  fil_addr_t node_addr;
4186  fil_addr_t next_node_addr;
4187  ulint n_free;
4188  ulint n_free_frag;
4189  ulint n_full_frag;
4190  ib_id_t seg_id;
4191  ulint n;
4192  ulint n_segs = 0;
4193  mtr_t mtr;
4194  mtr_t mtr2;
4195 
4196  latch = fil_space_get_latch(space, &flags);
4197  zip_size = dict_table_flags_to_zip_size(flags);
4198 
4199  /* Start first a mini-transaction mtr2 to lock out all other threads
4200  from the fsp system */
4201 
4202  mtr_start(&mtr2);
4203 
4204  mtr_x_lock(latch, &mtr2);
4205 
4206  mtr_start(&mtr);
4207 
4208  mtr_x_lock(latch, &mtr);
4209 
4210  header = fsp_get_space_header(space, zip_size, &mtr);
4211 
4212  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4213 
4214  free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4215  &mtr);
4216  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4217  &mtr);
4218  n_free = flst_get_len(header + FSP_FREE, &mtr);
4219  n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4220  n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4221 
4222  seg_id = mach_read_from_8(header + FSP_SEG_ID);
4223 
4224  fprintf(stderr,
4225  "FILE SPACE INFO: id %lu\n"
4226  "size %lu, free limit %lu, free extents %lu\n"
4227  "not full frag extents %lu: used pages %lu,"
4228  " full frag extents %lu\n"
4229  "first seg id not used %llu\n",
4230  (ulong) space,
4231  (ulong) size, (ulong) free_limit, (ulong) n_free,
4232  (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4233  (ullint) seg_id);
4234 
4235  mtr_commit(&mtr);
4236 
4237  /* Print segments */
4238 
4239  mtr_start(&mtr);
4240  mtr_x_lock(latch, &mtr);
4241 
4242  header = fsp_get_space_header(space, zip_size, &mtr);
4243 
4244  node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4245 
4246  mtr_commit(&mtr);
4247 
4248  while (!fil_addr_is_null(node_addr)) {
4249 
4250  n = 0;
4251 
4252  do {
4253 
4254  mtr_start(&mtr);
4255  mtr_x_lock(latch, &mtr);
4256 
4257  seg_inode_page = fut_get_ptr(
4258  space, zip_size, node_addr, RW_X_LATCH, &mtr)
4259  - FSEG_INODE_PAGE_NODE;
4260 
4261  seg_inode = fsp_seg_inode_page_get_nth_inode(
4262  seg_inode_page, n, zip_size, &mtr);
4263  ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4264  fseg_print_low(seg_inode, &mtr);
4265 
4266  n_segs++;
4267 
4268  next_node_addr = flst_get_next_addr(
4269  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4270  mtr_commit(&mtr);
4271  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4272 
4273  node_addr = next_node_addr;
4274  }
4275 
4276  mtr_start(&mtr);
4277  mtr_x_lock(latch, &mtr);
4278 
4279  header = fsp_get_space_header(space, zip_size, &mtr);
4280 
4281  node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4282 
4283  mtr_commit(&mtr);
4284 
4285  while (!fil_addr_is_null(node_addr)) {
4286 
4287  n = 0;
4288 
4289  do {
4290 
4291  mtr_start(&mtr);
4292  mtr_x_lock(latch, &mtr);
4293 
4294  seg_inode_page = fut_get_ptr(
4295  space, zip_size, node_addr, RW_X_LATCH, &mtr)
4296  - FSEG_INODE_PAGE_NODE;
4297 
4298  seg_inode = fsp_seg_inode_page_get_nth_inode(
4299  seg_inode_page, n, zip_size, &mtr);
4300  if (mach_read_from_8(seg_inode + FSEG_ID)) {
4301 
4302  fseg_print_low(seg_inode, &mtr);
4303  n_segs++;
4304  }
4305 
4306  next_node_addr = flst_get_next_addr(
4307  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4308  mtr_commit(&mtr);
4309  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4310 
4311  node_addr = next_node_addr;
4312  }
4313 
4314  mtr_commit(&mtr2);
4315 
4316  fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
4317 }
4318 #endif /* !UNIV_HOTBACKUP */