MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
fsp0fsp.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1995, 2013, Oracle and/or its affiliates. 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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 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 #include "srv0start.h"
52 
53 
54 #ifndef UNIV_HOTBACKUP
55 
56 static ibool fsp_tbs_full_error_printed = FALSE;
57 
58 /**********************************************************************/
60 static
61 void
62 fsp_free_extent(
63 /*============*/
64  ulint space,
65  ulint zip_size,
67  ulint page,
68  mtr_t* mtr);
69 /**********************************************************************/
71 static
72 void
73 fseg_free_extent(
74 /*=============*/
75  fseg_inode_t* seg_inode,
76  ulint space,
77  ulint zip_size,
79  ulint page,
80  mtr_t* mtr);
81 /**********************************************************************/
85 static
86 ulint
87 fseg_n_reserved_pages_low(
88 /*======================*/
89  fseg_inode_t* header,
90  ulint* used,
92  mtr_t* mtr);
93 /********************************************************************/
96 static __attribute__((nonnull))
97 void
98 fseg_mark_page_used(
99 /*================*/
100  fseg_inode_t* seg_inode,
101  ulint page,
102  xdes_t* descr,
103  mtr_t* mtr);
104 /**********************************************************************/
109 static
110 xdes_t*
111 fseg_get_first_extent(
112 /*==================*/
113  fseg_inode_t* inode,
114  ulint space,
115  ulint zip_size,
117  mtr_t* mtr);
118 /**********************************************************************/
123 static
124 void
125 fsp_fill_free_list(
126 /*===============*/
127  ibool init_space,
132  ulint space,
133  fsp_header_t* header,
134  mtr_t* mtr)
135  UNIV_COLD __attribute__((nonnull));
136 /**********************************************************************/
144 static
146 fseg_alloc_free_page_low(
147 /*=====================*/
148  ulint space,
149  ulint zip_size,
151  fseg_inode_t* seg_inode,
152  ulint hint,
154  byte direction,
159  mtr_t* mtr,
160  mtr_t* init_mtr)
164  __attribute__((warn_unused_result, nonnull));
165 #endif /* !UNIV_HOTBACKUP */
166 
167 /**********************************************************************/
170 UNIV_INTERN
171 ulint
173 /*=============*/
174  page_t* page)
175 {
176  return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
177 }
178 
179 #ifndef UNIV_HOTBACKUP
180 /**********************************************************************/
183 UNIV_INLINE
184 fsp_header_t*
186 /*=================*/
187  ulint id,
188  ulint zip_size,
190  mtr_t* mtr)
191 {
193  fsp_header_t* header;
194 
195  ut_ad(ut_is_2pow(zip_size));
196  ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
197  ut_ad(!zip_size || zip_size >= UNIV_ZIP_SIZE_MIN);
198  ut_ad(id || !zip_size);
199 
200  block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
201  header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
202  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
203 
204  ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
205  ut_ad(zip_size == fsp_flags_get_zip_size(
206  mach_read_from_4(FSP_SPACE_FLAGS + header)));
207  return(header);
208 }
209 
210 /**********************************************************************/
213 UNIV_INLINE
214 ibool
216 /*=============*/
217  const xdes_t* descr,
218  ulint bit,
219  ulint offset,
221  mtr_t* mtr)
222 {
223  ut_ad(mtr->state == MTR_ACTIVE);
224  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
225 
226  return(xdes_get_bit(descr, bit, offset));
227 }
228 
229 /**********************************************************************/
231 UNIV_INLINE
232 void
234 /*=========*/
235  xdes_t* descr,
236  ulint bit,
237  ulint offset,
239  ibool val,
240  mtr_t* mtr)
241 {
242  ulint index;
243  ulint byte_index;
244  ulint bit_index;
245  ulint descr_byte;
246 
247  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
248  ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
249  ut_ad(offset < FSP_EXTENT_SIZE);
250 
251  index = bit + XDES_BITS_PER_PAGE * offset;
252 
253  byte_index = index / 8;
254  bit_index = index % 8;
255 
256  descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
257  MLOG_1BYTE, mtr);
258  descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
259 
260  mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
261  MLOG_1BYTE, mtr);
262 }
263 
264 /**********************************************************************/
269 UNIV_INLINE
270 ulint
272 /*==========*/
273  xdes_t* descr,
274  ulint bit,
275  ibool val,
276  ulint hint,
278  mtr_t* mtr)
279 {
280  ulint i;
281 
282  ut_ad(descr && mtr);
283  ut_ad(val <= TRUE);
284  ut_ad(hint < FSP_EXTENT_SIZE);
285  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
286  for (i = hint; i < FSP_EXTENT_SIZE; i++) {
287  if (val == xdes_mtr_get_bit(descr, bit, i, mtr)) {
288 
289  return(i);
290  }
291  }
292 
293  for (i = 0; i < hint; i++) {
294  if (val == xdes_mtr_get_bit(descr, bit, i, mtr)) {
295 
296  return(i);
297  }
298  }
299 
300  return(ULINT_UNDEFINED);
301 }
302 
303 /**********************************************************************/
307 UNIV_INLINE
308 ulint
310 /*===================*/
311  xdes_t* descr,
312  ulint bit,
313  ibool val,
314  ulint hint,
316  mtr_t* mtr)
317 {
318  ulint i;
319 
320  ut_ad(descr && mtr);
321  ut_ad(val <= TRUE);
322  ut_ad(hint < FSP_EXTENT_SIZE);
323  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
324  for (i = hint + 1; i > 0; i--) {
325  if (val == xdes_mtr_get_bit(descr, bit, i - 1, mtr)) {
326 
327  return(i - 1);
328  }
329  }
330 
331  for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
332  if (val == xdes_mtr_get_bit(descr, bit, i, mtr)) {
333 
334  return(i);
335  }
336  }
337 
338  return(ULINT_UNDEFINED);
339 }
340 
341 /**********************************************************************/
344 UNIV_INLINE
345 ulint
347 /*============*/
348  const xdes_t* descr,
349  mtr_t* mtr)
350 {
351  ulint count = 0;
352 
353  ut_ad(descr && mtr);
354  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
355  for (ulint i = 0; i < FSP_EXTENT_SIZE; ++i) {
356  if (FALSE == xdes_mtr_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
357  count++;
358  }
359  }
360 
361  return(count);
362 }
363 
364 /**********************************************************************/
367 UNIV_INLINE
368 ibool
370 /*=========*/
371  const xdes_t* descr,
372  mtr_t* mtr)
373 {
374  if (0 == xdes_get_n_used(descr, mtr)) {
375 
376  return(TRUE);
377  }
378 
379  return(FALSE);
380 }
381 
382 /**********************************************************************/
385 UNIV_INLINE
386 ibool
388 /*=========*/
389  const xdes_t* descr,
390  mtr_t* mtr)
391 {
392  if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
393 
394  return(TRUE);
395  }
396 
397  return(FALSE);
398 }
399 
400 /**********************************************************************/
402 UNIV_INLINE
403 void
405 /*===========*/
406  xdes_t* descr,
407  ulint state,
408  mtr_t* mtr)
409 {
410  ut_ad(descr && mtr);
411  ut_ad(state >= XDES_FREE);
412  ut_ad(state <= XDES_FSEG);
413  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
414 
415  mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
416 }
417 
418 /**********************************************************************/
421 UNIV_INLINE
422 ulint
424 /*===========*/
425  const xdes_t* descr,
426  mtr_t* mtr)
427 {
428  ulint state;
429 
430  ut_ad(descr && mtr);
431  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
432 
433  state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
434  ut_ad(state - 1 < XDES_FSEG);
435  return(state);
436 }
437 
438 /**********************************************************************/
440 UNIV_INLINE
441 void
443 /*======*/
444  xdes_t* descr,
445  mtr_t* mtr)
446 {
447  ulint i;
448 
449  ut_ad(descr && mtr);
450  ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
451  ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
452 
453  for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
454  mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
455  }
456 
457  xdes_set_state(descr, XDES_FREE, mtr);
458 }
459 
460 /********************************************************************/
466 UNIV_INLINE __attribute__((nonnull, warn_unused_result))
467 xdes_t*
468 xdes_get_descriptor_with_space_hdr(
469 /*===============================*/
470  fsp_header_t* sp_header,
472  ulint space,
473  ulint offset,
477  mtr_t* mtr)
478 {
479  ulint limit;
480  ulint size;
481  ulint zip_size;
482  ulint descr_page_no;
483  page_t* descr_page;
484 
485  ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
486  MTR_MEMO_X_LOCK));
487  ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
488  ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
489  /* Read free limit and space size */
490  limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
491  size = mach_read_from_4(sp_header + FSP_SIZE);
492  zip_size = fsp_flags_get_zip_size(
493  mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
494 
495  if ((offset >= size) || (offset >= limit)) {
496  return(NULL);
497  }
498 
499  descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
500 
501  if (descr_page_no == 0) {
502  /* It is on the space header page */
503 
504  descr_page = page_align(sp_header);
505  } else {
507 
508  block = buf_page_get(space, zip_size, descr_page_no,
509  RW_X_LATCH, mtr);
510  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
511 
512  descr_page = buf_block_get_frame(block);
513  }
514 
515  return(descr_page + XDES_ARR_OFFSET
516  + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
517 }
518 
519 /********************************************************************/
528 static __attribute__((nonnull, warn_unused_result))
529 xdes_t*
530 xdes_get_descriptor(
531 /*================*/
532  ulint space,
533  ulint zip_size,
535  ulint offset,
537  mtr_t* mtr)
538 {
540  fsp_header_t* sp_header;
541 
542  block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
543  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
544 
545  sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
546  return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
547  mtr));
548 }
549 
550 /********************************************************************/
555 UNIV_INLINE
556 xdes_t*
557 xdes_lst_get_descriptor(
558 /*====================*/
559  ulint space,
560  ulint zip_size,
562  fil_addr_t lst_node,
564  mtr_t* mtr)
565 {
566  xdes_t* descr;
567 
568  ut_ad(mtr);
569  ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
570  MTR_MEMO_X_LOCK));
571  descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
572  - XDES_FLST_NODE;
573 
574  return(descr);
575 }
576 
577 /********************************************************************/
580 UNIV_INLINE
581 ulint
582 xdes_get_offset(
583 /*============*/
584  const xdes_t* descr)
585 {
586  ut_ad(descr);
587 
588  return(page_get_page_no(page_align(descr))
589  + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
590  * FSP_EXTENT_SIZE);
591 }
592 #endif /* !UNIV_HOTBACKUP */
593 
594 /***********************************************************/
596 static
597 void
598 fsp_init_file_page_low(
599 /*===================*/
600  buf_block_t* block)
601 {
602  page_t* page = buf_block_get_frame(block);
603  page_zip_des_t* page_zip= buf_block_get_page_zip(block);
604 
605 #ifndef UNIV_HOTBACKUP
606  block->check_index_page_at_flush = FALSE;
607 #endif /* !UNIV_HOTBACKUP */
608 
609  if (page_zip) {
610  memset(page, 0, UNIV_PAGE_SIZE);
611  memset(page_zip->data, 0, page_zip_get_size(page_zip));
613  buf_block_get_page_no(block));
614  mach_write_to_4(page
616  buf_block_get_space(block));
617  memcpy(page_zip->data + FIL_PAGE_OFFSET,
618  page + FIL_PAGE_OFFSET, 4);
619  memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
621  return;
622  }
623 
624  memset(page, 0, UNIV_PAGE_SIZE);
627  buf_block_get_space(block));
628 }
629 
630 #ifndef UNIV_HOTBACKUP
631 /***********************************************************/
633 static
634 void
635 fsp_init_file_page(
636 /*===============*/
637  buf_block_t* block,
638  mtr_t* mtr)
639 {
640  fsp_init_file_page_low(block);
641 
642  mlog_write_initial_log_record(buf_block_get_frame(block),
643  MLOG_INIT_FILE_PAGE, mtr);
644 }
645 #endif /* !UNIV_HOTBACKUP */
646 
647 /***********************************************************/
650 UNIV_INTERN
651 byte*
653 /*=====================*/
654  byte* ptr,
655  byte* end_ptr __attribute__((unused)),
656  buf_block_t* block)
657 {
658  ut_ad(ptr && end_ptr);
659 
660  if (block) {
661  fsp_init_file_page_low(block);
662  }
663 
664  return(ptr);
665 }
666 
667 /**********************************************************************/
669 UNIV_INTERN
670 void
671 fsp_init(void)
672 /*==========*/
673 {
674  /* FSP_EXTENT_SIZE must be a multiple of page & zip size */
675  ut_a(0 == (UNIV_PAGE_SIZE % FSP_EXTENT_SIZE));
676  ut_a(UNIV_PAGE_SIZE);
677 
678 #if UNIV_PAGE_SIZE_MAX % FSP_EXTENT_SIZE_MAX
679 # error "UNIV_PAGE_SIZE_MAX % FSP_EXTENT_SIZE_MAX != 0"
680 #endif
681 #if UNIV_ZIP_SIZE_MIN % FSP_EXTENT_SIZE_MIN
682 # error "UNIV_ZIP_SIZE_MIN % FSP_EXTENT_SIZE_MIN != 0"
683 #endif
684 
685  /* Does nothing at the moment */
686 }
687 
688 /**********************************************************************/
692 UNIV_INTERN
693 void
695 /*===================*/
696  page_t* page,
697  ulint space_id,
698  ulint flags)
699 {
700  ut_a(fsp_flags_is_valid(flags));
701 
702  mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
703  space_id);
704  mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
705  flags);
706 }
707 
708 #ifndef UNIV_HOTBACKUP
709 /**********************************************************************/
712 UNIV_INTERN
713 void
715 /*============*/
716  ulint space,
717  ulint size,
718  mtr_t* mtr)
719 {
720  fsp_header_t* header;
722  page_t* page;
723  ulint flags;
724  ulint zip_size;
725 
726  ut_ad(mtr);
727 
728  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
729 
730  zip_size = fsp_flags_get_zip_size(flags);
731  block = buf_page_create(space, 0, zip_size, mtr);
732  buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
733  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
734 
735  /* The prior contents of the file page should be ignored */
736 
737  fsp_init_file_page(block, mtr);
738  page = buf_block_get_frame(block);
739 
741  MLOG_2BYTES, mtr);
742 
743  header = FSP_HEADER_OFFSET + page;
744 
745  mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
746  mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
747 
748  mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
749  mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
750  mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
751  MLOG_4BYTES, mtr);
752  mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
753 
754  flst_init(header + FSP_FREE, mtr);
755  flst_init(header + FSP_FREE_FRAG, mtr);
756  flst_init(header + FSP_FULL_FRAG, mtr);
757  flst_init(header + FSP_SEG_INODES_FULL, mtr);
758  flst_init(header + FSP_SEG_INODES_FREE, mtr);
759 
760  mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
761  if (space == 0) {
762  fsp_fill_free_list(FALSE, space, header, mtr);
764  0, 0, DICT_IBUF_ID_MIN + space,
765  dict_ind_redundant, mtr);
766  } else {
767  fsp_fill_free_list(TRUE, space, header, mtr);
768  }
769 }
770 #endif /* !UNIV_HOTBACKUP */
771 
772 /**********************************************************************/
775 UNIV_INTERN
776 ulint
778 /*====================*/
779  const page_t* page)
780 {
781  ulint fsp_id;
782  ulint id;
783 
784  fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
785 
787 
788  DBUG_EXECUTE_IF("fsp_header_get_space_id_failure",
789  id = ULINT_UNDEFINED;);
790 
791  if (id != fsp_id) {
792  ib_logf(IB_LOG_LEVEL_ERROR,
793  "Space id in fsp header %lu,but in the page header "
794  "%lu", fsp_id, id);
795 
796  return(ULINT_UNDEFINED);
797  }
798 
799  return(id);
800 }
801 
802 /**********************************************************************/
805 UNIV_INTERN
806 ulint
808 /*=================*/
809  const page_t* page)
810 {
811  ut_ad(!page_offset(page));
812 
813  return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
814 }
815 
816 /**********************************************************************/
819 UNIV_INTERN
820 ulint
822 /*====================*/
823  const page_t* page)
824 {
825  ulint flags = fsp_header_get_flags(page);
826 
827  return(fsp_flags_get_zip_size(flags));
828 }
829 
830 #ifndef UNIV_HOTBACKUP
831 /**********************************************************************/
833 UNIV_INTERN
834 void
836 /*================*/
837  ulint space,
838  ulint size_inc,
839  mtr_t* mtr)
840 {
841  fsp_header_t* header;
842  ulint size;
843  ulint flags;
844 
845  ut_ad(mtr);
846 
847  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
848 
849  header = fsp_get_space_header(space,
850  fsp_flags_get_zip_size(flags),
851  mtr);
852 
853  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
854 
855  mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
856  mtr);
857 }
858 
859 /**********************************************************************/
865 UNIV_INTERN
866 ulint
868 /*================================*/
869 {
870  fsp_header_t* header;
871  ulint size;
872  mtr_t mtr;
873 
874  mtr_start(&mtr);
875 
876  mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
877 
878  header = fsp_get_space_header(0, 0, &mtr);
879 
880  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
881 
882  mtr_commit(&mtr);
883 
884  return(size);
885 }
886 
887 /***********************************************************************/
891 static UNIV_COLD __attribute__((nonnull, warn_unused_result))
892 ibool
893 fsp_try_extend_data_file_with_pages(
894 /*================================*/
895  ulint space,
896  ulint page_no,
897  fsp_header_t* header,
898  mtr_t* mtr)
899 {
900  ibool success;
901  ulint actual_size;
902  ulint size;
903 
904  ut_a(space != 0);
905 
906  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
907 
908  ut_a(page_no >= size);
909 
910  success = fil_extend_space_to_desired_size(&actual_size, space,
911  page_no + 1);
912  /* actual_size now has the space size in pages; it may be less than
913  we wanted if we ran out of disk space */
914 
915  mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
916 
917  return(success);
918 }
919 
920 /***********************************************************************/
923 static UNIV_COLD __attribute__((nonnull))
924 ibool
925 fsp_try_extend_data_file(
926 /*=====================*/
927  ulint* actual_increase,
932  ulint space,
933  fsp_header_t* header,
934  mtr_t* mtr)
935 {
936  ulint size;
937  ulint zip_size;
938  ulint new_size;
939  ulint old_size;
940  ulint size_increase;
941  ulint actual_size;
942  ibool success;
943 
944  *actual_increase = 0;
945 
946  if (space == 0 && !srv_auto_extend_last_data_file) {
947 
948  /* We print the error message only once to avoid
949  spamming the error log. Note that we don't need
950  to reset the flag to FALSE as dealing with this
951  error requires server restart. */
952  if (fsp_tbs_full_error_printed == FALSE) {
953  fprintf(stderr,
954  "InnoDB: Error: Data file(s) ran"
955  " out of space.\n"
956  "Please add another data file or"
957  " use \'autoextend\' for the last"
958  " data file.\n");
959  fsp_tbs_full_error_printed = TRUE;
960  }
961  return(FALSE);
962  }
963 
964  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
965  zip_size = fsp_flags_get_zip_size(
966  mach_read_from_4(header + FSP_SPACE_FLAGS));
967 
968  old_size = size;
969 
970  if (space == 0) {
971  if (!srv_last_file_size_max) {
972  size_increase = SRV_AUTO_EXTEND_INCREMENT;
973  } else {
974  if (srv_last_file_size_max
975  < srv_data_file_sizes[srv_n_data_files - 1]) {
976 
977  fprintf(stderr,
978  "InnoDB: Error: Last data file size"
979  " is %lu, max size allowed %lu\n",
980  (ulong) srv_data_file_sizes[
981  srv_n_data_files - 1],
982  (ulong) srv_last_file_size_max);
983  }
984 
985  size_increase = srv_last_file_size_max
986  - srv_data_file_sizes[srv_n_data_files - 1];
987  if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
988  size_increase = SRV_AUTO_EXTEND_INCREMENT;
989  }
990  }
991  } else {
992  /* We extend single-table tablespaces first one extent
993  at a time, but for bigger tablespaces more. It is not
994  enough to extend always by one extent, because some
995  extents are frag page extents. */
996  ulint extent_size;
998  if (!zip_size) {
999  extent_size = FSP_EXTENT_SIZE;
1000  } else {
1001  extent_size = FSP_EXTENT_SIZE
1002  * UNIV_PAGE_SIZE / zip_size;
1003  }
1004 
1005  if (size < extent_size) {
1006  /* Let us first extend the file to extent_size */
1007  success = fsp_try_extend_data_file_with_pages(
1008  space, extent_size - 1, header, mtr);
1009  if (!success) {
1010  new_size = mtr_read_ulint(header + FSP_SIZE,
1011  MLOG_4BYTES, mtr);
1012 
1013  *actual_increase = new_size - old_size;
1014 
1015  return(FALSE);
1016  }
1017 
1018  size = extent_size;
1019  }
1020 
1021  if (size < 32 * extent_size) {
1022  size_increase = extent_size;
1023  } else {
1024  /* Below in fsp_fill_free_list() we assume
1025  that we add at most FSP_FREE_ADD extents at
1026  a time */
1027  size_increase = FSP_FREE_ADD * extent_size;
1028  }
1029  }
1030 
1031  if (size_increase == 0) {
1032 
1033  return(TRUE);
1034  }
1035 
1036  success = fil_extend_space_to_desired_size(&actual_size, space,
1037  size + size_increase);
1038  if (!success) {
1039 
1040  return(false);
1041  }
1042 
1043  /* We ignore any fragments of a full megabyte when storing the size
1044  to the space header */
1045 
1046  if (!zip_size) {
1047  new_size = ut_calc_align_down(actual_size,
1048  (1024 * 1024) / UNIV_PAGE_SIZE);
1049  } else {
1050  new_size = ut_calc_align_down(actual_size,
1051  (1024 * 1024) / zip_size);
1052  }
1053  mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1054 
1055  *actual_increase = new_size - old_size;
1056 
1057  return(TRUE);
1058 }
1059 
1060 /**********************************************************************/
1064 static
1065 void
1066 fsp_fill_free_list(
1067 /*===============*/
1068  ibool init_space,
1073  ulint space,
1074  fsp_header_t* header,
1075  mtr_t* mtr)
1076 {
1077  ulint limit;
1078  ulint size;
1079  ulint zip_size;
1080  xdes_t* descr;
1081  ulint count = 0;
1082  ulint frag_n_used;
1083  ulint actual_increase;
1084  ulint i;
1085  mtr_t ibuf_mtr;
1086 
1087  ut_ad(header && mtr);
1088  ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
1089 
1090  /* Check if we can fill free list from above the free list limit */
1091  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1092  limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1093 
1094  zip_size = fsp_flags_get_zip_size(
1095  mach_read_from_4(FSP_SPACE_FLAGS + header));
1096  ut_a(ut_is_2pow(zip_size));
1097  ut_a(zip_size <= UNIV_ZIP_SIZE_MAX);
1098  ut_a(!zip_size || zip_size >= UNIV_ZIP_SIZE_MIN);
1099 
1100  if (space == 0 && srv_auto_extend_last_data_file
1101  && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1102 
1103  /* Try to increase the last data file size */
1104  fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1105  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1106  }
1107 
1108  if (space != 0 && !init_space
1109  && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1110 
1111  /* Try to increase the .ibd file size */
1112  fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1113  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1114  }
1115 
1116  i = limit;
1117 
1118  while ((init_space && i < 1)
1119  || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1120 
1121  ibool init_xdes;
1122  if (zip_size) {
1123  init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1124  } else {
1125  init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1126  }
1127 
1128  mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1129  MLOG_4BYTES, mtr);
1130 
1131  if (UNIV_UNLIKELY(init_xdes)) {
1132 
1133  buf_block_t* block;
1134 
1135  /* We are going to initialize a new descriptor page
1136  and a new ibuf bitmap page: the prior contents of the
1137  pages should be ignored. */
1138 
1139  if (i > 0) {
1140  block = buf_page_create(
1141  space, i, zip_size, mtr);
1142  buf_page_get(space, zip_size, i,
1143  RW_X_LATCH, mtr);
1144  buf_block_dbg_add_level(block,
1145  SYNC_FSP_PAGE);
1146 
1147  fsp_init_file_page(block, mtr);
1148  mlog_write_ulint(buf_block_get_frame(block)
1149  + FIL_PAGE_TYPE,
1151  MLOG_2BYTES, mtr);
1152  }
1153 
1154  /* Initialize the ibuf bitmap page in a separate
1155  mini-transaction because it is low in the latching
1156  order, and we must be able to release its latch
1157  before returning from the fsp routine */
1158 
1159  mtr_start(&ibuf_mtr);
1160 
1161  block = buf_page_create(space,
1162  i + FSP_IBUF_BITMAP_OFFSET,
1163  zip_size, &ibuf_mtr);
1164  buf_page_get(space, zip_size,
1165  i + FSP_IBUF_BITMAP_OFFSET,
1166  RW_X_LATCH, &ibuf_mtr);
1167  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1168 
1169  fsp_init_file_page(block, &ibuf_mtr);
1170 
1171  ibuf_bitmap_page_init(block, &ibuf_mtr);
1172 
1173  mtr_commit(&ibuf_mtr);
1174  }
1175 
1176  descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1177  mtr);
1178  xdes_init(descr, mtr);
1179 
1180  if (UNIV_UNLIKELY(init_xdes)) {
1181 
1182  /* The first page in the extent is a descriptor page
1183  and the second is an ibuf bitmap page: mark them
1184  used */
1185 
1186  xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1187  xdes_set_bit(descr, XDES_FREE_BIT,
1188  FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1189  xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1190 
1191  flst_add_last(header + FSP_FREE_FRAG,
1192  descr + XDES_FLST_NODE, mtr);
1193  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1194  MLOG_4BYTES, mtr);
1195  mlog_write_ulint(header + FSP_FRAG_N_USED,
1196  frag_n_used + 2, MLOG_4BYTES, mtr);
1197  } else {
1198  flst_add_last(header + FSP_FREE,
1199  descr + XDES_FLST_NODE, mtr);
1200  count++;
1201  }
1202 
1203  i += FSP_EXTENT_SIZE;
1204  }
1205 }
1206 
1207 /**********************************************************************/
1210 static
1211 xdes_t*
1212 fsp_alloc_free_extent(
1213 /*==================*/
1214  ulint space,
1215  ulint zip_size,
1217  ulint hint,
1220  mtr_t* mtr)
1221 {
1222  fsp_header_t* header;
1223  fil_addr_t first;
1224  xdes_t* descr;
1225 
1226  ut_ad(mtr);
1227 
1228  header = fsp_get_space_header(space, zip_size, mtr);
1229 
1230  descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1231 
1232  if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1233  /* Ok, we can take this extent */
1234  } else {
1235  /* Take the first extent in the free list */
1236  first = flst_get_first(header + FSP_FREE, mtr);
1237 
1238  if (fil_addr_is_null(first)) {
1239  fsp_fill_free_list(FALSE, space, header, mtr);
1240 
1241  first = flst_get_first(header + FSP_FREE, mtr);
1242  }
1243 
1244  if (fil_addr_is_null(first)) {
1245 
1246  return(NULL); /* No free extents left */
1247  }
1248 
1249  descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1250  }
1251 
1252  flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1253 
1254  return(descr);
1255 }
1256 
1257 /**********************************************************************/
1259 static __attribute__((nonnull))
1260 void
1261 fsp_alloc_from_free_frag(
1262 /*=====================*/
1263  fsp_header_t* header,
1264  xdes_t* descr,
1265  ulint bit,
1266  mtr_t* mtr)
1267 {
1268  ulint frag_n_used;
1269 
1270  ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG);
1271  ut_a(xdes_mtr_get_bit(descr, XDES_FREE_BIT, bit, mtr));
1272  xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr);
1273 
1274  /* Update the FRAG_N_USED field */
1275  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1276  mtr);
1277  frag_n_used++;
1278  mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1279  mtr);
1280  if (xdes_is_full(descr, mtr)) {
1281  /* The fragment is full: move it to another list */
1282  flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1283  mtr);
1284  xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1285 
1286  flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1287  mtr);
1288  mlog_write_ulint(header + FSP_FRAG_N_USED,
1289  frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1290  mtr);
1291  }
1292 }
1293 
1294 /**********************************************************************/
1303 static
1304 buf_block_t*
1305 fsp_page_create(
1306 /*============*/
1307  ulint space,
1308  ulint zip_size,
1310  ulint page_no,
1311  mtr_t* mtr,
1312  mtr_t* init_mtr)
1314 {
1315  buf_block_t* block
1316  = buf_page_create(space, page_no, zip_size, init_mtr);
1317 #ifdef UNIV_SYNC_DEBUG
1318  ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)
1319  == rw_lock_own(&block->lock, RW_LOCK_EX));
1320 #endif /* UNIV_SYNC_DEBUG */
1321 
1322  /* Mimic buf_page_get(), but avoid the buf_pool->page_hash lookup. */
1323  rw_lock_x_lock(&block->lock);
1324  mutex_enter(&block->mutex);
1325  buf_block_buf_fix_inc(block, __FILE__, __LINE__);
1326  mutex_exit(&block->mutex);
1327  mtr_memo_push(init_mtr, block, MTR_MEMO_PAGE_X_FIX);
1328 
1329  if (init_mtr == mtr
1330  || rw_lock_get_x_lock_count(&block->lock) == 1) {
1331 
1332  /* Initialize the page, unless it was already
1333  X-latched in mtr. (In this case, we would want to
1334  allocate another page that has not been freed in mtr.) */
1335  ut_ad(init_mtr == mtr
1336  || !mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
1337 
1338  fsp_init_file_page(block, init_mtr);
1339  }
1340 
1341  return(block);
1342 }
1343 
1344 /**********************************************************************/
1350 static __attribute__((nonnull, warn_unused_result))
1351 buf_block_t*
1352 fsp_alloc_free_page(
1353 /*================*/
1354  ulint space,
1355  ulint zip_size,
1357  ulint hint,
1358  mtr_t* mtr,
1359  mtr_t* init_mtr)
1362 {
1363  fsp_header_t* header;
1364  fil_addr_t first;
1365  xdes_t* descr;
1366  ulint free;
1367  ulint page_no;
1368  ulint space_size;
1369 
1370  ut_ad(mtr);
1371  ut_ad(init_mtr);
1372 
1373  header = fsp_get_space_header(space, zip_size, mtr);
1374 
1375  /* Get the hinted descriptor */
1376  descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1377 
1378  if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1379  /* Ok, we can take this extent */
1380  } else {
1381  /* Else take the first extent in free_frag list */
1382  first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1383 
1384  if (fil_addr_is_null(first)) {
1385  /* There are no partially full fragments: allocate
1386  a free extent and add it to the FREE_FRAG list. NOTE
1387  that the allocation may have as a side-effect that an
1388  extent containing a descriptor page is added to the
1389  FREE_FRAG list. But we will allocate our page from the
1390  the free extent anyway. */
1391 
1392  descr = fsp_alloc_free_extent(space, zip_size,
1393  hint, mtr);
1394 
1395  if (descr == NULL) {
1396  /* No free space left */
1397 
1398  return(NULL);
1399  }
1400 
1401  xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1402  flst_add_last(header + FSP_FREE_FRAG,
1403  descr + XDES_FLST_NODE, mtr);
1404  } else {
1405  descr = xdes_lst_get_descriptor(space, zip_size,
1406  first, mtr);
1407  }
1408 
1409  /* Reset the hint */
1410  hint = 0;
1411  }
1412 
1413  /* Now we have in descr an extent with at least one free page. Look
1414  for a free page in the extent. */
1415 
1416  free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1417  hint % FSP_EXTENT_SIZE, mtr);
1418  if (free == ULINT_UNDEFINED) {
1419 
1420  ut_print_buf(stderr, ((byte*) descr) - 500, 1000);
1421  putc('\n', stderr);
1422 
1423  ut_error;
1424  }
1425 
1426  page_no = xdes_get_offset(descr) + free;
1427 
1428  space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1429 
1430  if (space_size <= page_no) {
1431  /* It must be that we are extending a single-table tablespace
1432  whose size is still < 64 pages */
1433 
1434  ut_a(space != 0);
1435  if (page_no >= FSP_EXTENT_SIZE) {
1436  fprintf(stderr,
1437  "InnoDB: Error: trying to extend a"
1438  " single-table tablespace %lu\n"
1439  "InnoDB: by single page(s) though the"
1440  " space size %lu. Page no %lu.\n",
1441  (ulong) space, (ulong) space_size,
1442  (ulong) page_no);
1443  return(NULL);
1444  }
1445  if (!fsp_try_extend_data_file_with_pages(space, page_no,
1446  header, mtr)) {
1447  /* No disk space left */
1448  return(NULL);
1449  }
1450  }
1451 
1452  fsp_alloc_from_free_frag(header, descr, free, mtr);
1453  return(fsp_page_create(space, zip_size, page_no, mtr, init_mtr));
1454 }
1455 
1456 /**********************************************************************/
1458 static
1459 void
1460 fsp_free_page(
1461 /*==========*/
1462  ulint space,
1463  ulint zip_size,
1465  ulint page,
1466  mtr_t* mtr)
1467 {
1468  fsp_header_t* header;
1469  xdes_t* descr;
1470  ulint state;
1471  ulint frag_n_used;
1472 
1473  ut_ad(mtr);
1474 
1475  /* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1476 
1477  header = fsp_get_space_header(space, zip_size, mtr);
1478 
1479  descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1480 
1481  state = xdes_get_state(descr, mtr);
1482 
1483  if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1484  fprintf(stderr,
1485  "InnoDB: Error: File space extent descriptor"
1486  " of page %lu has state %lu\n",
1487  (ulong) page,
1488  (ulong) state);
1489  fputs("InnoDB: Dump of descriptor: ", stderr);
1490  ut_print_buf(stderr, ((byte*) descr) - 50, 200);
1491  putc('\n', stderr);
1492  /* Crash in debug version, so that we get a core dump
1493  of this corruption. */
1494  ut_ad(0);
1495 
1496  if (state == XDES_FREE) {
1497  /* We put here some fault tolerance: if the page
1498  is already free, return without doing anything! */
1499 
1500  return;
1501  }
1502 
1503  ut_error;
1504  }
1505 
1506  if (xdes_mtr_get_bit(descr, XDES_FREE_BIT,
1507  page % FSP_EXTENT_SIZE, mtr)) {
1508 
1509  fprintf(stderr,
1510  "InnoDB: Error: File space extent descriptor"
1511  " of page %lu says it is free\n"
1512  "InnoDB: Dump of descriptor: ", (ulong) page);
1513  ut_print_buf(stderr, ((byte*) descr) - 50, 200);
1514  putc('\n', stderr);
1515  /* Crash in debug version, so that we get a core dump
1516  of this corruption. */
1517  ut_ad(0);
1518 
1519  /* We put here some fault tolerance: if the page
1520  is already free, return without doing anything! */
1521 
1522  return;
1523  }
1524 
1525  xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1526  xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1527 
1528  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1529  mtr);
1530  if (state == XDES_FULL_FRAG) {
1531  /* The fragment was full: move it to another list */
1532  flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1533  mtr);
1534  xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1535  flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1536  mtr);
1537  mlog_write_ulint(header + FSP_FRAG_N_USED,
1538  frag_n_used + FSP_EXTENT_SIZE - 1,
1539  MLOG_4BYTES, mtr);
1540  } else {
1541  ut_a(frag_n_used > 0);
1542  mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1543  MLOG_4BYTES, mtr);
1544  }
1545 
1546  if (xdes_is_free(descr, mtr)) {
1547  /* The extent has become free: move it to another list */
1548  flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1549  mtr);
1550  fsp_free_extent(space, zip_size, page, mtr);
1551  }
1552 
1553  mtr->n_freed_pages++;
1554 }
1555 
1556 /**********************************************************************/
1558 static
1559 void
1560 fsp_free_extent(
1561 /*============*/
1562  ulint space,
1563  ulint zip_size,
1565  ulint page,
1566  mtr_t* mtr)
1567 {
1568  fsp_header_t* header;
1569  xdes_t* descr;
1570 
1571  ut_ad(mtr);
1572 
1573  header = fsp_get_space_header(space, zip_size, mtr);
1574 
1575  descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1576 
1577  if (xdes_get_state(descr, mtr) == XDES_FREE) {
1578 
1579  ut_print_buf(stderr, (byte*) descr - 500, 1000);
1580  putc('\n', stderr);
1581 
1582  ut_error;
1583  }
1584 
1585  xdes_init(descr, mtr);
1586 
1587  flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1588 }
1589 
1590 /**********************************************************************/
1593 UNIV_INLINE
1594 fseg_inode_t*
1595 fsp_seg_inode_page_get_nth_inode(
1596 /*=============================*/
1597  page_t* page,
1598  ulint i,
1599  ulint zip_size __attribute__((unused)),
1601  mtr_t* mtr __attribute__((unused)))
1603 {
1604  ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1605  ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1606 
1607  return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1608 }
1609 
1610 /**********************************************************************/
1613 static
1614 ulint
1615 fsp_seg_inode_page_find_used(
1616 /*=========================*/
1617  page_t* page,
1618  ulint zip_size,
1619  mtr_t* mtr)
1620 {
1621  ulint i;
1622  fseg_inode_t* inode;
1623 
1624  for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1625 
1626  inode = fsp_seg_inode_page_get_nth_inode(
1627  page, i, zip_size, mtr);
1628 
1629  if (mach_read_from_8(inode + FSEG_ID)) {
1630  /* This is used */
1631 
1632  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1633  == FSEG_MAGIC_N_VALUE);
1634  return(i);
1635  }
1636  }
1637 
1638  return(ULINT_UNDEFINED);
1639 }
1640 
1641 /**********************************************************************/
1644 static
1645 ulint
1646 fsp_seg_inode_page_find_free(
1647 /*=========================*/
1648  page_t* page,
1649  ulint i,
1650  ulint zip_size,
1651  mtr_t* mtr)
1652 {
1653  for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1654 
1655  fseg_inode_t* inode;
1656 
1657  inode = fsp_seg_inode_page_get_nth_inode(
1658  page, i, zip_size, mtr);
1659 
1660  if (!mach_read_from_8(inode + FSEG_ID)) {
1661  /* This is unused */
1662  return(i);
1663  }
1664 
1665  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1666  == FSEG_MAGIC_N_VALUE);
1667  }
1668 
1669  return(ULINT_UNDEFINED);
1670 }
1671 
1672 /**********************************************************************/
1675 static
1676 ibool
1677 fsp_alloc_seg_inode_page(
1678 /*=====================*/
1679  fsp_header_t* space_header,
1680  mtr_t* mtr)
1681 {
1682  fseg_inode_t* inode;
1683  buf_block_t* block;
1684  page_t* page;
1685  ulint space;
1686  ulint zip_size;
1687 
1688  ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1689 
1690  space = page_get_space_id(page_align(space_header));
1691 
1692  zip_size = fsp_flags_get_zip_size(
1693  mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1694 
1695  block = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr);
1696 
1697  if (block == NULL) {
1698 
1699  return(FALSE);
1700  }
1701 
1702  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1703  ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
1704 
1705  block->check_index_page_at_flush = FALSE;
1706 
1707  page = buf_block_get_frame(block);
1708 
1710  MLOG_2BYTES, mtr);
1711 
1712  for (ulint i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1713 
1714  inode = fsp_seg_inode_page_get_nth_inode(
1715  page, i, zip_size, mtr);
1716 
1717  mlog_write_ull(inode + FSEG_ID, 0, mtr);
1718  }
1719 
1720  flst_add_last(
1721  space_header + FSP_SEG_INODES_FREE,
1722  page + FSEG_INODE_PAGE_NODE, mtr);
1723 
1724  return(TRUE);
1725 }
1726 
1727 /**********************************************************************/
1730 static
1731 fseg_inode_t*
1732 fsp_alloc_seg_inode(
1733 /*================*/
1734  fsp_header_t* space_header,
1735  mtr_t* mtr)
1736 {
1737  ulint page_no;
1738  buf_block_t* block;
1739  page_t* page;
1740  fseg_inode_t* inode;
1741  ibool success;
1742  ulint zip_size;
1743  ulint n;
1744 
1745  ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1746 
1747  if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1748  /* Allocate a new segment inode page */
1749 
1750  success = fsp_alloc_seg_inode_page(space_header, mtr);
1751 
1752  if (!success) {
1753 
1754  return(NULL);
1755  }
1756  }
1757 
1758  page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1759 
1760  zip_size = fsp_flags_get_zip_size(
1761  mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1762  block = buf_page_get(page_get_space_id(page_align(space_header)),
1763  zip_size, page_no, RW_X_LATCH, mtr);
1764  buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1765 
1766  page = buf_block_get_frame(block);
1767 
1768  n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1769 
1770  ut_a(n != ULINT_UNDEFINED);
1771 
1772  inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1773 
1774  if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1775  zip_size, mtr)) {
1776  /* There are no other unused headers left on the page: move it
1777  to another list */
1778 
1779  flst_remove(space_header + FSP_SEG_INODES_FREE,
1780  page + FSEG_INODE_PAGE_NODE, mtr);
1781 
1782  flst_add_last(space_header + FSP_SEG_INODES_FULL,
1783  page + FSEG_INODE_PAGE_NODE, mtr);
1784  }
1785 
1786  ut_ad(!mach_read_from_8(inode + FSEG_ID)
1787  || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1788  return(inode);
1789 }
1790 
1791 /**********************************************************************/
1793 static
1794 void
1795 fsp_free_seg_inode(
1796 /*===============*/
1797  ulint space,
1798  ulint zip_size,
1800  fseg_inode_t* inode,
1801  mtr_t* mtr)
1802 {
1803  page_t* page;
1804  fsp_header_t* space_header;
1805 
1806  page = page_align(inode);
1807 
1808  space_header = fsp_get_space_header(space, zip_size, mtr);
1809 
1810  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1811 
1812  if (ULINT_UNDEFINED
1813  == fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
1814 
1815  /* Move the page to another list */
1816 
1817  flst_remove(space_header + FSP_SEG_INODES_FULL,
1818  page + FSEG_INODE_PAGE_NODE, mtr);
1819 
1820  flst_add_last(space_header + FSP_SEG_INODES_FREE,
1821  page + FSEG_INODE_PAGE_NODE, mtr);
1822  }
1823 
1824  mlog_write_ull(inode + FSEG_ID, 0, mtr);
1825  mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
1826 
1827  if (ULINT_UNDEFINED
1828  == fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
1829 
1830  /* There are no other used headers left on the page: free it */
1831 
1832  flst_remove(space_header + FSP_SEG_INODES_FREE,
1833  page + FSEG_INODE_PAGE_NODE, mtr);
1834 
1835  fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
1836  }
1837 }
1838 
1839 /**********************************************************************/
1842 static
1843 fseg_inode_t*
1844 fseg_inode_try_get(
1845 /*===============*/
1846  fseg_header_t* header,
1847  ulint space,
1848  ulint zip_size,
1850  mtr_t* mtr)
1851 {
1852  fil_addr_t inode_addr;
1853  fseg_inode_t* inode;
1854 
1855  inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
1856  inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
1857  ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
1858 
1859  inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
1860 
1861  if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
1862 
1863  inode = NULL;
1864  } else {
1865  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1866  == FSEG_MAGIC_N_VALUE);
1867  }
1868 
1869  return(inode);
1870 }
1871 
1872 /**********************************************************************/
1875 static
1876 fseg_inode_t*
1877 fseg_inode_get(
1878 /*===========*/
1879  fseg_header_t* header,
1880  ulint space,
1881  ulint zip_size,
1883  mtr_t* mtr)
1884 {
1885  fseg_inode_t* inode
1886  = fseg_inode_try_get(header, space, zip_size, mtr);
1887  ut_a(inode);
1888  return(inode);
1889 }
1890 
1891 /**********************************************************************/
1894 UNIV_INLINE
1895 ulint
1896 fseg_get_nth_frag_page_no(
1897 /*======================*/
1898  fseg_inode_t* inode,
1899  ulint n,
1900  mtr_t* mtr __attribute__((unused)))
1902 {
1903  ut_ad(inode && mtr);
1904  ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
1905  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
1906  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1907  return(mach_read_from_4(inode + FSEG_FRAG_ARR
1908  + n * FSEG_FRAG_SLOT_SIZE));
1909 }
1910 
1911 /**********************************************************************/
1913 UNIV_INLINE
1914 void
1915 fseg_set_nth_frag_page_no(
1916 /*======================*/
1917  fseg_inode_t* inode,
1918  ulint n,
1919  ulint page_no,
1920  mtr_t* mtr)
1921 {
1922  ut_ad(inode && mtr);
1923  ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
1924  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
1925  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1926 
1927  mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
1928  page_no, MLOG_4BYTES, mtr);
1929 }
1930 
1931 /**********************************************************************/
1934 static
1935 ulint
1936 fseg_find_free_frag_page_slot(
1937 /*==========================*/
1938  fseg_inode_t* inode,
1939  mtr_t* mtr)
1940 {
1941  ulint i;
1942  ulint page_no;
1943 
1944  ut_ad(inode && mtr);
1945 
1946  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
1947  page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
1948 
1949  if (page_no == FIL_NULL) {
1950 
1951  return(i);
1952  }
1953  }
1954 
1955  return(ULINT_UNDEFINED);
1956 }
1957 
1958 /**********************************************************************/
1961 static
1962 ulint
1963 fseg_find_last_used_frag_page_slot(
1964 /*===============================*/
1965  fseg_inode_t* inode,
1966  mtr_t* mtr)
1967 {
1968  ulint i;
1969  ulint page_no;
1970 
1971  ut_ad(inode && mtr);
1972 
1973  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
1974  page_no = fseg_get_nth_frag_page_no(
1975  inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
1976 
1977  if (page_no != FIL_NULL) {
1978 
1979  return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
1980  }
1981  }
1982 
1983  return(ULINT_UNDEFINED);
1984 }
1985 
1986 /**********************************************************************/
1989 static
1990 ulint
1991 fseg_get_n_frag_pages(
1992 /*==================*/
1993  fseg_inode_t* inode,
1994  mtr_t* mtr)
1995 {
1996  ulint i;
1997  ulint count = 0;
1998 
1999  ut_ad(inode && mtr);
2000 
2001  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2002  if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2003  count++;
2004  }
2005  }
2006 
2007  return(count);
2008 }
2009 
2010 /**********************************************************************/
2014 UNIV_INTERN
2015 buf_block_t*
2017 /*================*/
2018  ulint space,
2019  ulint page,
2023  ulint byte_offset,
2025  ibool has_done_reservation,
2031  mtr_t* mtr)
2032 {
2033  ulint flags;
2034  ulint zip_size;
2035  fsp_header_t* space_header;
2036  fseg_inode_t* inode;
2037  ib_id_t seg_id;
2038  buf_block_t* block = 0; /* remove warning */
2039  fseg_header_t* header = 0; /* remove warning */
2040  rw_lock_t* latch;
2041  ibool success;
2042  ulint n_reserved;
2043  ulint i;
2044 
2045  ut_ad(mtr);
2046  ut_ad(byte_offset + FSEG_HEADER_SIZE
2047  <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2048 
2049  latch = fil_space_get_latch(space, &flags);
2050  zip_size = fsp_flags_get_zip_size(flags);
2051 
2052  if (page != 0) {
2053  block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2054  header = byte_offset + buf_block_get_frame(block);
2055  }
2056 
2057  mtr_x_lock(latch, mtr);
2058 
2059  if (rw_lock_get_x_lock_count(latch) == 1) {
2060  /* This thread did not own the latch before this call: free
2061  excess pages from the insert buffer free list */
2062 
2063  if (space == IBUF_SPACE_ID) {
2065  }
2066  }
2067 
2068  if (!has_done_reservation) {
2069  success = fsp_reserve_free_extents(&n_reserved, space, 2,
2070  FSP_NORMAL, mtr);
2071  if (!success) {
2072  return(NULL);
2073  }
2074  }
2075 
2076  space_header = fsp_get_space_header(space, zip_size, mtr);
2077 
2078  inode = fsp_alloc_seg_inode(space_header, mtr);
2079 
2080  if (inode == NULL) {
2081 
2082  goto funct_exit;
2083  }
2084 
2085  /* Read the next segment id from space header and increment the
2086  value in space header */
2087 
2088  seg_id = mach_read_from_8(space_header + FSP_SEG_ID);
2089 
2090  mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr);
2091 
2092  mlog_write_ull(inode + FSEG_ID, seg_id, mtr);
2093  mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2094 
2095  flst_init(inode + FSEG_FREE, mtr);
2096  flst_init(inode + FSEG_NOT_FULL, mtr);
2097  flst_init(inode + FSEG_FULL, mtr);
2098 
2099  mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2100  MLOG_4BYTES, mtr);
2101  for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2102  fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2103  }
2104 
2105  if (page == 0) {
2106  block = fseg_alloc_free_page_low(space, zip_size,
2107  inode, 0, FSP_UP, mtr, mtr);
2108 
2109  if (block == NULL) {
2110 
2111  fsp_free_seg_inode(space, zip_size, inode, mtr);
2112 
2113  goto funct_exit;
2114  }
2115 
2116  ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
2117 
2118  header = byte_offset + buf_block_get_frame(block);
2119  mlog_write_ulint(buf_block_get_frame(block) + FIL_PAGE_TYPE,
2121  }
2122 
2123  mlog_write_ulint(header + FSEG_HDR_OFFSET,
2124  page_offset(inode), MLOG_2BYTES, mtr);
2125 
2126  mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2127  page_get_page_no(page_align(inode)),
2128  MLOG_4BYTES, mtr);
2129 
2130  mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2131 
2132 funct_exit:
2133  if (!has_done_reservation) {
2134 
2135  fil_space_release_free_extents(space, n_reserved);
2136  }
2137 
2138  return(block);
2139 }
2140 
2141 /**********************************************************************/
2145 UNIV_INTERN
2146 buf_block_t*
2147 fseg_create(
2148 /*========*/
2149  ulint space,
2150  ulint page,
2154  ulint byte_offset,
2156  mtr_t* mtr)
2157 {
2158  return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2159 }
2160 
2161 /**********************************************************************/
2165 static
2166 ulint
2167 fseg_n_reserved_pages_low(
2168 /*======================*/
2169  fseg_inode_t* inode,
2170  ulint* used,
2172  mtr_t* mtr)
2173 {
2174  ulint ret;
2175 
2176  ut_ad(inode && used && mtr);
2177  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2178 
2179  *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2180  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2181  + fseg_get_n_frag_pages(inode, mtr);
2182 
2183  ret = fseg_get_n_frag_pages(inode, mtr)
2184  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2185  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2186  + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2187 
2188  return(ret);
2189 }
2190 
2191 /**********************************************************************/
2195 UNIV_INTERN
2196 ulint
2198 /*==================*/
2199  fseg_header_t* header,
2200  ulint* used,
2201  mtr_t* mtr)
2202 {
2203  ulint ret;
2204  fseg_inode_t* inode;
2205  ulint space;
2206  ulint flags;
2207  ulint zip_size;
2208  rw_lock_t* latch;
2209 
2210  space = page_get_space_id(page_align(header));
2211  latch = fil_space_get_latch(space, &flags);
2212  zip_size = fsp_flags_get_zip_size(flags);
2213 
2214  mtr_x_lock(latch, mtr);
2215 
2216  inode = fseg_inode_get(header, space, zip_size, mtr);
2217 
2218  ret = fseg_n_reserved_pages_low(inode, used, mtr);
2219 
2220  return(ret);
2221 }
2222 
2223 /*********************************************************************/
2228 static
2229 void
2230 fseg_fill_free_list(
2231 /*================*/
2232  fseg_inode_t* inode,
2233  ulint space,
2234  ulint zip_size,
2236  ulint hint,
2238  mtr_t* mtr)
2239 {
2240  xdes_t* descr;
2241  ulint i;
2242  ib_id_t seg_id;
2243  ulint reserved;
2244  ulint used;
2245 
2246  ut_ad(inode && mtr);
2247  ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2248 
2249  reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2250 
2251  if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2252 
2253  /* The segment is too small to allow extents in free list */
2254 
2255  return;
2256  }
2257 
2258  if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2259  /* Free list is not empty */
2260 
2261  return;
2262  }
2263 
2264  for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2265  descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2266 
2267  if ((descr == NULL)
2268  || (XDES_FREE != xdes_get_state(descr, mtr))) {
2269 
2270  /* We cannot allocate the desired extent: stop */
2271 
2272  return;
2273  }
2274 
2275  descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2276 
2277  xdes_set_state(descr, XDES_FSEG, mtr);
2278 
2279  seg_id = mach_read_from_8(inode + FSEG_ID);
2280  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2281  == FSEG_MAGIC_N_VALUE);
2282  mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2283 
2284  flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2285  hint += FSP_EXTENT_SIZE;
2286  }
2287 }
2288 
2289 /*********************************************************************/
2297 static
2298 xdes_t*
2299 fseg_alloc_free_extent(
2300 /*===================*/
2301  fseg_inode_t* inode,
2302  ulint space,
2303  ulint zip_size,
2305  mtr_t* mtr)
2306 {
2307  xdes_t* descr;
2308  ib_id_t seg_id;
2309  fil_addr_t first;
2310 
2311  ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2312  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2313 
2314  if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2315  /* Segment free list is not empty, allocate from it */
2316 
2317  first = flst_get_first(inode + FSEG_FREE, mtr);
2318 
2319  descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2320  } else {
2321  /* Segment free list was empty, allocate from space */
2322  descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2323 
2324  if (descr == NULL) {
2325 
2326  return(NULL);
2327  }
2328 
2329  seg_id = mach_read_from_8(inode + FSEG_ID);
2330 
2331  xdes_set_state(descr, XDES_FSEG, mtr);
2332  mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2333  flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2334 
2335  /* Try to fill the segment free list */
2336  fseg_fill_free_list(inode, space, zip_size,
2337  xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2338  mtr);
2339  }
2340 
2341  return(descr);
2342 }
2343 
2344 /**********************************************************************/
2352 static
2353 buf_block_t*
2354 fseg_alloc_free_page_low(
2355 /*=====================*/
2356  ulint space,
2357  ulint zip_size,
2359  fseg_inode_t* seg_inode,
2360  ulint hint,
2362  byte direction,
2367  mtr_t* mtr,
2368  mtr_t* init_mtr)
2372 {
2373  fsp_header_t* space_header;
2374  ulint space_size;
2375  ib_id_t seg_id;
2376  ulint used;
2377  ulint reserved;
2378  xdes_t* descr;
2379  ulint ret_page;
2381  xdes_t* ret_descr;
2382  ibool success;
2383  ulint n;
2384 
2385  ut_ad(mtr);
2386  ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2387  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2388  == FSEG_MAGIC_N_VALUE);
2389  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2390  seg_id = mach_read_from_8(seg_inode + FSEG_ID);
2391 
2392  ut_ad(seg_id);
2393 
2394  reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2395 
2396  space_header = fsp_get_space_header(space, zip_size, mtr);
2397 
2398  descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2399  hint, mtr);
2400  if (descr == NULL) {
2401  /* Hint outside space or too high above free limit: reset
2402  hint */
2403  /* The file space header page is always allocated. */
2404  hint = 0;
2405  descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2406  }
2407 
2408  /* In the big if-else below we look for ret_page and ret_descr */
2409  /*-------------------------------------------------------------*/
2410  if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2411  && mach_read_from_8(descr + XDES_ID) == seg_id
2412  && (xdes_mtr_get_bit(descr, XDES_FREE_BIT,
2413  hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2414 take_hinted_page:
2415  /* 1. We can take the hinted page
2416  =================================*/
2417  ret_descr = descr;
2418  ret_page = hint;
2419  /* Skip the check for extending the tablespace. If the
2420  page hint were not within the size of the tablespace,
2421  we would have got (descr == NULL) above and reset the hint. */
2422  goto got_hinted_page;
2423  /*-----------------------------------------------------------*/
2424  } else if (xdes_get_state(descr, mtr) == XDES_FREE
2425  && reserved - used < reserved / FSEG_FILLFACTOR
2426  && used >= FSEG_FRAG_LIMIT) {
2427 
2428  /* 2. We allocate the free extent from space and can take
2429  =========================================================
2430  the hinted page
2431  ===============*/
2432  ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2433 
2434  ut_a(ret_descr == descr);
2435 
2436  xdes_set_state(ret_descr, XDES_FSEG, mtr);
2437  mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
2438  flst_add_last(seg_inode + FSEG_FREE,
2439  ret_descr + XDES_FLST_NODE, mtr);
2440 
2441  /* Try to fill the segment free list */
2442  fseg_fill_free_list(seg_inode, space, zip_size,
2443  hint + FSP_EXTENT_SIZE, mtr);
2444  goto take_hinted_page;
2445  /*-----------------------------------------------------------*/
2446  } else if ((direction != FSP_NO_DIR)
2447  && ((reserved - used) < reserved / FSEG_FILLFACTOR)
2448  && (used >= FSEG_FRAG_LIMIT)
2449  && (!!(ret_descr
2450  = fseg_alloc_free_extent(seg_inode,
2451  space, zip_size, mtr)))) {
2452 
2453  /* 3. We take any free extent (which was already assigned above
2454  ===============================================================
2455  in the if-condition to ret_descr) and take the lowest or
2456  ========================================================
2457  highest page in it, depending on the direction
2458  ==============================================*/
2459  ret_page = xdes_get_offset(ret_descr);
2460 
2461  if (direction == FSP_DOWN) {
2462  ret_page += FSP_EXTENT_SIZE - 1;
2463  }
2464  /*-----------------------------------------------------------*/
2465  } else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2466  && mach_read_from_8(descr + XDES_ID) == seg_id
2467  && (!xdes_is_full(descr, mtr))) {
2468 
2469  /* 4. We can take the page from the same extent as the
2470  ======================================================
2471  hinted page (and the extent already belongs to the
2472  ==================================================
2473  segment)
2474  ========*/
2475  ret_descr = descr;
2476  ret_page = xdes_get_offset(ret_descr)
2477  + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2478  hint % FSP_EXTENT_SIZE, mtr);
2479  /*-----------------------------------------------------------*/
2480  } else if (reserved - used > 0) {
2481  /* 5. We take any unused page from the segment
2482  ==============================================*/
2483  fil_addr_t first;
2484 
2485  if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2486  first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2487  mtr);
2488  } else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2489  first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2490  } else {
2491  ut_error;
2492  return(NULL);
2493  }
2494 
2495  ret_descr = xdes_lst_get_descriptor(space, zip_size,
2496  first, mtr);
2497  ret_page = xdes_get_offset(ret_descr)
2498  + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2499  0, mtr);
2500  /*-----------------------------------------------------------*/
2501  } else if (used < FSEG_FRAG_LIMIT) {
2502  /* 6. We allocate an individual page from the space
2503  ===================================================*/
2504  buf_block_t* block = fsp_alloc_free_page(
2505  space, zip_size, hint, mtr, init_mtr);
2506 
2507  if (block != NULL) {
2508  /* Put the page in the fragment page array of the
2509  segment */
2510  n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2511  ut_a(n != ULINT_UNDEFINED);
2512 
2513  fseg_set_nth_frag_page_no(
2514  seg_inode, n, buf_block_get_page_no(block),
2515  mtr);
2516  }
2517 
2518  /* fsp_alloc_free_page() invoked fsp_init_file_page()
2519  already. */
2520  return(block);
2521  /*-----------------------------------------------------------*/
2522  } else {
2523  /* 7. We allocate a new extent and take its first page
2524  ======================================================*/
2525  ret_descr = fseg_alloc_free_extent(seg_inode,
2526  space, zip_size, mtr);
2527 
2528  if (ret_descr == NULL) {
2529  ret_page = FIL_NULL;
2530  } else {
2531  ret_page = xdes_get_offset(ret_descr);
2532  }
2533  }
2534 
2535  if (ret_page == FIL_NULL) {
2536  /* Page could not be allocated */
2537 
2538  return(NULL);
2539  }
2540 
2541  if (space != 0) {
2542  space_size = fil_space_get_size(space);
2543 
2544  if (space_size <= ret_page) {
2545  /* It must be that we are extending a single-table
2546  tablespace whose size is still < 64 pages */
2547 
2548  if (ret_page >= FSP_EXTENT_SIZE) {
2549  fprintf(stderr,
2550  "InnoDB: Error (2): trying to extend"
2551  " a single-table tablespace %lu\n"
2552  "InnoDB: by single page(s) though"
2553  " the space size %lu. Page no %lu.\n",
2554  (ulong) space, (ulong) space_size,
2555  (ulong) ret_page);
2556  return(NULL);
2557  }
2558 
2559  success = fsp_try_extend_data_file_with_pages(
2560  space, ret_page, space_header, mtr);
2561  if (!success) {
2562  /* No disk space left */
2563  return(NULL);
2564  }
2565  }
2566  }
2567 
2568 got_hinted_page:
2569  /* ret_descr == NULL if the block was allocated from free_frag
2570  (XDES_FREE_FRAG) */
2571  if (ret_descr != NULL) {
2572  /* At this point we know the extent and the page offset.
2573  The extent is still in the appropriate list (FSEG_NOT_FULL
2574  or FSEG_FREE), and the page is not yet marked as used. */
2575 
2576  ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
2577  == ret_descr);
2578 
2580  ret_descr, XDES_FREE_BIT,
2581  ret_page % FSP_EXTENT_SIZE, mtr));
2582 
2583  fseg_mark_page_used(seg_inode, ret_page, ret_descr, mtr);
2584  }
2585 
2586  return(fsp_page_create(
2587  space, fsp_flags_get_zip_size(
2588  mach_read_from_4(FSP_SPACE_FLAGS
2589  + space_header)),
2590  ret_page, mtr, init_mtr));
2591 }
2592 
2593 /**********************************************************************/
2601 UNIV_INTERN
2602 buf_block_t*
2604 /*=========================*/
2605  fseg_header_t* seg_header,
2606  ulint hint,
2608  byte direction,
2613  ibool has_done_reservation,
2618  mtr_t* mtr,
2619  mtr_t* init_mtr)
2623 {
2624  fseg_inode_t* inode;
2625  ulint space;
2626  ulint flags;
2627  ulint zip_size;
2628  rw_lock_t* latch;
2629  buf_block_t* block;
2630  ulint n_reserved;
2631 
2632  space = page_get_space_id(page_align(seg_header));
2633 
2634  latch = fil_space_get_latch(space, &flags);
2635 
2636  zip_size = fsp_flags_get_zip_size(flags);
2637 
2638  mtr_x_lock(latch, mtr);
2639 
2640  if (rw_lock_get_x_lock_count(latch) == 1) {
2641  /* This thread did not own the latch before this call: free
2642  excess pages from the insert buffer free list */
2643 
2644  if (space == IBUF_SPACE_ID) {
2646  }
2647  }
2648 
2649  inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2650 
2651  if (!has_done_reservation
2652  && !fsp_reserve_free_extents(&n_reserved, space, 2,
2653  FSP_NORMAL, mtr)) {
2654  return(NULL);
2655  }
2656 
2657  block = fseg_alloc_free_page_low(space, zip_size,
2658  inode, hint, direction,
2659  mtr, init_mtr);
2660  if (!has_done_reservation) {
2661  fil_space_release_free_extents(space, n_reserved);
2662  }
2663 
2664  return(block);
2665 }
2666 
2667 /**********************************************************************/
2674 static
2675 ibool
2676 fsp_reserve_free_pages(
2677 /*===================*/
2678  ulint space,
2679  fsp_header_t* space_header,
2681  ulint size,
2683  mtr_t* mtr)
2684 {
2685  xdes_t* descr;
2686  ulint n_used;
2687 
2688  ut_a(space != 0);
2689  ut_a(size < FSP_EXTENT_SIZE / 2);
2690 
2691  descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2692  mtr);
2693  n_used = xdes_get_n_used(descr, mtr);
2694 
2695  ut_a(n_used <= size);
2696 
2697  if (size >= n_used + 2) {
2698 
2699  return(TRUE);
2700  }
2701 
2702  return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2703  space_header, mtr));
2704 }
2705 
2706 /**********************************************************************/
2732 UNIV_INTERN
2733 ibool
2735 /*=====================*/
2736  ulint* n_reserved,
2739  ulint space,
2740  ulint n_ext,
2741  ulint alloc_type,
2742  mtr_t* mtr)
2743 {
2744  fsp_header_t* space_header;
2745  rw_lock_t* latch;
2746  ulint n_free_list_ext;
2747  ulint free_limit;
2748  ulint size;
2749  ulint flags;
2750  ulint zip_size;
2751  ulint n_free;
2752  ulint n_free_up;
2753  ulint reserve;
2754  ibool success;
2755  ulint n_pages_added;
2756 
2757  ut_ad(mtr);
2758  *n_reserved = n_ext;
2759 
2760  latch = fil_space_get_latch(space, &flags);
2761  zip_size = fsp_flags_get_zip_size(flags);
2762 
2763  mtr_x_lock(latch, mtr);
2764 
2765  space_header = fsp_get_space_header(space, zip_size, mtr);
2766 try_again:
2767  size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
2768 
2769  if (size < FSP_EXTENT_SIZE / 2) {
2770  /* Use different rules for small single-table tablespaces */
2771  *n_reserved = 0;
2772  return(fsp_reserve_free_pages(space, space_header, size, mtr));
2773  }
2774 
2775  n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
2776 
2777  free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
2778  MLOG_4BYTES, mtr);
2779 
2780  /* Below we play safe when counting free extents above the free limit:
2781  some of them will contain extent descriptor pages, and therefore
2782  will not be free extents */
2783 
2784  n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
2785 
2786  if (n_free_up > 0) {
2787  n_free_up--;
2788  if (!zip_size) {
2789  n_free_up -= n_free_up
2790  / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
2791  } else {
2792  n_free_up -= n_free_up
2793  / (zip_size / FSP_EXTENT_SIZE);
2794  }
2795  }
2796 
2797  n_free = n_free_list_ext + n_free_up;
2798 
2799  if (alloc_type == FSP_NORMAL) {
2800  /* We reserve 1 extent + 0.5 % of the space size to undo logs
2801  and 1 extent + 0.5 % to cleaning operations; NOTE: this source
2802  code is duplicated in the function below! */
2803 
2804  reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
2805 
2806  if (n_free <= reserve + n_ext) {
2807 
2808  goto try_to_extend;
2809  }
2810  } else if (alloc_type == FSP_UNDO) {
2811  /* We reserve 0.5 % of the space size to cleaning operations */
2812 
2813  reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
2814 
2815  if (n_free <= reserve + n_ext) {
2816 
2817  goto try_to_extend;
2818  }
2819  } else {
2820  ut_a(alloc_type == FSP_CLEANING);
2821  }
2822 
2823  success = fil_space_reserve_free_extents(space, n_free, n_ext);
2824 
2825  if (success) {
2826  return(TRUE);
2827  }
2828 try_to_extend:
2829  success = fsp_try_extend_data_file(&n_pages_added, space,
2830  space_header, mtr);
2831  if (success && n_pages_added > 0) {
2832 
2833  goto try_again;
2834  }
2835 
2836  return(FALSE);
2837 }
2838 
2839 /**********************************************************************/
2845 UNIV_INTERN
2846 ullint
2848 /*====================================*/
2849  ulint space)
2850 {
2851  fsp_header_t* space_header;
2852  ulint n_free_list_ext;
2853  ulint free_limit;
2854  ulint size;
2855  ulint flags;
2856  ulint zip_size;
2857  ulint n_free;
2858  ulint n_free_up;
2859  ulint reserve;
2860  rw_lock_t* latch;
2861  mtr_t mtr;
2862 
2863  /* The convoluted mutex acquire is to overcome latching order
2864  issues: The problem is that the fil_mutex is at a lower level
2865  than the tablespace latch and the buffer pool mutex. We have to
2866  first prevent any operations on the file system by acquiring the
2867  dictionary mutex. Then acquire the tablespace latch to obey the
2868  latching order and then release the dictionary mutex. That way we
2869  ensure that the tablespace instance can't be freed while we are
2870  examining its contents (see fil_space_free()).
2871 
2872  However, there is one further complication, we release the fil_mutex
2873  when we need to invalidate the the pages in the buffer pool and we
2874  reacquire the fil_mutex when deleting and freeing the tablespace
2875  instance in fil0fil.cc. Here we need to account for that situation
2876  too. */
2877 
2878  mutex_enter(&dict_sys->mutex);
2879 
2880  /* At this stage there is no guarantee that the tablespace even
2881  exists in the cache. */
2882 
2884 
2885  mutex_exit(&dict_sys->mutex);
2886 
2887  return(ULLINT_UNDEFINED);
2888  }
2889 
2890  mtr_start(&mtr);
2891 
2892  latch = fil_space_get_latch(space, &flags);
2893 
2894  /* This should ensure that the tablespace instance can't be freed
2895  by another thread. However, the tablespace pages can still be freed
2896  from the buffer pool. We need to check for that again. */
2897 
2898  zip_size = fsp_flags_get_zip_size(flags);
2899 
2900  mtr_x_lock(latch, &mtr);
2901 
2902  mutex_exit(&dict_sys->mutex);
2903 
2904  /* At this point it is possible for the tablespace to be deleted and
2905  its pages removed from the buffer pool. We need to check for that
2906  situation. However, the tablespace instance can't be deleted because
2907  our latching above should ensure that. */
2908 
2909  if (fil_tablespace_is_being_deleted(space)) {
2910 
2911  mtr_commit(&mtr);
2912 
2913  return(ULLINT_UNDEFINED);
2914  }
2915 
2916  /* From here on even if the user has dropped the tablespace, the
2917  pages _must_ still exist in the buffer pool and the tablespace
2918  instance _must_ be in the file system hash table. */
2919 
2920  space_header = fsp_get_space_header(space, zip_size, &mtr);
2921 
2922  size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
2923 
2924  n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
2925 
2926  free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
2927  MLOG_4BYTES, &mtr);
2928  mtr_commit(&mtr);
2929 
2930  if (size < FSP_EXTENT_SIZE) {
2931  ut_a(space != 0); /* This must be a single-table
2932  tablespace */
2933 
2934  return(0); /* TODO: count free frag pages and
2935  return a value based on that */
2936  }
2937 
2938  /* Below we play safe when counting free extents above the free limit:
2939  some of them will contain extent descriptor pages, and therefore
2940  will not be free extents */
2941 
2942  n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
2943 
2944  if (n_free_up > 0) {
2945  n_free_up--;
2946  if (!zip_size) {
2947  n_free_up -= n_free_up
2948  / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
2949  } else {
2950  n_free_up -= n_free_up
2951  / (zip_size / FSP_EXTENT_SIZE);
2952  }
2953  }
2954 
2955  n_free = n_free_list_ext + n_free_up;
2956 
2957  /* We reserve 1 extent + 0.5 % of the space size to undo logs
2958  and 1 extent + 0.5 % to cleaning operations; NOTE: this source
2959  code is duplicated in the function above! */
2960 
2961  reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
2962 
2963  if (reserve > n_free) {
2964  return(0);
2965  }
2966 
2967  if (!zip_size) {
2968  return((ullint) (n_free - reserve)
2969  * FSP_EXTENT_SIZE
2970  * (UNIV_PAGE_SIZE / 1024));
2971  } else {
2972  return((ullint) (n_free - reserve)
2973  * FSP_EXTENT_SIZE
2974  * (zip_size / 1024));
2975  }
2976 }
2977 
2978 /********************************************************************/
2981 static __attribute__((nonnull))
2982 void
2983 fseg_mark_page_used(
2984 /*================*/
2985  fseg_inode_t* seg_inode,
2986  ulint page,
2987  xdes_t* descr,
2988  mtr_t* mtr)
2989 {
2990  ulint not_full_n_used;
2991 
2992  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2993  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2994  == FSEG_MAGIC_N_VALUE);
2995 
2996  ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
2997  == mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
2998 
2999  if (xdes_is_free(descr, mtr)) {
3000  /* We move the extent from the free list to the
3001  NOT_FULL list */
3002  flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3003  mtr);
3004  flst_add_last(seg_inode + FSEG_NOT_FULL,
3005  descr + XDES_FLST_NODE, mtr);
3006  }
3007 
3009  descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr));
3010 
3011  /* We mark the page as used */
3012  xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3013 
3014  not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3015  MLOG_4BYTES, mtr);
3016  not_full_n_used++;
3017  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3018  MLOG_4BYTES, mtr);
3019  if (xdes_is_full(descr, mtr)) {
3020  /* We move the extent from the NOT_FULL list to the
3021  FULL list */
3022  flst_remove(seg_inode + FSEG_NOT_FULL,
3023  descr + XDES_FLST_NODE, mtr);
3024  flst_add_last(seg_inode + FSEG_FULL,
3025  descr + XDES_FLST_NODE, mtr);
3026 
3027  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3028  not_full_n_used - FSP_EXTENT_SIZE,
3029  MLOG_4BYTES, mtr);
3030  }
3031 }
3032 
3033 /**********************************************************************/
3035 static
3036 void
3037 fseg_free_page_low(
3038 /*===============*/
3039  fseg_inode_t* seg_inode,
3040  ulint space,
3041  ulint zip_size,
3043  ulint page,
3044  mtr_t* mtr)
3045 {
3046  xdes_t* descr;
3047  ulint not_full_n_used;
3048  ulint state;
3049  ib_id_t descr_id;
3050  ib_id_t seg_id;
3051  ulint i;
3052 
3053  ut_ad(seg_inode && mtr);
3054  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3055  == FSEG_MAGIC_N_VALUE);
3056  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3057 
3058  /* Drop search system page hash index if the page is found in
3059  the pool and is hashed */
3060 
3061  btr_search_drop_page_hash_when_freed(space, zip_size, page);
3062 
3063  descr = xdes_get_descriptor(space, zip_size, page, mtr);
3064 
3065  if (xdes_mtr_get_bit(descr, XDES_FREE_BIT,
3066  page % FSP_EXTENT_SIZE, mtr)) {
3067  fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3068  stderr);
3069  ut_print_buf(stderr, descr, 40);
3070 
3071  fprintf(stderr, "\n"
3072  "InnoDB: Serious error! InnoDB is trying to"
3073  " free page %lu\n"
3074  "InnoDB: though it is already marked as free"
3075  " in the tablespace!\n"
3076  "InnoDB: The tablespace free space info is corrupt.\n"
3077  "InnoDB: You may need to dump your"
3078  " InnoDB tables and recreate the whole\n"
3079  "InnoDB: database!\n", (ulong) page);
3080 crash:
3081  fputs("InnoDB: Please refer to\n"
3082  "InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
3083  "InnoDB: about forcing recovery.\n", stderr);
3084  ut_error;
3085  }
3086 
3087  state = xdes_get_state(descr, mtr);
3088 
3089  if (state != XDES_FSEG) {
3090  /* The page is in the fragment pages of the segment */
3091 
3092  for (i = 0;; i++) {
3093  if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3094  == page) {
3095 
3096  fseg_set_nth_frag_page_no(seg_inode, i,
3097  FIL_NULL, mtr);
3098  break;
3099  }
3100  }
3101 
3102  fsp_free_page(space, zip_size, page, mtr);
3103 
3104  return;
3105  }
3106 
3107  /* If we get here, the page is in some extent of the segment */
3108 
3109  descr_id = mach_read_from_8(descr + XDES_ID);
3110  seg_id = mach_read_from_8(seg_inode + FSEG_ID);
3111 #if 0
3112  fprintf(stderr,
3113  "InnoDB: InnoDB is freeing space %lu page %lu,\n"
3114  "InnoDB: which belongs to descr seg %llu\n"
3115  "InnoDB: segment %llu.\n",
3116  (ulong) space, (ulong) page,
3117  (ullint) descr_id,
3118  (ullint) seg_id);
3119 #endif /* 0 */
3120  if (UNIV_UNLIKELY(descr_id != seg_id)) {
3121  fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3122  stderr);
3123  ut_print_buf(stderr, descr, 40);
3124  fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3125  ut_print_buf(stderr, seg_inode, 40);
3126  putc('\n', stderr);
3127 
3128  fprintf(stderr,
3129  "InnoDB: Serious error: InnoDB is trying to"
3130  " free space %lu page %lu,\n"
3131  "InnoDB: which does not belong to"
3132  " segment %llu but belongs\n"
3133  "InnoDB: to segment %llu.\n",
3134  (ulong) space, (ulong) page,
3135  (ullint) descr_id,
3136  (ullint) seg_id);
3137  goto crash;
3138  }
3139 
3140  not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3141  MLOG_4BYTES, mtr);
3142  if (xdes_is_full(descr, mtr)) {
3143  /* The fragment is full: move it to another list */
3144  flst_remove(seg_inode + FSEG_FULL,
3145  descr + XDES_FLST_NODE, mtr);
3146  flst_add_last(seg_inode + FSEG_NOT_FULL,
3147  descr + XDES_FLST_NODE, mtr);
3148  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3149  not_full_n_used + FSP_EXTENT_SIZE - 1,
3150  MLOG_4BYTES, mtr);
3151  } else {
3152  ut_a(not_full_n_used > 0);
3153  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3154  not_full_n_used - 1, MLOG_4BYTES, mtr);
3155  }
3156 
3157  xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3158  xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3159 
3160  if (xdes_is_free(descr, mtr)) {
3161  /* The extent has become free: free it to space */
3162  flst_remove(seg_inode + FSEG_NOT_FULL,
3163  descr + XDES_FLST_NODE, mtr);
3164  fsp_free_extent(space, zip_size, page, mtr);
3165  }
3166 
3167  mtr->n_freed_pages++;
3168 }
3169 
3170 /**********************************************************************/
3172 UNIV_INTERN
3173 void
3175 /*===========*/
3176  fseg_header_t* seg_header,
3177  ulint space,
3178  ulint page,
3179  mtr_t* mtr)
3180 {
3181  ulint flags;
3182  ulint zip_size;
3183  fseg_inode_t* seg_inode;
3184  rw_lock_t* latch;
3185 
3186  latch = fil_space_get_latch(space, &flags);
3187  zip_size = fsp_flags_get_zip_size(flags);
3188 
3189  mtr_x_lock(latch, mtr);
3190 
3191  seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3192 
3193  fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3194 
3195 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
3196  buf_page_set_file_page_was_freed(space, page);
3197 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
3198 }
3199 
3200 /**********************************************************************/
3203 UNIV_INTERN
3204 bool
3206 /*==============*/
3207  fseg_header_t* seg_header,
3208  ulint space,
3209  ulint page)
3210 {
3211  mtr_t mtr;
3212  ibool is_free;
3213  ulint flags;
3214  rw_lock_t* latch;
3215  xdes_t* descr;
3216  ulint zip_size;
3217  fseg_inode_t* seg_inode;
3218 
3219  latch = fil_space_get_latch(space, &flags);
3220  zip_size = dict_tf_get_zip_size(flags);
3221 
3222  mtr_start(&mtr);
3223  mtr_x_lock(latch, &mtr);
3224 
3225  seg_inode = fseg_inode_get(seg_header, space, zip_size, &mtr);
3226 
3227  ut_a(seg_inode);
3228  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3229  == FSEG_MAGIC_N_VALUE);
3230  ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3231 
3232  descr = xdes_get_descriptor(space, zip_size, page, &mtr);
3233  ut_a(descr);
3234 
3235  is_free = xdes_mtr_get_bit(
3236  descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, &mtr);
3237 
3238  mtr_commit(&mtr);
3239 
3240  return(is_free);
3241 }
3242 
3243 /**********************************************************************/
3245 static
3246 void
3247 fseg_free_extent(
3248 /*=============*/
3249  fseg_inode_t* seg_inode,
3250  ulint space,
3251  ulint zip_size,
3253  ulint page,
3254  mtr_t* mtr)
3255 {
3256  ulint first_page_in_extent;
3257  xdes_t* descr;
3258  ulint not_full_n_used;
3259  ulint descr_n_used;
3260  ulint i;
3261 
3262  ut_ad(seg_inode && mtr);
3263 
3264  descr = xdes_get_descriptor(space, zip_size, page, mtr);
3265 
3266  ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3267  ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
3268  ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3269  == FSEG_MAGIC_N_VALUE);
3270 
3271  first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3272 
3273  for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3274  if (!xdes_mtr_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3275 
3276  /* Drop search system page hash index if the page is
3277  found in the pool and is hashed */
3278 
3280  space, zip_size, first_page_in_extent + i);
3281  }
3282  }
3283 
3284  if (xdes_is_full(descr, mtr)) {
3285  flst_remove(seg_inode + FSEG_FULL,
3286  descr + XDES_FLST_NODE, mtr);
3287  } else if (xdes_is_free(descr, mtr)) {
3288  flst_remove(seg_inode + FSEG_FREE,
3289  descr + XDES_FLST_NODE, mtr);
3290  } else {
3291  flst_remove(seg_inode + FSEG_NOT_FULL,
3292  descr + XDES_FLST_NODE, mtr);
3293 
3294  not_full_n_used = mtr_read_ulint(
3295  seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3296 
3297  descr_n_used = xdes_get_n_used(descr, mtr);
3298  ut_a(not_full_n_used >= descr_n_used);
3299  mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3300  not_full_n_used - descr_n_used,
3301  MLOG_4BYTES, mtr);
3302  }
3303 
3304  fsp_free_extent(space, zip_size, page, mtr);
3305 
3306 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
3307  for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3308 
3309  buf_page_set_file_page_was_freed(space,
3310  first_page_in_extent + i);
3311  }
3312 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
3313 }
3314 
3315 /**********************************************************************/
3321 UNIV_INTERN
3322 ibool
3324 /*===========*/
3325  fseg_header_t* header,
3329  mtr_t* mtr)
3330 {
3331  ulint n;
3332  ulint page;
3333  xdes_t* descr;
3334  fseg_inode_t* inode;
3335  ulint space;
3336  ulint flags;
3337  ulint zip_size;
3338  ulint header_page;
3339  rw_lock_t* latch;
3340 
3341  space = page_get_space_id(page_align(header));
3342  header_page = page_get_page_no(page_align(header));
3343 
3344  latch = fil_space_get_latch(space, &flags);
3345  zip_size = fsp_flags_get_zip_size(flags);
3346 
3347  mtr_x_lock(latch, mtr);
3348 
3349  descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3350 
3351  /* Check that the header resides on a page which has not been
3352  freed yet */
3353 
3354  ut_a(xdes_mtr_get_bit(descr, XDES_FREE_BIT,
3355  header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3356 
3357  inode = fseg_inode_try_get(header, space, zip_size, mtr);
3358 
3359  if (UNIV_UNLIKELY(inode == NULL)) {
3360  fprintf(stderr, "double free of inode from %u:%u\n",
3361  (unsigned) space, (unsigned) header_page);
3362  return(TRUE);
3363  }
3364 
3365  descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3366 
3367  if (descr != NULL) {
3368  /* Free the extent held by the segment */
3369  page = xdes_get_offset(descr);
3370 
3371  fseg_free_extent(inode, space, zip_size, page, mtr);
3372 
3373  return(FALSE);
3374  }
3375 
3376  /* Free a frag page */
3377  n = fseg_find_last_used_frag_page_slot(inode, mtr);
3378 
3379  if (n == ULINT_UNDEFINED) {
3380  /* Freeing completed: free the segment inode */
3381  fsp_free_seg_inode(space, zip_size, inode, mtr);
3382 
3383  return(TRUE);
3384  }
3385 
3386  fseg_free_page_low(inode, space, zip_size,
3387  fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3388 
3389  n = fseg_find_last_used_frag_page_slot(inode, mtr);
3390 
3391  if (n == ULINT_UNDEFINED) {
3392  /* Freeing completed: free the segment inode */
3393  fsp_free_seg_inode(space, zip_size, inode, mtr);
3394 
3395  return(TRUE);
3396  }
3397 
3398  return(FALSE);
3399 }
3400 
3401 /**********************************************************************/
3405 UNIV_INTERN
3406 ibool
3408 /*======================*/
3409  fseg_header_t* header,
3411  mtr_t* mtr)
3412 {
3413  ulint n;
3414  ulint page;
3415  xdes_t* descr;
3416  fseg_inode_t* inode;
3417  ulint space;
3418  ulint flags;
3419  ulint zip_size;
3420  ulint page_no;
3421  rw_lock_t* latch;
3422 
3423  space = page_get_space_id(page_align(header));
3424 
3425  latch = fil_space_get_latch(space, &flags);
3426  zip_size = fsp_flags_get_zip_size(flags);
3427 
3428  mtr_x_lock(latch, mtr);
3429 
3430  inode = fseg_inode_get(header, space, zip_size, mtr);
3431 
3432  descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3433 
3434  if (descr != NULL) {
3435  /* Free the extent held by the segment */
3436  page = xdes_get_offset(descr);
3437 
3438  fseg_free_extent(inode, space, zip_size, page, mtr);
3439 
3440  return(FALSE);
3441  }
3442 
3443  /* Free a frag page */
3444 
3445  n = fseg_find_last_used_frag_page_slot(inode, mtr);
3446 
3447  if (n == ULINT_UNDEFINED) {
3448  ut_error;
3449  }
3450 
3451  page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3452 
3453  if (page_no == page_get_page_no(page_align(header))) {
3454 
3455  return(TRUE);
3456  }
3457 
3458  fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3459 
3460  return(FALSE);
3461 }
3462 
3463 /**********************************************************************/
3468 static
3469 xdes_t*
3470 fseg_get_first_extent(
3471 /*==================*/
3472  fseg_inode_t* inode,
3473  ulint space,
3474  ulint zip_size,
3476  mtr_t* mtr)
3477 {
3478  fil_addr_t first;
3479  xdes_t* descr;
3480 
3481  ut_ad(inode && mtr);
3482 
3483  ut_ad(space == page_get_space_id(page_align(inode)));
3484  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3485 
3486  first = fil_addr_null;
3487 
3488  if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3489 
3490  first = flst_get_first(inode + FSEG_FULL, mtr);
3491 
3492  } else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3493 
3494  first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3495 
3496  } else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3497 
3498  first = flst_get_first(inode + FSEG_FREE, mtr);
3499  }
3500 
3501  if (first.page == FIL_NULL) {
3502 
3503  return(NULL);
3504  }
3505  descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3506 
3507  return(descr);
3508 }
3509 
3510 /*******************************************************************/
3513 static
3514 ibool
3515 fseg_validate_low(
3516 /*==============*/
3517  fseg_inode_t* inode,
3518  mtr_t* mtr2)
3519 {
3520  ulint space;
3521  ib_id_t seg_id;
3522  mtr_t mtr;
3523  xdes_t* descr;
3524  fil_addr_t node_addr;
3525  ulint n_used = 0;
3526  ulint n_used2 = 0;
3527 
3528  ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3529  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3530 
3531  space = page_get_space_id(page_align(inode));
3532 
3533  seg_id = mach_read_from_8(inode + FSEG_ID);
3534  n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3535  MLOG_4BYTES, mtr2);
3536  flst_validate(inode + FSEG_FREE, mtr2);
3537  flst_validate(inode + FSEG_NOT_FULL, mtr2);
3538  flst_validate(inode + FSEG_FULL, mtr2);
3539 
3540  /* Validate FSEG_FREE list */
3541  node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3542 
3543  while (!fil_addr_is_null(node_addr)) {
3544  ulint flags;
3545  ulint zip_size;
3546 
3547  mtr_start(&mtr);
3548  mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3549  zip_size = fsp_flags_get_zip_size(flags);
3550 
3551  descr = xdes_lst_get_descriptor(space, zip_size,
3552  node_addr, &mtr);
3553 
3554  ut_a(xdes_get_n_used(descr, &mtr) == 0);
3555  ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3556  ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3557 
3558  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3559  mtr_commit(&mtr);
3560  }
3561 
3562  /* Validate FSEG_NOT_FULL list */
3563 
3564  node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3565 
3566  while (!fil_addr_is_null(node_addr)) {
3567  ulint flags;
3568  ulint zip_size;
3569 
3570  mtr_start(&mtr);
3571  mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3572  zip_size = fsp_flags_get_zip_size(flags);
3573 
3574  descr = xdes_lst_get_descriptor(space, zip_size,
3575  node_addr, &mtr);
3576 
3577  ut_a(xdes_get_n_used(descr, &mtr) > 0);
3578  ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3579  ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3580  ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3581 
3582  n_used2 += xdes_get_n_used(descr, &mtr);
3583 
3584  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3585  mtr_commit(&mtr);
3586  }
3587 
3588  /* Validate FSEG_FULL list */
3589 
3590  node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3591 
3592  while (!fil_addr_is_null(node_addr)) {
3593  ulint flags;
3594  ulint zip_size;
3595 
3596  mtr_start(&mtr);
3597  mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3598  zip_size = fsp_flags_get_zip_size(flags);
3599 
3600  descr = xdes_lst_get_descriptor(space, zip_size,
3601  node_addr, &mtr);
3602 
3603  ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3604  ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3605  ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3606 
3607  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3608  mtr_commit(&mtr);
3609  }
3610 
3611  ut_a(n_used == n_used2);
3612 
3613  return(TRUE);
3614 }
3615 
3616 #ifdef UNIV_DEBUG
3617 /*******************************************************************/
3620 UNIV_INTERN
3621 ibool
3622 fseg_validate(
3623 /*==========*/
3624  fseg_header_t* header,
3625  mtr_t* mtr)
3626 {
3627  fseg_inode_t* inode;
3628  ibool ret;
3629  ulint space;
3630  ulint flags;
3631  ulint zip_size;
3632 
3633  space = page_get_space_id(page_align(header));
3634 
3635  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3636  zip_size = fsp_flags_get_zip_size(flags);
3637 
3638  inode = fseg_inode_get(header, space, zip_size, mtr);
3639 
3640  ret = fseg_validate_low(inode, mtr);
3641 
3642  return(ret);
3643 }
3644 #endif /* UNIV_DEBUG */
3645 
3646 /*******************************************************************/
3648 static
3649 void
3650 fseg_print_low(
3651 /*===========*/
3652  fseg_inode_t* inode,
3653  mtr_t* mtr)
3654 {
3655  ulint space;
3656  ulint n_used;
3657  ulint n_frag;
3658  ulint n_free;
3659  ulint n_not_full;
3660  ulint n_full;
3661  ulint reserved;
3662  ulint used;
3663  ulint page_no;
3664  ib_id_t seg_id;
3665 
3666  ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3667  space = page_get_space_id(page_align(inode));
3668  page_no = page_get_page_no(page_align(inode));
3669 
3670  reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3671 
3672  seg_id = mach_read_from_8(inode + FSEG_ID);
3673 
3674  n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3675  MLOG_4BYTES, mtr);
3676  n_frag = fseg_get_n_frag_pages(inode, mtr);
3677  n_free = flst_get_len(inode + FSEG_FREE, mtr);
3678  n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3679  n_full = flst_get_len(inode + FSEG_FULL, mtr);
3680 
3681  fprintf(stderr,
3682  "SEGMENT id %llu space %lu; page %lu;"
3683  " res %lu used %lu; full ext %lu\n"
3684  "fragm pages %lu; free extents %lu;"
3685  " not full extents %lu: pages %lu\n",
3686  (ullint) seg_id,
3687  (ulong) space, (ulong) page_no,
3688  (ulong) reserved, (ulong) used, (ulong) n_full,
3689  (ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3690  (ulong) n_used);
3691  ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3692 }
3693 
3694 #ifdef UNIV_BTR_PRINT
3695 /*******************************************************************/
3697 UNIV_INTERN
3698 void
3699 fseg_print(
3700 /*=======*/
3701  fseg_header_t* header,
3702  mtr_t* mtr)
3703 {
3704  fseg_inode_t* inode;
3705  ulint space;
3706  ulint flags;
3707  ulint zip_size;
3708 
3709  space = page_get_space_id(page_align(header));
3710 
3711  mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3712  zip_size = fsp_flags_get_zip_size(flags);
3713 
3714  inode = fseg_inode_get(header, space, zip_size, mtr);
3715 
3716  fseg_print_low(inode, mtr);
3717 }
3718 #endif /* UNIV_BTR_PRINT */
3719 
3720 /*******************************************************************/
3723 UNIV_INTERN
3724 ibool
3725 fsp_validate(
3726 /*=========*/
3727  ulint space)
3728 {
3729  fsp_header_t* header;
3730  fseg_inode_t* seg_inode;
3731  page_t* seg_inode_page;
3732  rw_lock_t* latch;
3733  ulint size;
3734  ulint flags;
3735  ulint zip_size;
3736  ulint free_limit;
3737  ulint frag_n_used;
3738  mtr_t mtr;
3739  mtr_t mtr2;
3740  xdes_t* descr;
3741  fil_addr_t node_addr;
3742  fil_addr_t next_node_addr;
3743  ulint descr_count = 0;
3744  ulint n_used = 0;
3745  ulint n_used2 = 0;
3746  ulint n_full_frag_pages;
3747  ulint n;
3748  ulint seg_inode_len_free;
3749  ulint seg_inode_len_full;
3750 
3751  latch = fil_space_get_latch(space, &flags);
3752  zip_size = fsp_flags_get_zip_size(flags);
3753  ut_a(ut_is_2pow(zip_size));
3754  ut_a(zip_size <= UNIV_ZIP_SIZE_MAX);
3755  ut_a(!zip_size || zip_size >= UNIV_ZIP_SIZE_MIN);
3756 
3757  /* Start first a mini-transaction mtr2 to lock out all other threads
3758  from the fsp system */
3759  mtr_start(&mtr2);
3760  mtr_x_lock(latch, &mtr2);
3761 
3762  mtr_start(&mtr);
3763  mtr_x_lock(latch, &mtr);
3764 
3765  header = fsp_get_space_header(space, zip_size, &mtr);
3766 
3767  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3768  free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3769  MLOG_4BYTES, &mtr);
3770  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3771  MLOG_4BYTES, &mtr);
3772 
3773  n_full_frag_pages = FSP_EXTENT_SIZE
3774  * flst_get_len(header + FSP_FULL_FRAG, &mtr);
3775 
3776  if (UNIV_UNLIKELY(free_limit > size)) {
3777 
3778  ut_a(space != 0);
3779  ut_a(size < FSP_EXTENT_SIZE);
3780  }
3781 
3782  flst_validate(header + FSP_FREE, &mtr);
3783  flst_validate(header + FSP_FREE_FRAG, &mtr);
3784  flst_validate(header + FSP_FULL_FRAG, &mtr);
3785 
3786  mtr_commit(&mtr);
3787 
3788  /* Validate FSP_FREE list */
3789  mtr_start(&mtr);
3790  mtr_x_lock(latch, &mtr);
3791 
3792  header = fsp_get_space_header(space, zip_size, &mtr);
3793  node_addr = flst_get_first(header + FSP_FREE, &mtr);
3794 
3795  mtr_commit(&mtr);
3796 
3797  while (!fil_addr_is_null(node_addr)) {
3798  mtr_start(&mtr);
3799  mtr_x_lock(latch, &mtr);
3800 
3801  descr_count++;
3802  descr = xdes_lst_get_descriptor(space, zip_size,
3803  node_addr, &mtr);
3804 
3805  ut_a(xdes_get_n_used(descr, &mtr) == 0);
3806  ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3807 
3808  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3809  mtr_commit(&mtr);
3810  }
3811 
3812  /* Validate FSP_FREE_FRAG list */
3813  mtr_start(&mtr);
3814  mtr_x_lock(latch, &mtr);
3815 
3816  header = fsp_get_space_header(space, zip_size, &mtr);
3817  node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
3818 
3819  mtr_commit(&mtr);
3820 
3821  while (!fil_addr_is_null(node_addr)) {
3822  mtr_start(&mtr);
3823  mtr_x_lock(latch, &mtr);
3824 
3825  descr_count++;
3826  descr = xdes_lst_get_descriptor(space, zip_size,
3827  node_addr, &mtr);
3828 
3829  ut_a(xdes_get_n_used(descr, &mtr) > 0);
3830  ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3831  ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
3832 
3833  n_used += xdes_get_n_used(descr, &mtr);
3834  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3835 
3836  mtr_commit(&mtr);
3837  }
3838 
3839  /* Validate FSP_FULL_FRAG list */
3840  mtr_start(&mtr);
3841  mtr_x_lock(latch, &mtr);
3842 
3843  header = fsp_get_space_header(space, zip_size, &mtr);
3844  node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
3845 
3846  mtr_commit(&mtr);
3847 
3848  while (!fil_addr_is_null(node_addr)) {
3849  mtr_start(&mtr);
3850  mtr_x_lock(latch, &mtr);
3851 
3852  descr_count++;
3853  descr = xdes_lst_get_descriptor(space, zip_size,
3854  node_addr, &mtr);
3855 
3856  ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3857  ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
3858 
3859  node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3860  mtr_commit(&mtr);
3861  }
3862 
3863  /* Validate segments */
3864  mtr_start(&mtr);
3865  mtr_x_lock(latch, &mtr);
3866 
3867  header = fsp_get_space_header(space, zip_size, &mtr);
3868 
3869  node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
3870 
3871  seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
3872 
3873  mtr_commit(&mtr);
3874 
3875  while (!fil_addr_is_null(node_addr)) {
3876 
3877  n = 0;
3878  do {
3879  mtr_start(&mtr);
3880  mtr_x_lock(latch, &mtr);
3881 
3882  seg_inode_page = fut_get_ptr(
3883  space, zip_size, node_addr, RW_X_LATCH, &mtr)
3884  - FSEG_INODE_PAGE_NODE;
3885 
3886  seg_inode = fsp_seg_inode_page_get_nth_inode(
3887  seg_inode_page, n, zip_size, &mtr);
3888  ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
3889  fseg_validate_low(seg_inode, &mtr);
3890 
3891  descr_count += flst_get_len(seg_inode + FSEG_FREE,
3892  &mtr);
3893  descr_count += flst_get_len(seg_inode + FSEG_FULL,
3894  &mtr);
3895  descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
3896  &mtr);
3897 
3898  n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
3899 
3900  next_node_addr = flst_get_next_addr(
3901  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
3902  mtr_commit(&mtr);
3903  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
3904 
3905  node_addr = next_node_addr;
3906  }
3907 
3908  mtr_start(&mtr);
3909  mtr_x_lock(latch, &mtr);
3910 
3911  header = fsp_get_space_header(space, zip_size, &mtr);
3912 
3913  node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
3914 
3915  seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
3916 
3917  mtr_commit(&mtr);
3918 
3919  while (!fil_addr_is_null(node_addr)) {
3920 
3921  n = 0;
3922 
3923  do {
3924  mtr_start(&mtr);
3925  mtr_x_lock(latch, &mtr);
3926 
3927  seg_inode_page = fut_get_ptr(
3928  space, zip_size, node_addr, RW_X_LATCH, &mtr)
3929  - FSEG_INODE_PAGE_NODE;
3930 
3931  seg_inode = fsp_seg_inode_page_get_nth_inode(
3932  seg_inode_page, n, zip_size, &mtr);
3933  if (mach_read_from_8(seg_inode + FSEG_ID)) {
3934  fseg_validate_low(seg_inode, &mtr);
3935 
3936  descr_count += flst_get_len(
3937  seg_inode + FSEG_FREE, &mtr);
3938  descr_count += flst_get_len(
3939  seg_inode + FSEG_FULL, &mtr);
3940  descr_count += flst_get_len(
3941  seg_inode + FSEG_NOT_FULL, &mtr);
3942  n_used2 += fseg_get_n_frag_pages(
3943  seg_inode, &mtr);
3944  }
3945 
3946  next_node_addr = flst_get_next_addr(
3947  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
3948  mtr_commit(&mtr);
3949  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
3950 
3951  node_addr = next_node_addr;
3952  }
3953 
3954  ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
3955  if (!zip_size) {
3956  ut_a(n_used + n_full_frag_pages
3957  == n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
3958  / UNIV_PAGE_SIZE)
3959  + seg_inode_len_full + seg_inode_len_free);
3960  } else {
3961  ut_a(n_used + n_full_frag_pages
3962  == n_used2 + 2 * ((free_limit + (zip_size - 1))
3963  / zip_size)
3964  + seg_inode_len_full + seg_inode_len_free);
3965  }
3966  ut_a(frag_n_used == n_used);
3967 
3968  mtr_commit(&mtr2);
3969 
3970  return(TRUE);
3971 }
3972 
3973 /*******************************************************************/
3975 UNIV_INTERN
3976 void
3977 fsp_print(
3978 /*======*/
3979  ulint space)
3980 {
3981  fsp_header_t* header;
3982  fseg_inode_t* seg_inode;
3983  page_t* seg_inode_page;
3984  rw_lock_t* latch;
3985  ulint flags;
3986  ulint zip_size;
3987  ulint size;
3988  ulint free_limit;
3989  ulint frag_n_used;
3990  fil_addr_t node_addr;
3991  fil_addr_t next_node_addr;
3992  ulint n_free;
3993  ulint n_free_frag;
3994  ulint n_full_frag;
3995  ib_id_t seg_id;
3996  ulint n;
3997  ulint n_segs = 0;
3998  mtr_t mtr;
3999  mtr_t mtr2;
4000 
4001  latch = fil_space_get_latch(space, &flags);
4002  zip_size = fsp_flags_get_zip_size(flags);
4003 
4004  /* Start first a mini-transaction mtr2 to lock out all other threads
4005  from the fsp system */
4006 
4007  mtr_start(&mtr2);
4008 
4009  mtr_x_lock(latch, &mtr2);
4010 
4011  mtr_start(&mtr);
4012 
4013  mtr_x_lock(latch, &mtr);
4014 
4015  header = fsp_get_space_header(space, zip_size, &mtr);
4016 
4017  size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4018 
4019  free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4020  &mtr);
4021  frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4022  &mtr);
4023  n_free = flst_get_len(header + FSP_FREE, &mtr);
4024  n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4025  n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4026 
4027  seg_id = mach_read_from_8(header + FSP_SEG_ID);
4028 
4029  fprintf(stderr,
4030  "FILE SPACE INFO: id %lu\n"
4031  "size %lu, free limit %lu, free extents %lu\n"
4032  "not full frag extents %lu: used pages %lu,"
4033  " full frag extents %lu\n"
4034  "first seg id not used %llu\n",
4035  (ulong) space,
4036  (ulong) size, (ulong) free_limit, (ulong) n_free,
4037  (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4038  (ullint) seg_id);
4039 
4040  mtr_commit(&mtr);
4041 
4042  /* Print segments */
4043 
4044  mtr_start(&mtr);
4045  mtr_x_lock(latch, &mtr);
4046 
4047  header = fsp_get_space_header(space, zip_size, &mtr);
4048 
4049  node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4050 
4051  mtr_commit(&mtr);
4052 
4053  while (!fil_addr_is_null(node_addr)) {
4054 
4055  n = 0;
4056 
4057  do {
4058 
4059  mtr_start(&mtr);
4060  mtr_x_lock(latch, &mtr);
4061 
4062  seg_inode_page = fut_get_ptr(
4063  space, zip_size, node_addr, RW_X_LATCH, &mtr)
4064  - FSEG_INODE_PAGE_NODE;
4065 
4066  seg_inode = fsp_seg_inode_page_get_nth_inode(
4067  seg_inode_page, n, zip_size, &mtr);
4068  ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4069  fseg_print_low(seg_inode, &mtr);
4070 
4071  n_segs++;
4072 
4073  next_node_addr = flst_get_next_addr(
4074  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4075  mtr_commit(&mtr);
4076  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4077 
4078  node_addr = next_node_addr;
4079  }
4080 
4081  mtr_start(&mtr);
4082  mtr_x_lock(latch, &mtr);
4083 
4084  header = fsp_get_space_header(space, zip_size, &mtr);
4085 
4086  node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4087 
4088  mtr_commit(&mtr);
4089 
4090  while (!fil_addr_is_null(node_addr)) {
4091 
4092  n = 0;
4093 
4094  do {
4095 
4096  mtr_start(&mtr);
4097  mtr_x_lock(latch, &mtr);
4098 
4099  seg_inode_page = fut_get_ptr(
4100  space, zip_size, node_addr, RW_X_LATCH, &mtr)
4101  - FSEG_INODE_PAGE_NODE;
4102 
4103  seg_inode = fsp_seg_inode_page_get_nth_inode(
4104  seg_inode_page, n, zip_size, &mtr);
4105  if (mach_read_from_8(seg_inode + FSEG_ID)) {
4106 
4107  fseg_print_low(seg_inode, &mtr);
4108  n_segs++;
4109  }
4110 
4111  next_node_addr = flst_get_next_addr(
4112  seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4113  mtr_commit(&mtr);
4114  } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4115 
4116  node_addr = next_node_addr;
4117  }
4118 
4119  mtr_commit(&mtr2);
4120 
4121  fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
4122 }
4123 #endif /* !UNIV_HOTBACKUP */