1
/**********************************************************************
6
Created 11/29/1995 Heikki Tuuri
7
***********************************************************************/
17
#include "sync0sync.h"
23
#include "ibuf0ibuf.h"
26
#include "dict0boot.h"
31
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
34
/* The data structures in files are defined just as byte strings in C */
35
typedef byte fsp_header_t;
41
File space header data structure: this data structure is contained in the
42
first page of a space. The space for this header is reserved in every extent
43
descriptor page, but used only in the first. */
45
/*-------------------------------------*/
46
#define FSP_SPACE_ID 0 /* space id */
47
#define FSP_NOT_USED 4 /* this field contained a value up to
48
which we know that the modifications
49
in the database have been flushed to
50
the file space; not used now */
51
#define FSP_SIZE 8 /* Current size of the space in
53
#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
54
free list has not been initialized:
55
the pages >= this limit are, by
56
definition, free; note that in a
57
single-table tablespace where size
58
< 64 pages, this number is 64, i.e.,
59
we have initialized the space
60
about the first extent, but have not
61
physically allocted those pages to the
63
#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */
64
#define FSP_FRAG_N_USED 20 /* number of used pages in the
66
#define FSP_FREE 24 /* list of free extents */
67
#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
68
/* list of partially free extents not
69
belonging to any segment */
70
#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
71
/* list of full extents not belonging
73
#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
74
/* 8 bytes which give the first unused
76
#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
77
/* list of pages containing segment
78
headers, where all the segment inode
80
#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
81
/* list of pages containing segment
82
headers, where not all the segment
83
header slots are reserved */
84
/*-------------------------------------*/
85
/* File space header size */
86
#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
88
#define FSP_FREE_ADD 4 /* this many free extents are added
89
to the free list from above
90
FSP_FREE_LIMIT at a time */
95
Segment inode which is created for each segment in a tablespace. NOTE: in
96
purge we assume that a segment having only one currently used page can be
97
freed in a few steps, so that the freeing cannot fill the file buffer with
98
bufferfixed file pages. */
100
typedef byte fseg_inode_t;
102
#define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
103
/* the list node for linking
104
segment inode pages */
106
#define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
107
/*-------------------------------------*/
108
#define FSEG_ID 0 /* 8 bytes of segment id: if this is
109
ut_dulint_zero, it means that the
111
#define FSEG_NOT_FULL_N_USED 8
112
/* number of used segment pages in
113
the FSEG_NOT_FULL list */
115
/* list of free extents of this
117
#define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
118
/* list of partially free extents */
119
#define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
120
/* list of full extents */
121
#define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
122
/* magic number used in debugging */
123
#define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
124
/* array of individual pages
125
belonging to this segment in fsp
126
fragment extent lists */
127
#define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
128
/* number of slots in the array for
129
the fragment pages */
130
#define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
131
page number within space, FIL_NULL
132
means that the slot is not in use */
133
/*-------------------------------------*/
134
#define FSEG_INODE_SIZE \
135
(16 + 3 * FLST_BASE_NODE_SIZE \
136
+ FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
138
#define FSP_SEG_INODES_PER_PAGE(zip_size) \
139
(((zip_size ? zip_size : UNIV_PAGE_SIZE) \
140
- FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
141
/* Number of segment inodes which fit on a
144
#define FSEG_MAGIC_N_VALUE 97937874
146
#define FSEG_FILLFACTOR 8 /* If this value is x, then if
147
the number of unused but reserved
148
pages in a segment is less than
149
reserved pages * 1/x, and there are
150
at least FSEG_FRAG_LIMIT used pages,
151
then we allow a new empty extent to
152
be added to the segment in
153
fseg_alloc_free_page. Otherwise, we
154
use unused pages of the segment. */
156
#define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
157
/* If the segment has >= this many
158
used pages, it may be expanded by
159
allocating extents to the segment;
160
until that only individual fragment
161
pages are allocated from the space */
163
#define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
164
is at least this many extents, we
165
allow extents to be put to the free
166
list of the extent: at most
167
FSEG_FREE_LIST_MAX_LEN many */
168
#define FSEG_FREE_LIST_MAX_LEN 4
174
File extent descriptor data structure: contains bits to tell which pages in
175
the extent are free and which contain old tuple version to clean. */
177
/*-------------------------------------*/
178
#define XDES_ID 0 /* The identifier of the segment
179
to which this extent belongs */
180
#define XDES_FLST_NODE 8 /* The list node data structure
181
for the descriptors */
182
#define XDES_STATE (FLST_NODE_SIZE + 8)
183
/* contains state information
185
#define XDES_BITMAP (FLST_NODE_SIZE + 12)
186
/* Descriptor bitmap of the pages
188
/*-------------------------------------*/
190
#define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
191
#define XDES_FREE_BIT 0 /* Index of the bit which tells if
193
#define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
194
Index of the bit which tells if
195
there are old versions of tuples
197
/* States of a descriptor */
198
#define XDES_FREE 1 /* extent is in free list of space */
199
#define XDES_FREE_FRAG 2 /* extent is in free fragment list of
201
#define XDES_FULL_FRAG 3 /* extent is in full fragment list of
203
#define XDES_FSEG 4 /* extent belongs to a segment */
205
/* File extent data structure size in bytes. */
207
(XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
209
/* Offset of the descriptor array on a descriptor page */
210
#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
212
/**************************************************************************
213
Returns an extent to the free list of a space. */
218
ulint space, /* in: space id */
219
ulint zip_size,/* in: compressed page size in bytes
220
or 0 for uncompressed pages */
221
ulint page, /* in: page offset in the extent */
222
mtr_t* mtr); /* in: mtr */
223
/**************************************************************************
224
Frees an extent of a segment to the space free list. */
229
fseg_inode_t* seg_inode, /* in: segment inode */
230
ulint space, /* in: space id */
231
ulint zip_size,/* in: compressed page size in bytes
232
or 0 for uncompressed pages */
233
ulint page, /* in: page offset in the extent */
234
mtr_t* mtr); /* in: mtr handle */
235
/**************************************************************************
236
Calculates the number of pages reserved by a segment, and how
237
many pages are currently used. */
240
fseg_n_reserved_pages_low(
241
/*======================*/
242
/* out: number of reserved pages */
243
fseg_inode_t* header, /* in: segment inode */
244
ulint* used, /* out: number of pages used (<= reserved) */
245
mtr_t* mtr); /* in: mtr handle */
246
/************************************************************************
247
Marks a page used. The page must reside within the extents of the given
253
fseg_inode_t* seg_inode,/* in: segment inode */
254
ulint space, /* in: space id */
255
ulint zip_size,/* in: compressed page size in bytes
256
or 0 for uncompressed pages */
257
ulint page, /* in: page offset */
258
mtr_t* mtr); /* in: mtr */
259
/**************************************************************************
260
Returns the first extent descriptor for a segment. We think of the extent
261
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
265
fseg_get_first_extent(
266
/*==================*/
267
/* out: the first extent descriptor, or NULL if
269
fseg_inode_t* inode, /* in: segment inode */
270
ulint space, /* in: space id */
271
ulint zip_size,/* in: compressed page size in bytes
272
or 0 for uncompressed pages */
273
mtr_t* mtr); /* in: mtr */
274
/**************************************************************************
275
Puts new extents to the free list if
276
there are free extents above the free limit. If an extent happens
277
to contain an extent descriptor page, the extent is put to
278
the FSP_FREE_FRAG list with the page marked as used. */
283
ibool init_space, /* in: TRUE if this is a single-table
284
tablespace and we are only initing
285
the tablespace's first extent
286
descriptor page and ibuf bitmap page;
287
then we do not allocate more extents */
288
ulint space, /* in: space */
289
fsp_header_t* header, /* in: space header */
290
mtr_t* mtr); /* in: mtr */
291
/**************************************************************************
292
Allocates a single free page from a segment. This function implements
293
the intelligent allocation strategy which tries to minimize file space
297
fseg_alloc_free_page_low(
298
/*=====================*/
299
/* out: the allocated page number, FIL_NULL
300
if no page could be allocated */
301
ulint space, /* in: space */
302
ulint zip_size,/* in: compressed page size in bytes
303
or 0 for uncompressed pages */
304
fseg_inode_t* seg_inode, /* in: segment inode */
305
ulint hint, /* in: hint of which page would be desirable */
306
byte direction, /* in: if the new page is needed because
307
of an index page split, and records are
308
inserted there in order, into which
309
direction they go alphabetically: FSP_DOWN,
310
FSP_UP, FSP_NO_DIR */
311
mtr_t* mtr); /* in: mtr handle */
314
/**************************************************************************
315
Reads the file space size stored in the header page. */
320
/* out: tablespace size stored in the space header */
321
page_t* page) /* in: header page (page 0 in the tablespace) */
323
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
326
/**************************************************************************
327
Gets a pointer to the space header and x-locks its page. */
330
fsp_get_space_header(
331
/*=================*/
332
/* out: pointer to the space header, page x-locked */
333
ulint id, /* in: space id */
334
ulint zip_size,/* in: compressed page size in bytes
335
or 0 for uncompressed pages */
336
mtr_t* mtr) /* in: mtr */
339
fsp_header_t* header;
341
ut_ad(ut_is_2pow(zip_size));
342
ut_ad(zip_size <= UNIV_PAGE_SIZE);
343
ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
344
ut_ad(id || !zip_size);
346
block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
347
header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
348
#ifdef UNIV_SYNC_DEBUG
349
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
350
#endif /* UNIV_SYNC_DEBUG */
351
ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
352
ut_ad(zip_size == dict_table_flags_to_zip_size(
353
mach_read_from_4(FSP_SPACE_FLAGS + header)));
357
/**************************************************************************
358
Gets a descriptor bit of a page. */
363
/* out: TRUE if free */
364
xdes_t* descr, /* in: descriptor */
365
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
366
ulint offset, /* in: page offset within extent:
367
0 ... FSP_EXTENT_SIZE - 1 */
368
mtr_t* mtr) /* in: mtr */
374
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
375
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
376
ut_ad(offset < FSP_EXTENT_SIZE);
378
index = bit + XDES_BITS_PER_PAGE * offset;
380
byte_index = index / 8;
381
bit_index = index % 8;
383
return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
388
/**************************************************************************
389
Sets a descriptor bit of a page. */
394
xdes_t* descr, /* in: descriptor */
395
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
396
ulint offset, /* in: page offset within extent:
397
0 ... FSP_EXTENT_SIZE - 1 */
398
ibool val, /* in: bit value */
399
mtr_t* mtr) /* in: mtr */
406
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
407
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
408
ut_ad(offset < FSP_EXTENT_SIZE);
410
index = bit + XDES_BITS_PER_PAGE * offset;
412
byte_index = index / 8;
413
bit_index = index % 8;
415
descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
417
descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
419
mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
423
/**************************************************************************
424
Looks for a descriptor bit having the desired value. Starts from hint
425
and scans upward; at the end of the extent the search is wrapped to
426
the start of the extent. */
431
/* out: bit index of the bit, ULINT_UNDEFINED if not
433
xdes_t* descr, /* in: descriptor */
434
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
435
ibool val, /* in: desired bit value */
436
ulint hint, /* in: hint of which bit position would be desirable */
437
mtr_t* mtr) /* in: mtr */
443
ut_ad(hint < FSP_EXTENT_SIZE);
444
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
445
for (i = hint; i < FSP_EXTENT_SIZE; i++) {
446
if (val == xdes_get_bit(descr, bit, i, mtr)) {
452
for (i = 0; i < hint; i++) {
453
if (val == xdes_get_bit(descr, bit, i, mtr)) {
459
return(ULINT_UNDEFINED);
462
/**************************************************************************
463
Looks for a descriptor bit having the desired value. Scans the extent in
464
a direction opposite to xdes_find_bit. */
467
xdes_find_bit_downward(
468
/*===================*/
469
/* out: bit index of the bit, ULINT_UNDEFINED if not
471
xdes_t* descr, /* in: descriptor */
472
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
473
ibool val, /* in: desired bit value */
474
ulint hint, /* in: hint of which bit position would be desirable */
475
mtr_t* mtr) /* in: mtr */
481
ut_ad(hint < FSP_EXTENT_SIZE);
482
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
483
for (i = hint + 1; i > 0; i--) {
484
if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
490
for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
491
if (val == xdes_get_bit(descr, bit, i, mtr)) {
497
return(ULINT_UNDEFINED);
500
/**************************************************************************
501
Returns the number of used pages in a descriptor. */
506
/* out: number of pages used */
507
xdes_t* descr, /* in: descriptor */
508
mtr_t* mtr) /* in: mtr */
514
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
515
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
516
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
524
/**************************************************************************
525
Returns true if extent contains no used pages. */
530
/* out: TRUE if totally free */
531
xdes_t* descr, /* in: descriptor */
532
mtr_t* mtr) /* in: mtr */
534
if (0 == xdes_get_n_used(descr, mtr)) {
542
/**************************************************************************
543
Returns true if extent contains no free pages. */
548
/* out: TRUE if full */
549
xdes_t* descr, /* in: descriptor */
550
mtr_t* mtr) /* in: mtr */
552
if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
560
/**************************************************************************
561
Sets the state of an xdes. */
566
xdes_t* descr, /* in: descriptor */
567
ulint state, /* in: state to set */
568
mtr_t* mtr) /* in: mtr handle */
571
ut_ad(state >= XDES_FREE);
572
ut_ad(state <= XDES_FSEG);
573
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
575
mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
578
/**************************************************************************
579
Gets the state of an xdes. */
585
xdes_t* descr, /* in: descriptor */
586
mtr_t* mtr) /* in: mtr handle */
591
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
593
state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
594
ut_ad(state - 1 < XDES_FSEG);
598
/**************************************************************************
599
Inits an extent descriptor to the free and clean state. */
604
xdes_t* descr, /* in: descriptor */
605
mtr_t* mtr) /* in: mtr */
610
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
611
ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
613
for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
614
mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
617
xdes_set_state(descr, XDES_FREE, mtr);
620
/************************************************************************
621
Calculates the page where the descriptor of a page resides. */
624
xdes_calc_descriptor_page(
625
/*======================*/
626
/* out: descriptor page offset */
627
ulint zip_size, /* in: compressed page size in bytes;
628
0 for uncompressed pages */
629
ulint offset) /* in: page offset */
631
#if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
632
+ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
635
#if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
636
+ (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
639
ut_ad(ut_is_2pow(zip_size));
642
return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
644
ut_ad(zip_size > XDES_ARR_OFFSET
645
+ (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
646
return(ut_2pow_round(offset, zip_size));
650
/************************************************************************
651
Calculates the descriptor index within a descriptor page. */
654
xdes_calc_descriptor_index(
655
/*=======================*/
656
/* out: descriptor index */
657
ulint zip_size, /* in: compressed page size in bytes;
658
0 for uncompressed pages */
659
ulint offset) /* in: page offset */
661
ut_ad(ut_is_2pow(zip_size));
664
return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
667
return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
671
/************************************************************************
672
Gets pointer to a the extent descriptor of a page. The page where the extent
673
descriptor resides is x-locked. If the page offset is equal to the free limit
674
of the space, adds new extents from above the free limit to the space free
675
list, if not free limit == space size. This adding is necessary to make the
676
descriptor defined, as they are uninitialized above the free limit. */
679
xdes_get_descriptor_with_space_hdr(
680
/*===============================*/
681
/* out: pointer to the extent descriptor,
682
NULL if the page does not exist in the
683
space or if offset > free limit */
684
fsp_header_t* sp_header,/* in: space header, x-latched */
685
ulint space, /* in: space id */
686
ulint offset, /* in: page offset;
687
if equal to the free limit,
688
we try to add new extents to
689
the space free list */
690
mtr_t* mtr) /* in: mtr handle */
699
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
701
ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
702
|| mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
703
/* Read free limit and space size */
704
limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
705
size = mach_read_from_4(sp_header + FSP_SIZE);
706
zip_size = dict_table_flags_to_zip_size(
707
mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
709
/* If offset is >= size or > limit, return NULL */
711
if ((offset >= size) || (offset > limit)) {
716
/* If offset is == limit, fill free list of the space. */
718
if (offset == limit) {
719
fsp_fill_free_list(FALSE, space, sp_header, mtr);
722
descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
724
if (descr_page_no == 0) {
725
/* It is on the space header page */
727
descr_page = page_align(sp_header);
731
block = buf_page_get(space, zip_size, descr_page_no,
733
#ifdef UNIV_SYNC_DEBUG
734
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
735
#endif /* UNIV_SYNC_DEBUG */
736
descr_page = buf_block_get_frame(block);
739
return(descr_page + XDES_ARR_OFFSET
740
+ XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
743
/************************************************************************
744
Gets pointer to a the extent descriptor of a page. The page where the
745
extent descriptor resides is x-locked. If the page offset is equal to
746
the free limit of the space, adds new extents from above the free limit
747
to the space free list, if not free limit == space size. This adding
748
is necessary to make the descriptor defined, as they are uninitialized
749
above the free limit. */
754
/* out: pointer to the extent descriptor, NULL if the
755
page does not exist in the space or if offset > free
757
ulint space, /* in: space id */
758
ulint zip_size,/* in: compressed page size in bytes
759
or 0 for uncompressed pages */
760
ulint offset, /* in: page offset; if equal to the free limit,
761
we try to add new extents to the space free list */
762
mtr_t* mtr) /* in: mtr handle */
765
fsp_header_t* sp_header;
767
block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
768
#ifdef UNIV_SYNC_DEBUG
769
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
770
#endif /* UNIV_SYNC_DEBUG */
771
sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
772
return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
776
/************************************************************************
777
Gets pointer to a the extent descriptor if the file address
778
of the descriptor list node is known. The page where the
779
extent descriptor resides is x-locked. */
782
xdes_lst_get_descriptor(
783
/*====================*/
784
/* out: pointer to the extent descriptor */
785
ulint space, /* in: space id */
786
ulint zip_size,/* in: compressed page size in bytes
787
or 0 for uncompressed pages */
788
fil_addr_t lst_node,/* in: file address of the list node
789
contained in the descriptor */
790
mtr_t* mtr) /* in: mtr handle */
795
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
797
descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
803
/************************************************************************
804
Returns page offset of the first page in extent described by a descriptor. */
809
/* out: offset of the first page in extent */
810
xdes_t* descr) /* in: extent descriptor */
814
return(page_get_page_no(page_align(descr))
815
+ ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
819
/***************************************************************
820
Inits a file page whose prior contents should be ignored. */
823
fsp_init_file_page_low(
824
/*===================*/
825
buf_block_t* block) /* in: pointer to a page */
827
page_t* page = buf_block_get_frame(block);
828
page_zip_des_t* page_zip= buf_block_get_page_zip(block);
830
block->check_index_page_at_flush = FALSE;
832
if (UNIV_LIKELY_NULL(page_zip)) {
833
memset(page, 0, UNIV_PAGE_SIZE);
834
memset(page_zip->data, 0, page_zip_get_size(page_zip));
835
mach_write_to_4(page + FIL_PAGE_OFFSET,
836
buf_block_get_page_no(block));
838
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
839
buf_block_get_space(block));
840
memcpy(page_zip->data + FIL_PAGE_OFFSET,
841
page + FIL_PAGE_OFFSET, 4);
842
memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
843
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
847
#ifdef UNIV_BASIC_LOG_DEBUG
848
memset(page, 0xff, UNIV_PAGE_SIZE);
850
mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
851
memset(page + FIL_PAGE_LSN, 0, 8);
852
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
853
buf_block_get_space(block));
854
memset(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, 0, 8);
857
/***************************************************************
858
Inits a file page whose prior contents should be ignored. */
863
buf_block_t* block, /* in: pointer to a page */
864
mtr_t* mtr) /* in: mtr */
866
fsp_init_file_page_low(block);
868
mlog_write_initial_log_record(buf_block_get_frame(block),
869
MLOG_INIT_FILE_PAGE, mtr);
872
/***************************************************************
873
Parses a redo log record of a file page init. */
876
fsp_parse_init_file_page(
877
/*=====================*/
878
/* out: end of log record or NULL */
879
byte* ptr, /* in: buffer */
880
byte* end_ptr __attribute__((unused)), /* in: buffer end */
881
buf_block_t* block) /* in: block or NULL */
883
ut_ad(ptr && end_ptr);
886
fsp_init_file_page_low(block);
892
/**************************************************************************
893
Initializes the fsp system. */
899
/* Does nothing at the moment */
902
/**************************************************************************
903
Writes the space id and compressed page size to a tablespace header.
904
This function is used past the buffer pool when we in fil0fil.c create
905
a new single-table tablespace. */
908
fsp_header_init_fields(
909
/*===================*/
910
page_t* page, /* in/out: first page in the space */
911
ulint space_id, /* in: space id */
912
ulint flags) /* in: tablespace flags (FSP_SPACE_FLAGS):
913
0, or table->flags if newer than COMPACT */
915
/* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
916
ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
917
ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
918
format, the tablespace flags should equal table->flags. */
919
ut_a(flags != DICT_TF_COMPACT);
921
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
923
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
927
/**************************************************************************
928
Initializes the space header of a new created space and creates also the
929
insert buffer tree root if space == 0. */
934
ulint space, /* in: space id */
935
ulint size, /* in: current size in blocks */
936
mtr_t* mtr) /* in: mini-transaction handle */
938
fsp_header_t* header;
946
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
948
zip_size = dict_table_flags_to_zip_size(flags);
949
block = buf_page_create(space, 0, zip_size, mtr);
950
buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
951
#ifdef UNIV_SYNC_DEBUG
952
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
953
#endif /* UNIV_SYNC_DEBUG */
955
/* The prior contents of the file page should be ignored */
957
fsp_init_file_page(block, mtr);
958
page = buf_block_get_frame(block);
960
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
963
header = FSP_HEADER_OFFSET + page;
965
mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
966
mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
968
mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
969
mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
970
mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
972
mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
974
flst_init(header + FSP_FREE, mtr);
975
flst_init(header + FSP_FREE_FRAG, mtr);
976
flst_init(header + FSP_FULL_FRAG, mtr);
977
flst_init(header + FSP_SEG_INODES_FULL, mtr);
978
flst_init(header + FSP_SEG_INODES_FREE, mtr);
980
mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), mtr);
982
fsp_fill_free_list(FALSE, space, header, mtr);
983
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
984
0, 0, ut_dulint_add(DICT_IBUF_ID_MIN, space),
985
srv_sys->dummy_ind1, mtr);
987
fsp_fill_free_list(TRUE, space, header, mtr);
991
/**************************************************************************
992
Reads the space id from the first page of a tablespace. */
995
fsp_header_get_space_id(
996
/*====================*/
997
/* out: space id, ULINT UNDEFINED if error */
998
const page_t* page) /* in: first page of a tablespace */
1003
fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
1005
id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
1009
"InnoDB: Error: space id in fsp header %lu,"
1010
" but in the page header %lu\n",
1011
(ulong) fsp_id, (ulong) id);
1013
return(ULINT_UNDEFINED);
1019
/**************************************************************************
1020
Reads the space flags from the first page of a tablespace. */
1023
fsp_header_get_flags(
1024
/*=================*/
1026
const page_t* page) /* in: first page of a tablespace */
1028
ut_ad(!page_offset(page));
1030
return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
1033
/**************************************************************************
1034
Reads the compressed page size from the first page of a tablespace. */
1037
fsp_header_get_zip_size(
1038
/*====================*/
1039
/* out: compressed page size in bytes,
1040
or 0 if uncompressed */
1041
const page_t* page) /* in: first page of a tablespace */
1043
ulint flags = fsp_header_get_flags(page);
1045
return(dict_table_flags_to_zip_size(flags));
1048
/**************************************************************************
1049
Increases the space size field of a space. */
1052
fsp_header_inc_size(
1053
/*================*/
1054
ulint space, /* in: space id */
1055
ulint size_inc,/* in: size increment in pages */
1056
mtr_t* mtr) /* in: mini-transaction handle */
1058
fsp_header_t* header;
1064
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
1066
header = fsp_get_space_header(space,
1067
dict_table_flags_to_zip_size(flags),
1070
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1072
mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
1076
/**************************************************************************
1077
Gets the current free limit of the system tablespace. The free limit
1078
means the place of the first page which has never been put to the the
1079
free list for allocation. The space above that address is initialized
1080
to zero. Sets also the global variable log_fsp_current_free_limit. */
1083
fsp_header_get_free_limit(void)
1084
/*===========================*/
1085
/* out: free limit in megabytes */
1087
fsp_header_t* header;
1093
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1095
header = fsp_get_space_header(0, 0, &mtr);
1097
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1099
limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
1101
log_fsp_current_free_limit_set_and_checkpoint(limit);
1108
/**************************************************************************
1109
Gets the size of the system tablespace from the tablespace header. If
1110
we do not have an auto-extending data file, this should be equal to
1111
the size of the data files. If there is an auto-extending data file,
1112
this can be smaller. */
1115
fsp_header_get_tablespace_size(void)
1116
/*================================*/
1117
/* out: size in pages */
1119
fsp_header_t* header;
1125
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1127
header = fsp_get_space_header(0, 0, &mtr);
1129
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1136
/***************************************************************************
1137
Tries to extend a single-table tablespace so that a page would fit in the
1141
fsp_try_extend_data_file_with_pages(
1142
/*================================*/
1143
/* out: TRUE if success */
1144
ulint space, /* in: space */
1145
ulint page_no, /* in: page number */
1146
fsp_header_t* header, /* in: space header */
1147
mtr_t* mtr) /* in: mtr */
1155
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1157
ut_a(page_no >= size);
1159
success = fil_extend_space_to_desired_size(&actual_size, space,
1161
/* actual_size now has the space size in pages; it may be less than
1162
we wanted if we ran out of disk space */
1164
mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1169
/***************************************************************************
1170
Tries to extend the last data file of a tablespace if it is auto-extending. */
1173
fsp_try_extend_data_file(
1174
/*=====================*/
1175
/* out: FALSE if not auto-extending */
1176
ulint* actual_increase,/* out: actual increase in pages, where
1177
we measure the tablespace size from
1178
what the header field says; it may be
1179
the actual file size rounded down to
1181
ulint space, /* in: space */
1182
fsp_header_t* header, /* in: space header */
1183
mtr_t* mtr) /* in: mtr */
1189
ulint size_increase;
1193
*actual_increase = 0;
1195
if (space == 0 && !srv_auto_extend_last_data_file) {
1200
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1201
zip_size = dict_table_flags_to_zip_size(
1202
mach_read_from_4(header + FSP_SPACE_FLAGS));
1207
if (!srv_last_file_size_max) {
1208
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1210
if (srv_last_file_size_max
1211
< srv_data_file_sizes[srv_n_data_files - 1]) {
1214
"InnoDB: Error: Last data file size"
1215
" is %lu, max size allowed %lu\n",
1216
(ulong) srv_data_file_sizes[
1217
srv_n_data_files - 1],
1218
(ulong) srv_last_file_size_max);
1221
size_increase = srv_last_file_size_max
1222
- srv_data_file_sizes[srv_n_data_files - 1];
1223
if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1224
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1228
/* We extend single-table tablespaces first one extent
1229
at a time, but for bigger tablespaces more. It is not
1230
enough to extend always by one extent, because some
1231
extents are frag page extents. */
1232
ulint extent_size; /* one megabyte, in pages */
1235
extent_size = FSP_EXTENT_SIZE;
1237
extent_size = FSP_EXTENT_SIZE
1238
* UNIV_PAGE_SIZE / zip_size;
1241
if (size < extent_size) {
1242
/* Let us first extend the file to extent_size */
1243
success = fsp_try_extend_data_file_with_pages(
1244
space, extent_size - 1, header, mtr);
1246
new_size = mtr_read_ulint(header + FSP_SIZE,
1249
*actual_increase = new_size - old_size;
1257
if (size < 32 * extent_size) {
1258
size_increase = extent_size;
1260
/* Below in fsp_fill_free_list() we assume
1261
that we add at most FSP_FREE_ADD extents at
1263
size_increase = FSP_FREE_ADD * extent_size;
1267
if (size_increase == 0) {
1272
success = fil_extend_space_to_desired_size(&actual_size, space,
1273
size + size_increase);
1274
/* We ignore any fragments of a full megabyte when storing the size
1275
to the space header */
1278
new_size = ut_calc_align_down(actual_size,
1279
(1024 * 1024) / UNIV_PAGE_SIZE);
1281
new_size = ut_calc_align_down(actual_size,
1282
(1024 * 1024) / zip_size);
1284
mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1286
*actual_increase = new_size - old_size;
1291
/**************************************************************************
1292
Puts new extents to the free list if there are free extents above the free
1293
limit. If an extent happens to contain an extent descriptor page, the extent
1294
is put to the FSP_FREE_FRAG list with the page marked as used. */
1299
ibool init_space, /* in: TRUE if this is a single-table
1300
tablespace and we are only initing
1301
the tablespace's first extent
1302
descriptor page and ibuf bitmap page;
1303
then we do not allocate more extents */
1304
ulint space, /* in: space */
1305
fsp_header_t* header, /* in: space header */
1306
mtr_t* mtr) /* in: mtr */
1314
ulint actual_increase;
1318
ut_ad(header && mtr);
1320
/* Check if we can fill free list from above the free list limit */
1321
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1322
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1324
zip_size = dict_table_flags_to_zip_size(
1325
mach_read_from_4(FSP_SPACE_FLAGS + header));
1326
ut_a(ut_is_2pow(zip_size));
1327
ut_a(zip_size <= UNIV_PAGE_SIZE);
1328
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
1330
if (space == 0 && srv_auto_extend_last_data_file
1331
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1333
/* Try to increase the last data file size */
1334
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1335
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1338
if (space != 0 && !init_space
1339
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1341
/* Try to increase the .ibd file size */
1342
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1343
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1348
while ((init_space && i < 1)
1349
|| ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1353
init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1355
init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1358
mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1361
/* Update the free limit info in the log system and make
1365
log_fsp_current_free_limit_set_and_checkpoint(
1366
(i + FSP_EXTENT_SIZE)
1367
/ ((1024 * 1024) / UNIV_PAGE_SIZE));
1370
if (UNIV_UNLIKELY(init_xdes)) {
1374
/* We are going to initialize a new descriptor page
1375
and a new ibuf bitmap page: the prior contents of the
1376
pages should be ignored. */
1379
block = buf_page_create(
1380
space, i, zip_size, mtr);
1381
buf_page_get(space, zip_size, i,
1383
#ifdef UNIV_SYNC_DEBUG
1384
buf_block_dbg_add_level(block,
1386
#endif /* UNIV_SYNC_DEBUG */
1387
fsp_init_file_page(block, mtr);
1388
mlog_write_ulint(buf_block_get_frame(block)
1394
/* Initialize the ibuf bitmap page in a separate
1395
mini-transaction because it is low in the latching
1396
order, and we must be able to release its latch
1397
before returning from the fsp routine */
1399
mtr_start(&ibuf_mtr);
1401
block = buf_page_create(space,
1402
i + FSP_IBUF_BITMAP_OFFSET,
1403
zip_size, &ibuf_mtr);
1404
buf_page_get(space, zip_size,
1405
i + FSP_IBUF_BITMAP_OFFSET,
1406
RW_X_LATCH, &ibuf_mtr);
1407
#ifdef UNIV_SYNC_DEBUG
1408
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1409
#endif /* UNIV_SYNC_DEBUG */
1410
fsp_init_file_page(block, &ibuf_mtr);
1412
ibuf_bitmap_page_init(block, &ibuf_mtr);
1414
mtr_commit(&ibuf_mtr);
1417
descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1419
xdes_init(descr, mtr);
1421
#if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
1422
# error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
1424
#if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
1425
# error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
1428
if (UNIV_UNLIKELY(init_xdes)) {
1430
/* The first page in the extent is a descriptor page
1431
and the second is an ibuf bitmap page: mark them
1434
xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1435
xdes_set_bit(descr, XDES_FREE_BIT,
1436
FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1437
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1439
flst_add_last(header + FSP_FREE_FRAG,
1440
descr + XDES_FLST_NODE, mtr);
1441
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1443
mlog_write_ulint(header + FSP_FRAG_N_USED,
1444
frag_n_used + 2, MLOG_4BYTES, mtr);
1446
flst_add_last(header + FSP_FREE,
1447
descr + XDES_FLST_NODE, mtr);
1451
i += FSP_EXTENT_SIZE;
1455
/**************************************************************************
1456
Allocates a new free extent. */
1459
fsp_alloc_free_extent(
1460
/*==================*/
1461
/* out: extent descriptor, NULL if cannot be
1463
ulint space, /* in: space id */
1464
ulint zip_size,/* in: compressed page size in bytes
1465
or 0 for uncompressed pages */
1466
ulint hint, /* in: hint of which extent would be desirable: any
1467
page offset in the extent goes; the hint must not
1468
be > FSP_FREE_LIMIT */
1469
mtr_t* mtr) /* in: mtr */
1471
fsp_header_t* header;
1477
header = fsp_get_space_header(space, zip_size, mtr);
1479
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1481
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1482
/* Ok, we can take this extent */
1484
/* Take the first extent in the free list */
1485
first = flst_get_first(header + FSP_FREE, mtr);
1487
if (fil_addr_is_null(first)) {
1488
fsp_fill_free_list(FALSE, space, header, mtr);
1490
first = flst_get_first(header + FSP_FREE, mtr);
1493
if (fil_addr_is_null(first)) {
1495
return(NULL); /* No free extents left */
1498
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1501
flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1506
/**************************************************************************
1507
Allocates a single free page from a space. The page is marked as used. */
1510
fsp_alloc_free_page(
1511
/*================*/
1512
/* out: the page offset, FIL_NULL if no page could
1514
ulint space, /* in: space id */
1515
ulint zip_size,/* in: compressed page size in bytes
1516
or 0 for uncompressed pages */
1517
ulint hint, /* in: hint of which page would be desirable */
1518
mtr_t* mtr) /* in: mtr handle */
1520
fsp_header_t* header;
1532
header = fsp_get_space_header(space, zip_size, mtr);
1534
/* Get the hinted descriptor */
1535
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1537
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1538
/* Ok, we can take this extent */
1540
/* Else take the first extent in free_frag list */
1541
first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1543
if (fil_addr_is_null(first)) {
1544
/* There are no partially full fragments: allocate
1545
a free extent and add it to the FREE_FRAG list. NOTE
1546
that the allocation may have as a side-effect that an
1547
extent containing a descriptor page is added to the
1548
FREE_FRAG list. But we will allocate our page from the
1549
the free extent anyway. */
1551
descr = fsp_alloc_free_extent(space, zip_size,
1554
if (descr == NULL) {
1555
/* No free space left */
1560
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1561
flst_add_last(header + FSP_FREE_FRAG,
1562
descr + XDES_FLST_NODE, mtr);
1564
descr = xdes_lst_get_descriptor(space, zip_size,
1568
/* Reset the hint */
1572
/* Now we have in descr an extent with at least one free page. Look
1573
for a free page in the extent. */
1575
free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1576
hint % FSP_EXTENT_SIZE, mtr);
1577
if (free == ULINT_UNDEFINED) {
1579
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1584
page_no = xdes_get_offset(descr) + free;
1586
space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1588
if (space_size <= page_no) {
1589
/* It must be that we are extending a single-table tablespace
1590
whose size is still < 64 pages */
1593
if (page_no >= FSP_EXTENT_SIZE) {
1595
"InnoDB: Error: trying to extend a"
1596
" single-table tablespace %lu\n"
1597
"InnoDB: by single page(s) though the"
1598
" space size %lu. Page no %lu.\n",
1599
(ulong) space, (ulong) space_size,
1603
success = fsp_try_extend_data_file_with_pages(space, page_no,
1606
/* No disk space left */
1611
xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1613
/* Update the FRAG_N_USED field */
1614
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1617
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1619
if (xdes_is_full(descr, mtr)) {
1620
/* The fragment is full: move it to another list */
1621
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1623
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1625
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1627
mlog_write_ulint(header + FSP_FRAG_N_USED,
1628
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1632
/* Initialize the allocated page to the buffer pool, so that it can
1633
be obtained immediately with buf_page_get without need for a disk
1636
buf_page_create(space, page_no, zip_size, mtr);
1638
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1639
#ifdef UNIV_SYNC_DEBUG
1640
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1641
#endif /* UNIV_SYNC_DEBUG */
1643
/* Prior contents of the page should be ignored */
1644
fsp_init_file_page(block, mtr);
1649
/**************************************************************************
1650
Frees a single page of a space. The page is marked as free and clean. */
1655
ulint space, /* in: space id */
1656
ulint zip_size,/* in: compressed page size in bytes
1657
or 0 for uncompressed pages */
1658
ulint page, /* in: page offset */
1659
mtr_t* mtr) /* in: mtr handle */
1661
fsp_header_t* header;
1668
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1670
header = fsp_get_space_header(space, zip_size, mtr);
1672
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1674
state = xdes_get_state(descr, mtr);
1676
if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1678
"InnoDB: Error: File space extent descriptor"
1679
" of page %lu has state %lu\n",
1682
fputs("InnoDB: Dump of descriptor: ", stderr);
1683
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1686
if (state == XDES_FREE) {
1687
/* We put here some fault tolerance: if the page
1688
is already free, return without doing anything! */
1696
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1698
"InnoDB: Error: File space extent descriptor"
1699
" of page %lu says it is free\n"
1700
"InnoDB: Dump of descriptor: ", (ulong) page);
1701
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1704
/* We put here some fault tolerance: if the page
1705
is already free, return without doing anything! */
1710
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1711
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1713
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1715
if (state == XDES_FULL_FRAG) {
1716
/* The fragment was full: move it to another list */
1717
flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1719
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1720
flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1722
mlog_write_ulint(header + FSP_FRAG_N_USED,
1723
frag_n_used + FSP_EXTENT_SIZE - 1,
1726
ut_a(frag_n_used > 0);
1727
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1731
if (xdes_is_free(descr, mtr)) {
1732
/* The extent has become free: move it to another list */
1733
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1735
fsp_free_extent(space, zip_size, page, mtr);
1739
/**************************************************************************
1740
Returns an extent to the free list of a space. */
1745
ulint space, /* in: space id */
1746
ulint zip_size,/* in: compressed page size in bytes
1747
or 0 for uncompressed pages */
1748
ulint page, /* in: page offset in the extent */
1749
mtr_t* mtr) /* in: mtr */
1751
fsp_header_t* header;
1756
header = fsp_get_space_header(space, zip_size, mtr);
1758
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1760
if (xdes_get_state(descr, mtr) == XDES_FREE) {
1762
ut_print_buf(stderr, (byte*)descr - 500, 1000);
1767
xdes_init(descr, mtr);
1769
flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1772
/**************************************************************************
1773
Returns the nth inode slot on an inode page. */
1776
fsp_seg_inode_page_get_nth_inode(
1777
/*=============================*/
1778
/* out: segment inode */
1779
page_t* page, /* in: segment inode page */
1780
ulint i, /* in: inode index on page */
1781
ulint zip_size __attribute__((unused)),
1782
/* in: compressed page size, or 0 */
1783
mtr_t* mtr __attribute__((unused)))
1784
/* in: mini-transaction handle */
1786
ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1787
ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1789
return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1792
/**************************************************************************
1793
Looks for a used segment inode on a segment inode page. */
1796
fsp_seg_inode_page_find_used(
1797
/*=========================*/
1798
/* out: segment inode index, or ULINT_UNDEFINED
1800
page_t* page, /* in: segment inode page */
1801
ulint zip_size,/* in: compressed page size, or 0 */
1802
mtr_t* mtr) /* in: mini-transaction handle */
1805
fseg_inode_t* inode;
1807
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1809
inode = fsp_seg_inode_page_get_nth_inode(
1810
page, i, zip_size, mtr);
1812
if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
1819
return(ULINT_UNDEFINED);
1822
/**************************************************************************
1823
Looks for an unused segment inode on a segment inode page. */
1826
fsp_seg_inode_page_find_free(
1827
/*=========================*/
1828
/* out: segment inode index, or ULINT_UNDEFINED
1830
page_t* page, /* in: segment inode page */
1831
ulint i, /* in: search forward starting from this index */
1832
ulint zip_size,/* in: compressed page size, or 0 */
1833
mtr_t* mtr) /* in: mini-transaction handle */
1835
fseg_inode_t* inode;
1837
for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1839
inode = fsp_seg_inode_page_get_nth_inode(
1840
page, i, zip_size, mtr);
1842
if (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
1843
/* This is unused */
1849
return(ULINT_UNDEFINED);
1852
/**************************************************************************
1853
Allocates a new file segment inode page. */
1856
fsp_alloc_seg_inode_page(
1857
/*=====================*/
1858
/* out: TRUE if could be allocated */
1859
fsp_header_t* space_header, /* in: space header */
1860
mtr_t* mtr) /* in: mini-transaction handle */
1862
fseg_inode_t* inode;
1870
space = page_get_space_id(page_align(space_header));
1871
zip_size = dict_table_flags_to_zip_size(
1872
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1874
page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
1876
if (page_no == FIL_NULL) {
1881
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1882
#ifdef UNIV_SYNC_DEBUG
1883
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1884
#endif /* UNIV_SYNC_DEBUG */
1886
block->check_index_page_at_flush = FALSE;
1888
page = buf_block_get_frame(block);
1890
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
1893
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1895
inode = fsp_seg_inode_page_get_nth_inode(page, i,
1898
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
1901
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1902
page + FSEG_INODE_PAGE_NODE, mtr);
1906
/**************************************************************************
1907
Allocates a new file segment inode. */
1910
fsp_alloc_seg_inode(
1911
/*================*/
1912
/* out: segment inode, or NULL if
1914
fsp_header_t* space_header, /* in: space header */
1915
mtr_t* mtr) /* in: mini-transaction handle */
1920
fseg_inode_t* inode;
1925
if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1926
/* Allocate a new segment inode page */
1928
success = fsp_alloc_seg_inode_page(space_header, mtr);
1936
page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1938
zip_size = dict_table_flags_to_zip_size(
1939
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1940
block = buf_page_get(page_get_space_id(page_align(space_header)),
1941
zip_size, page_no, RW_X_LATCH, mtr);
1942
#ifdef UNIV_SYNC_DEBUG
1943
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1944
#endif /* UNIV_SYNC_DEBUG */
1945
page = buf_block_get_frame(block);
1947
n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1949
ut_a(n != ULINT_UNDEFINED);
1951
inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1953
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1955
/* There are no other unused headers left on the page: move it
1958
flst_remove(space_header + FSP_SEG_INODES_FREE,
1959
page + FSEG_INODE_PAGE_NODE, mtr);
1961
flst_add_last(space_header + FSP_SEG_INODES_FULL,
1962
page + FSEG_INODE_PAGE_NODE, mtr);
1968
/**************************************************************************
1969
Frees a file segment inode. */
1974
ulint space, /* in: space id */
1975
ulint zip_size,/* in: compressed page size in bytes
1976
or 0 for uncompressed pages */
1977
fseg_inode_t* inode, /* in: segment inode */
1978
mtr_t* mtr) /* in: mini-transaction handle */
1981
fsp_header_t* space_header;
1983
page = page_align(inode);
1985
space_header = fsp_get_space_header(space, zip_size, mtr);
1987
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1990
== fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
1992
/* Move the page to another list */
1994
flst_remove(space_header + FSP_SEG_INODES_FULL,
1995
page + FSEG_INODE_PAGE_NODE, mtr);
1997
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1998
page + FSEG_INODE_PAGE_NODE, mtr);
2001
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
2002
mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr);
2005
== fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
2007
/* There are no other used headers left on the page: free it */
2009
flst_remove(space_header + FSP_SEG_INODES_FREE,
2010
page + FSEG_INODE_PAGE_NODE, mtr);
2012
fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
2016
/**************************************************************************
2017
Returns the file segment inode, page x-latched. */
2022
/* out: segment inode, page x-latched */
2023
fseg_header_t* header, /* in: segment header */
2024
ulint space, /* in: space id */
2025
ulint zip_size,/* in: compressed page size in bytes
2026
or 0 for uncompressed pages */
2027
mtr_t* mtr) /* in: mtr handle */
2029
fil_addr_t inode_addr;
2030
fseg_inode_t* inode;
2032
inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
2033
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
2034
ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
2036
inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
2038
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2043
/**************************************************************************
2044
Gets the page number from the nth fragment page slot. */
2047
fseg_get_nth_frag_page_no(
2048
/*======================*/
2049
/* out: page number, FIL_NULL if not in use */
2050
fseg_inode_t* inode, /* in: segment inode */
2051
ulint n, /* in: slot index */
2052
mtr_t* mtr __attribute__((unused))) /* in: mtr handle */
2054
ut_ad(inode && mtr);
2055
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2056
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2057
return(mach_read_from_4(inode + FSEG_FRAG_ARR
2058
+ n * FSEG_FRAG_SLOT_SIZE));
2061
/**************************************************************************
2062
Sets the page number in the nth fragment page slot. */
2065
fseg_set_nth_frag_page_no(
2066
/*======================*/
2067
fseg_inode_t* inode, /* in: segment inode */
2068
ulint n, /* in: slot index */
2069
ulint page_no,/* in: page number to set */
2070
mtr_t* mtr) /* in: mtr handle */
2072
ut_ad(inode && mtr);
2073
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2074
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2076
mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
2077
page_no, MLOG_4BYTES, mtr);
2080
/**************************************************************************
2081
Finds a fragment page slot which is free. */
2084
fseg_find_free_frag_page_slot(
2085
/*==========================*/
2086
/* out: slot index; ULINT_UNDEFINED if none
2088
fseg_inode_t* inode, /* in: segment inode */
2089
mtr_t* mtr) /* in: mtr handle */
2094
ut_ad(inode && mtr);
2096
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2097
page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
2099
if (page_no == FIL_NULL) {
2105
return(ULINT_UNDEFINED);
2108
/**************************************************************************
2109
Finds a fragment page slot which is used and last in the array. */
2112
fseg_find_last_used_frag_page_slot(
2113
/*===============================*/
2114
/* out: slot index; ULINT_UNDEFINED if none
2116
fseg_inode_t* inode, /* in: segment inode */
2117
mtr_t* mtr) /* in: mtr handle */
2122
ut_ad(inode && mtr);
2124
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2125
page_no = fseg_get_nth_frag_page_no(
2126
inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
2128
if (page_no != FIL_NULL) {
2130
return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
2134
return(ULINT_UNDEFINED);
2137
/**************************************************************************
2138
Calculates reserved fragment page slots. */
2141
fseg_get_n_frag_pages(
2142
/*==================*/
2143
/* out: number of fragment pages */
2144
fseg_inode_t* inode, /* in: segment inode */
2145
mtr_t* mtr) /* in: mtr handle */
2150
ut_ad(inode && mtr);
2152
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2153
if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2161
/**************************************************************************
2162
Creates a new segment. */
2165
fseg_create_general(
2166
/*================*/
2167
/* out: the block where the segment header is placed,
2168
x-latched, NULL if could not create segment
2169
because of lack of space */
2170
ulint space, /* in: space id */
2171
ulint page, /* in: page where the segment header is placed: if
2172
this is != 0, the page must belong to another segment,
2173
if this is 0, a new page will be allocated and it
2174
will belong to the created segment */
2175
ulint byte_offset, /* in: byte offset of the created segment header
2177
ibool has_done_reservation, /* in: TRUE if the caller has already
2178
done the reservation for the pages with
2179
fsp_reserve_free_extents (at least 2 extents: one for
2180
the inode and the other for the segment) then there is
2181
no need to do the check for this individual
2183
mtr_t* mtr) /* in: mtr */
2187
fsp_header_t* space_header;
2188
fseg_inode_t* inode;
2190
buf_block_t* block = 0; /* remove warning */
2191
fseg_header_t* header = 0; /* remove warning */
2198
ut_ad(byte_offset + FSEG_HEADER_SIZE
2199
<= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2201
latch = fil_space_get_latch(space, &flags);
2202
zip_size = dict_table_flags_to_zip_size(flags);
2205
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2206
header = byte_offset + buf_block_get_frame(block);
2209
ut_ad(!mutex_own(&kernel_mutex)
2210
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2212
mtr_x_lock(latch, mtr);
2214
if (rw_lock_get_x_lock_count(latch) == 1) {
2215
/* This thread did not own the latch before this call: free
2216
excess pages from the insert buffer free list */
2219
ibuf_free_excess_pages(0);
2223
if (!has_done_reservation) {
2224
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2231
space_header = fsp_get_space_header(space, zip_size, mtr);
2233
inode = fsp_alloc_seg_inode(space_header, mtr);
2235
if (inode == NULL) {
2240
/* Read the next segment id from space header and increment the
2241
value in space header */
2243
seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, mtr);
2245
mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1),
2248
mlog_write_dulint(inode + FSEG_ID, seg_id, mtr);
2249
mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2251
flst_init(inode + FSEG_FREE, mtr);
2252
flst_init(inode + FSEG_NOT_FULL, mtr);
2253
flst_init(inode + FSEG_FULL, mtr);
2255
mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2257
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2258
fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2262
page = fseg_alloc_free_page_low(space, zip_size,
2263
inode, 0, FSP_UP, mtr);
2265
if (page == FIL_NULL) {
2267
fsp_free_seg_inode(space, zip_size, inode, mtr);
2272
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2273
header = byte_offset + buf_block_get_frame(block);
2274
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2275
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
2278
mlog_write_ulint(header + FSEG_HDR_OFFSET,
2279
page_offset(inode), MLOG_2BYTES, mtr);
2281
mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2282
page_get_page_no(page_align(inode)),
2285
mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2288
if (!has_done_reservation) {
2290
fil_space_release_free_extents(space, n_reserved);
2296
/**************************************************************************
2297
Creates a new segment. */
2302
/* out: the block where the segment header is placed,
2303
x-latched, NULL if could not create segment
2304
because of lack of space */
2305
ulint space, /* in: space id */
2306
ulint page, /* in: page where the segment header is placed: if
2307
this is != 0, the page must belong to another segment,
2308
if this is 0, a new page will be allocated and it
2309
will belong to the created segment */
2310
ulint byte_offset, /* in: byte offset of the created segment header
2312
mtr_t* mtr) /* in: mtr */
2314
return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2317
/**************************************************************************
2318
Calculates the number of pages reserved by a segment, and how many pages are
2322
fseg_n_reserved_pages_low(
2323
/*======================*/
2324
/* out: number of reserved pages */
2325
fseg_inode_t* inode, /* in: segment inode */
2326
ulint* used, /* out: number of pages used (<= reserved) */
2327
mtr_t* mtr) /* in: mtr handle */
2331
ut_ad(inode && used && mtr);
2332
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2334
*used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2335
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2336
+ fseg_get_n_frag_pages(inode, mtr);
2338
ret = fseg_get_n_frag_pages(inode, mtr)
2339
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2340
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2341
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2346
/**************************************************************************
2347
Calculates the number of pages reserved by a segment, and how many pages are
2351
fseg_n_reserved_pages(
2352
/*==================*/
2353
/* out: number of reserved pages */
2354
fseg_header_t* header, /* in: segment header */
2355
ulint* used, /* out: number of pages used (<= reserved) */
2356
mtr_t* mtr) /* in: mtr handle */
2359
fseg_inode_t* inode;
2365
space = page_get_space_id(page_align(header));
2366
latch = fil_space_get_latch(space, &flags);
2367
zip_size = dict_table_flags_to_zip_size(flags);
2369
ut_ad(!mutex_own(&kernel_mutex)
2370
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2372
mtr_x_lock(latch, mtr);
2374
inode = fseg_inode_get(header, space, zip_size, mtr);
2376
ret = fseg_n_reserved_pages_low(inode, used, mtr);
2381
/*************************************************************************
2382
Tries to fill the free list of a segment with consecutive free extents.
2383
This happens if the segment is big enough to allow extents in the free list,
2384
the free list is empty, and the extents can be allocated consecutively from
2388
fseg_fill_free_list(
2389
/*================*/
2390
fseg_inode_t* inode, /* in: segment inode */
2391
ulint space, /* in: space id */
2392
ulint zip_size,/* in: compressed page size in bytes
2393
or 0 for uncompressed pages */
2394
ulint hint, /* in: hint which extent would be good as
2396
mtr_t* mtr) /* in: mtr */
2404
ut_ad(inode && mtr);
2406
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2408
if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2410
/* The segment is too small to allow extents in free list */
2415
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2416
/* Free list is not empty */
2421
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2422
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2425
|| (XDES_FREE != xdes_get_state(descr, mtr))) {
2427
/* We cannot allocate the desired extent: stop */
2432
descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2434
xdes_set_state(descr, XDES_FSEG, mtr);
2436
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2437
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2439
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2440
hint += FSP_EXTENT_SIZE;
2444
/*************************************************************************
2445
Allocates a free extent for the segment: looks first in the free list of the
2446
segment, then tries to allocate from the space free list. NOTE that the extent
2447
returned still resides in the segment free list, it is not yet taken off it! */
2450
fseg_alloc_free_extent(
2451
/*===================*/
2452
/* out: allocated extent, still placed in the
2453
segment free list, NULL if could
2455
fseg_inode_t* inode, /* in: segment inode */
2456
ulint space, /* in: space id */
2457
ulint zip_size,/* in: compressed page size in bytes
2458
or 0 for uncompressed pages */
2459
mtr_t* mtr) /* in: mtr */
2465
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2466
/* Segment free list is not empty, allocate from it */
2468
first = flst_get_first(inode + FSEG_FREE, mtr);
2470
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2472
/* Segment free list was empty, allocate from space */
2473
descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2475
if (descr == NULL) {
2480
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2482
xdes_set_state(descr, XDES_FSEG, mtr);
2483
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2484
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2486
/* Try to fill the segment free list */
2487
fseg_fill_free_list(inode, space, zip_size,
2488
xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2495
/**************************************************************************
2496
Allocates a single free page from a segment. This function implements
2497
the intelligent allocation strategy which tries to minimize file space
2501
fseg_alloc_free_page_low(
2502
/*=====================*/
2503
/* out: the allocated page number, FIL_NULL
2504
if no page could be allocated */
2505
ulint space, /* in: space */
2506
ulint zip_size,/* in: compressed page size in bytes
2507
or 0 for uncompressed pages */
2508
fseg_inode_t* seg_inode, /* in: segment inode */
2509
ulint hint, /* in: hint of which page would be desirable */
2510
byte direction, /* in: if the new page is needed because
2511
of an index page split, and records are
2512
inserted there in order, into which
2513
direction they go alphabetically: FSP_DOWN,
2514
FSP_UP, FSP_NO_DIR */
2515
mtr_t* mtr) /* in: mtr handle */
2517
fsp_header_t* space_header;
2522
xdes_t* descr; /* extent of the hinted page */
2523
ulint ret_page; /* the allocated page offset, FIL_NULL
2524
if could not be allocated */
2525
xdes_t* ret_descr; /* the extent of the allocated page */
2526
ibool frag_page_allocated = FALSE;
2531
ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2532
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2533
== FSEG_MAGIC_N_VALUE);
2534
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
2536
ut_ad(!ut_dulint_is_zero(seg_id));
2538
reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2540
space_header = fsp_get_space_header(space, zip_size, mtr);
2542
descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2544
if (descr == NULL) {
2545
/* Hint outside space or too high above free limit: reset
2548
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2551
/* In the big if-else below we look for ret_page and ret_descr */
2552
/*-------------------------------------------------------------*/
2553
if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2554
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2556
&& (xdes_get_bit(descr, XDES_FREE_BIT,
2557
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2559
/* 1. We can take the hinted page
2560
=================================*/
2563
/*-----------------------------------------------------------*/
2564
} else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2565
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2566
&& (used >= FSEG_FRAG_LIMIT)) {
2568
/* 2. We allocate the free extent from space and can take
2569
=========================================================
2572
ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2574
ut_a(ret_descr == descr);
2576
xdes_set_state(ret_descr, XDES_FSEG, mtr);
2577
mlog_write_dulint(ret_descr + XDES_ID, seg_id, mtr);
2578
flst_add_last(seg_inode + FSEG_FREE,
2579
ret_descr + XDES_FLST_NODE, mtr);
2581
/* Try to fill the segment free list */
2582
fseg_fill_free_list(seg_inode, space, zip_size,
2583
hint + FSP_EXTENT_SIZE, mtr);
2585
/*-----------------------------------------------------------*/
2586
} else if ((direction != FSP_NO_DIR)
2587
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2588
&& (used >= FSEG_FRAG_LIMIT)
2590
= fseg_alloc_free_extent(seg_inode,
2591
space, zip_size, mtr)))) {
2593
/* 3. We take any free extent (which was already assigned above
2594
===============================================================
2595
in the if-condition to ret_descr) and take the lowest or
2596
========================================================
2597
highest page in it, depending on the direction
2598
==============================================*/
2599
ret_page = xdes_get_offset(ret_descr);
2601
if (direction == FSP_DOWN) {
2602
ret_page += FSP_EXTENT_SIZE - 1;
2604
/*-----------------------------------------------------------*/
2605
} else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2606
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2608
&& (!xdes_is_full(descr, mtr))) {
2610
/* 4. We can take the page from the same extent as the
2611
======================================================
2612
hinted page (and the extent already belongs to the
2613
==================================================
2617
ret_page = xdes_get_offset(ret_descr)
2618
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2619
hint % FSP_EXTENT_SIZE, mtr);
2620
/*-----------------------------------------------------------*/
2621
} else if (reserved - used > 0) {
2622
/* 5. We take any unused page from the segment
2623
==============================================*/
2626
if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2627
first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2629
} else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2630
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2636
ret_descr = xdes_lst_get_descriptor(space, zip_size,
2638
ret_page = xdes_get_offset(ret_descr)
2639
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2641
/*-----------------------------------------------------------*/
2642
} else if (used < FSEG_FRAG_LIMIT) {
2643
/* 6. We allocate an individual page from the space
2644
===================================================*/
2645
ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
2648
frag_page_allocated = TRUE;
2650
if (ret_page != FIL_NULL) {
2651
/* Put the page in the fragment page array of the
2653
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2654
ut_a(n != FIL_NULL);
2656
fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2659
/*-----------------------------------------------------------*/
2661
/* 7. We allocate a new extent and take its first page
2662
======================================================*/
2663
ret_descr = fseg_alloc_free_extent(seg_inode,
2664
space, zip_size, mtr);
2666
if (ret_descr == NULL) {
2667
ret_page = FIL_NULL;
2669
ret_page = xdes_get_offset(ret_descr);
2673
if (ret_page == FIL_NULL) {
2674
/* Page could not be allocated */
2680
space_size = fil_space_get_size(space);
2682
if (space_size <= ret_page) {
2683
/* It must be that we are extending a single-table
2684
tablespace whose size is still < 64 pages */
2686
if (ret_page >= FSP_EXTENT_SIZE) {
2688
"InnoDB: Error (2): trying to extend"
2689
" a single-table tablespace %lu\n"
2690
"InnoDB: by single page(s) though"
2691
" the space size %lu. Page no %lu.\n",
2692
(ulong) space, (ulong) space_size,
2697
success = fsp_try_extend_data_file_with_pages(
2698
space, ret_page, space_header, mtr);
2700
/* No disk space left */
2706
if (!frag_page_allocated) {
2707
/* Initialize the allocated page to buffer pool, so that it
2708
can be obtained immediately with buf_page_get without need
2711
ulint zip_size = dict_table_flags_to_zip_size(
2712
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
2714
block = buf_page_create(space, ret_page, zip_size, mtr);
2715
#ifdef UNIV_SYNC_DEBUG
2716
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
2717
#endif /* UNIV_SYNC_DEBUG */
2718
if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
2719
ret_page, RW_X_LATCH,
2724
/* The prior contents of the page should be ignored */
2725
fsp_init_file_page(block, mtr);
2727
/* At this point we know the extent and the page offset.
2728
The extent is still in the appropriate list (FSEG_NOT_FULL
2729
or FSEG_FREE), and the page is not yet marked as used. */
2731
ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
2733
ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2734
ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2736
fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
2739
buf_reset_check_index_page_at_flush(space, ret_page);
2744
/**************************************************************************
2745
Allocates a single free page from a segment. This function implements
2746
the intelligent allocation strategy which tries to minimize file space
2750
fseg_alloc_free_page_general(
2751
/*=========================*/
2752
/* out: allocated page offset, FIL_NULL if no
2753
page could be allocated */
2754
fseg_header_t* seg_header,/* in: segment header */
2755
ulint hint, /* in: hint of which page would be desirable */
2756
byte direction,/* in: if the new page is needed because
2757
of an index page split, and records are
2758
inserted there in order, into which
2759
direction they go alphabetically: FSP_DOWN,
2760
FSP_UP, FSP_NO_DIR */
2761
ibool has_done_reservation, /* in: TRUE if the caller has
2762
already done the reservation for the page
2763
with fsp_reserve_free_extents, then there
2764
is no need to do the check for this individual
2766
mtr_t* mtr) /* in: mtr handle */
2768
fseg_inode_t* inode;
2777
space = page_get_space_id(page_align(seg_header));
2779
latch = fil_space_get_latch(space, &flags);
2781
zip_size = dict_table_flags_to_zip_size(flags);
2783
ut_ad(!mutex_own(&kernel_mutex)
2784
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2786
mtr_x_lock(latch, mtr);
2788
if (rw_lock_get_x_lock_count(latch) == 1) {
2789
/* This thread did not own the latch before this call: free
2790
excess pages from the insert buffer free list */
2793
ibuf_free_excess_pages(0);
2797
inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2799
if (!has_done_reservation) {
2800
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2807
page_no = fseg_alloc_free_page_low(space, zip_size,
2808
inode, hint, direction, mtr);
2809
if (!has_done_reservation) {
2810
fil_space_release_free_extents(space, n_reserved);
2816
/**************************************************************************
2817
Allocates a single free page from a segment. This function implements
2818
the intelligent allocation strategy which tries to minimize file space
2822
fseg_alloc_free_page(
2823
/*=================*/
2824
/* out: allocated page offset, FIL_NULL if no
2825
page could be allocated */
2826
fseg_header_t* seg_header,/* in: segment header */
2827
ulint hint, /* in: hint of which page would be desirable */
2828
byte direction,/* in: if the new page is needed because
2829
of an index page split, and records are
2830
inserted there in order, into which
2831
direction they go alphabetically: FSP_DOWN,
2832
FSP_UP, FSP_NO_DIR */
2833
mtr_t* mtr) /* in: mtr handle */
2835
return(fseg_alloc_free_page_general(seg_header, hint, direction,
2839
/**************************************************************************
2840
Checks that we have at least 2 frag pages free in the first extent of a
2841
single-table tablespace, and they are also physically initialized to the data
2842
file. That is we have already extended the data file so that those pages are
2843
inside the data file. If not, this function extends the tablespace with
2847
fsp_reserve_free_pages(
2848
/*===================*/
2849
/* out: TRUE if there were >= 3 free
2850
pages, or we were able to extend */
2851
ulint space, /* in: space id, must be != 0 */
2852
fsp_header_t* space_header, /* in: header of that space,
2854
ulint size, /* in: size of the tablespace in pages,
2855
must be < FSP_EXTENT_SIZE / 2 */
2856
mtr_t* mtr) /* in: mtr */
2862
ut_a(size < FSP_EXTENT_SIZE / 2);
2864
descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2866
n_used = xdes_get_n_used(descr, mtr);
2868
ut_a(n_used <= size);
2870
if (size >= n_used + 2) {
2875
return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2876
space_header, mtr));
2879
/**************************************************************************
2880
Reserves free pages from a tablespace. All mini-transactions which may
2881
use several pages from the tablespace should call this function beforehand
2882
and reserve enough free extents so that they certainly will be able
2883
to do their operation, like a B-tree page split, fully. Reservations
2884
must be released with function fil_space_release_free_extents!
2886
The alloc_type below has the following meaning: FSP_NORMAL means an
2887
operation which will probably result in more space usage, like an
2888
insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
2889
deleting rows, then this allocation will in the long run result in
2890
less space usage (after a purge); FSP_CLEANING means allocation done
2891
in a physical record delete (like in a purge) or other cleaning operation
2892
which will result in less space usage in the long run. We prefer the latter
2893
two types of allocation: when space is scarce, FSP_NORMAL allocations
2894
will not succeed, but the latter two allocations will succeed, if possible.
2895
The purpose is to avoid dead end where the database is full but the
2896
user cannot free any space because these freeing operations temporarily
2899
Single-table tablespaces whose size is < 32 pages are a special case. In this
2900
function we would liberally reserve several 64 page extents for every page
2901
split or merge in a B-tree. But we do not want to waste disk space if the table
2902
only occupies < 32 pages. That is why we apply different rules in that special
2903
case, just ensuring that there are 3 free pages available. */
2906
fsp_reserve_free_extents(
2907
/*=====================*/
2908
/* out: TRUE if we were able to make the reservation */
2909
ulint* n_reserved,/* out: number of extents actually reserved; if we
2910
return TRUE and the tablespace size is < 64 pages,
2911
then this can be 0, otherwise it is n_ext */
2912
ulint space, /* in: space id */
2913
ulint n_ext, /* in: number of extents to reserve */
2914
ulint alloc_type,/* in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
2915
mtr_t* mtr) /* in: mtr */
2917
fsp_header_t* space_header;
2919
ulint n_free_list_ext;
2928
ulint n_pages_added;
2931
*n_reserved = n_ext;
2933
latch = fil_space_get_latch(space, &flags);
2934
zip_size = dict_table_flags_to_zip_size(flags);
2936
ut_ad(!mutex_own(&kernel_mutex)
2937
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2939
mtr_x_lock(latch, mtr);
2941
space_header = fsp_get_space_header(space, zip_size, mtr);
2943
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
2945
if (size < FSP_EXTENT_SIZE / 2) {
2946
/* Use different rules for small single-table tablespaces */
2948
return(fsp_reserve_free_pages(space, space_header, size, mtr));
2951
n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
2953
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
2956
/* Below we play safe when counting free extents above the free limit:
2957
some of them will contain extent descriptor pages, and therefore
2958
will not be free extents */
2960
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
2962
if (n_free_up > 0) {
2965
n_free_up -= n_free_up
2966
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
2968
n_free_up -= n_free_up
2969
/ (zip_size / FSP_EXTENT_SIZE);
2973
n_free = n_free_list_ext + n_free_up;
2975
if (alloc_type == FSP_NORMAL) {
2976
/* We reserve 1 extent + 0.5 % of the space size to undo logs
2977
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
2978
code is duplicated in the function below! */
2980
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
2982
if (n_free <= reserve + n_ext) {
2986
} else if (alloc_type == FSP_UNDO) {
2987
/* We reserve 0.5 % of the space size to cleaning operations */
2989
reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
2991
if (n_free <= reserve + n_ext) {
2996
ut_a(alloc_type == FSP_CLEANING);
2999
success = fil_space_reserve_free_extents(space, n_free, n_ext);
3005
success = fsp_try_extend_data_file(&n_pages_added, space,
3007
if (success && n_pages_added > 0) {
3015
/**************************************************************************
3016
This function should be used to get information on how much we still
3017
will be able to insert new data to the database without running out the
3018
tablespace. Only free extents are taken into account and we also subtract
3019
the safety margin required by the above function fsp_reserve_free_extents. */
3022
fsp_get_available_space_in_free_extents(
3023
/*====================================*/
3024
/* out: available space in kB */
3025
ulint space) /* in: space id */
3027
fsp_header_t* space_header;
3028
ulint n_free_list_ext;
3039
ut_ad(!mutex_own(&kernel_mutex));
3043
latch = fil_space_get_latch(space, &flags);
3044
zip_size = dict_table_flags_to_zip_size(flags);
3046
mtr_x_lock(latch, &mtr);
3048
space_header = fsp_get_space_header(space, zip_size, &mtr);
3050
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
3052
n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
3054
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3058
if (size < FSP_EXTENT_SIZE) {
3059
ut_a(space != 0); /* This must be a single-table
3062
return(0); /* TODO: count free frag pages and
3063
return a value based on that */
3066
/* Below we play safe when counting free extents above the free limit:
3067
some of them will contain extent descriptor pages, and therefore
3068
will not be free extents */
3070
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3072
if (n_free_up > 0) {
3075
n_free_up -= n_free_up
3076
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3078
n_free_up -= n_free_up
3079
/ (zip_size / FSP_EXTENT_SIZE);
3083
n_free = n_free_list_ext + n_free_up;
3085
/* We reserve 1 extent + 0.5 % of the space size to undo logs
3086
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3087
code is duplicated in the function above! */
3089
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3091
if (reserve > n_free) {
3096
return((ullint) (n_free - reserve)
3098
* (UNIV_PAGE_SIZE / 1024));
3100
return((ullint) (n_free - reserve)
3102
* (zip_size / 1024));
3106
/************************************************************************
3107
Marks a page used. The page must reside within the extents of the given
3111
fseg_mark_page_used(
3112
/*================*/
3113
fseg_inode_t* seg_inode,/* in: segment inode */
3114
ulint space, /* in: space id */
3115
ulint zip_size,/* in: compressed page size in bytes
3116
or 0 for uncompressed pages */
3117
ulint page, /* in: page offset */
3118
mtr_t* mtr) /* in: mtr */
3121
ulint not_full_n_used;
3123
ut_ad(seg_inode && mtr);
3125
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3127
ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
3128
== mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
3130
if (xdes_is_free(descr, mtr)) {
3131
/* We move the extent from the free list to the
3133
flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3135
flst_add_last(seg_inode + FSEG_NOT_FULL,
3136
descr + XDES_FLST_NODE, mtr);
3139
ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
3141
/* We mark the page as used */
3142
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3144
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3147
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3149
if (xdes_is_full(descr, mtr)) {
3150
/* We move the extent from the NOT_FULL list to the
3152
flst_remove(seg_inode + FSEG_NOT_FULL,
3153
descr + XDES_FLST_NODE, mtr);
3154
flst_add_last(seg_inode + FSEG_FULL,
3155
descr + XDES_FLST_NODE, mtr);
3157
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3158
not_full_n_used - FSP_EXTENT_SIZE,
3163
/**************************************************************************
3164
Frees a single page of a segment. */
3169
fseg_inode_t* seg_inode, /* in: segment inode */
3170
ulint space, /* in: space id */
3171
ulint zip_size,/* in: compressed page size in bytes
3172
or 0 for uncompressed pages */
3173
ulint page, /* in: page offset */
3174
mtr_t* mtr) /* in: mtr handle */
3177
ulint not_full_n_used;
3183
ut_ad(seg_inode && mtr);
3184
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3185
== FSEG_MAGIC_N_VALUE);
3187
/* Drop search system page hash index if the page is found in
3188
the pool and is hashed */
3190
btr_search_drop_page_hash_when_freed(space, zip_size, page);
3192
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3195
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
3196
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3198
ut_print_buf(stderr, descr, 40);
3200
fprintf(stderr, "\n"
3201
"InnoDB: Serious error! InnoDB is trying to"
3203
"InnoDB: though it is already marked as free"
3204
" in the tablespace!\n"
3205
"InnoDB: The tablespace free space info is corrupt.\n"
3206
"InnoDB: You may need to dump your"
3207
" InnoDB tables and recreate the whole\n"
3208
"InnoDB: database!\n", (ulong) page);
3210
fputs("InnoDB: Please refer to\n"
3211
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3212
"forcing-recovery.html\n"
3213
"InnoDB: about forcing recovery.\n", stderr);
3217
state = xdes_get_state(descr, mtr);
3219
if (state != XDES_FSEG) {
3220
/* The page is in the fragment pages of the segment */
3223
if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3226
fseg_set_nth_frag_page_no(seg_inode, i,
3232
fsp_free_page(space, zip_size, page, mtr);
3237
/* If we get here, the page is in some extent of the segment */
3239
descr_id = mtr_read_dulint(descr + XDES_ID, mtr);
3240
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
3243
"InnoDB: InnoDB is freeing space %lu page %lu,\n"
3244
"InnoDB: which belongs to descr seg %lu %lu\n"
3245
"InnoDB: segment %lu %lu.\n",
3246
(ulong) space, (ulong) page,
3247
(ulong) ut_dulint_get_high(descr_id),
3248
(ulong) ut_dulint_get_low(descr_id),
3249
(ulong) ut_dulint_get_high(seg_id),
3250
(ulong) ut_dulint_get_low(seg_id));
3252
if (0 != ut_dulint_cmp(descr_id, seg_id)) {
3253
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3255
ut_print_buf(stderr, descr, 40);
3256
fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3257
ut_print_buf(stderr, seg_inode, 40);
3261
"InnoDB: Serious error: InnoDB is trying to"
3262
" free space %lu page %lu,\n"
3263
"InnoDB: which does not belong to"
3264
" segment %lu %lu but belongs\n"
3265
"InnoDB: to segment %lu %lu.\n",
3266
(ulong) space, (ulong) page,
3267
(ulong) ut_dulint_get_high(descr_id),
3268
(ulong) ut_dulint_get_low(descr_id),
3269
(ulong) ut_dulint_get_high(seg_id),
3270
(ulong) ut_dulint_get_low(seg_id));
3274
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3276
if (xdes_is_full(descr, mtr)) {
3277
/* The fragment is full: move it to another list */
3278
flst_remove(seg_inode + FSEG_FULL,
3279
descr + XDES_FLST_NODE, mtr);
3280
flst_add_last(seg_inode + FSEG_NOT_FULL,
3281
descr + XDES_FLST_NODE, mtr);
3282
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3283
not_full_n_used + FSP_EXTENT_SIZE - 1,
3286
ut_a(not_full_n_used > 0);
3287
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3288
not_full_n_used - 1, MLOG_4BYTES, mtr);
3291
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3292
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3294
if (xdes_is_free(descr, mtr)) {
3295
/* The extent has become free: free it to space */
3296
flst_remove(seg_inode + FSEG_NOT_FULL,
3297
descr + XDES_FLST_NODE, mtr);
3298
fsp_free_extent(space, zip_size, page, mtr);
3302
/**************************************************************************
3303
Frees a single page of a segment. */
3308
fseg_header_t* seg_header, /* in: segment header */
3309
ulint space, /* in: space id */
3310
ulint page, /* in: page offset */
3311
mtr_t* mtr) /* in: mtr handle */
3315
fseg_inode_t* seg_inode;
3318
latch = fil_space_get_latch(space, &flags);
3319
zip_size = dict_table_flags_to_zip_size(flags);
3321
ut_ad(!mutex_own(&kernel_mutex)
3322
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3324
mtr_x_lock(latch, mtr);
3326
seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3328
fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3330
#ifdef UNIV_DEBUG_FILE_ACCESSES
3331
buf_page_set_file_page_was_freed(space, page);
3335
/**************************************************************************
3336
Frees an extent of a segment to the space free list. */
3341
fseg_inode_t* seg_inode, /* in: segment inode */
3342
ulint space, /* in: space id */
3343
ulint zip_size,/* in: compressed page size in bytes
3344
or 0 for uncompressed pages */
3345
ulint page, /* in: a page in the extent */
3346
mtr_t* mtr) /* in: mtr handle */
3348
ulint first_page_in_extent;
3350
ulint not_full_n_used;
3354
ut_ad(seg_inode && mtr);
3356
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3358
ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3359
ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr),
3360
mtr_read_dulint(seg_inode + FSEG_ID, mtr)));
3362
first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3364
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3365
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3367
/* Drop search system page hash index if the page is
3368
found in the pool and is hashed */
3370
btr_search_drop_page_hash_when_freed(
3371
space, zip_size, first_page_in_extent + i);
3375
if (xdes_is_full(descr, mtr)) {
3376
flst_remove(seg_inode + FSEG_FULL,
3377
descr + XDES_FLST_NODE, mtr);
3378
} else if (xdes_is_free(descr, mtr)) {
3379
flst_remove(seg_inode + FSEG_FREE,
3380
descr + XDES_FLST_NODE, mtr);
3382
flst_remove(seg_inode + FSEG_NOT_FULL,
3383
descr + XDES_FLST_NODE, mtr);
3385
not_full_n_used = mtr_read_ulint(
3386
seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3388
descr_n_used = xdes_get_n_used(descr, mtr);
3389
ut_a(not_full_n_used >= descr_n_used);
3390
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3391
not_full_n_used - descr_n_used,
3395
fsp_free_extent(space, zip_size, page, mtr);
3397
#ifdef UNIV_DEBUG_FILE_ACCESSES
3398
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3400
buf_page_set_file_page_was_freed(space,
3401
first_page_in_extent + i);
3406
/**************************************************************************
3407
Frees part of a segment. This function can be used to free a segment by
3408
repeatedly calling this function in different mini-transactions. Doing
3409
the freeing in a single mini-transaction might result in too big a
3410
mini-transaction. */
3415
/* out: TRUE if freeing completed */
3416
fseg_header_t* header, /* in, own: segment header; NOTE: if the header
3417
resides on the first page of the frag list
3418
of the segment, this pointer becomes obsolete
3419
after the last freeing step */
3420
mtr_t* mtr) /* in: mtr */
3425
fseg_inode_t* inode;
3432
space = page_get_space_id(page_align(header));
3433
header_page = page_get_page_no(page_align(header));
3435
latch = fil_space_get_latch(space, &flags);
3436
zip_size = dict_table_flags_to_zip_size(flags);
3438
ut_ad(!mutex_own(&kernel_mutex)
3439
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3441
mtr_x_lock(latch, mtr);
3443
descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3445
/* Check that the header resides on a page which has not been
3449
ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
3450
header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3451
inode = fseg_inode_get(header, space, zip_size, mtr);
3453
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3455
if (descr != NULL) {
3456
/* Free the extent held by the segment */
3457
page = xdes_get_offset(descr);
3459
fseg_free_extent(inode, space, zip_size, page, mtr);
3464
/* Free a frag page */
3465
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3467
if (n == ULINT_UNDEFINED) {
3468
/* Freeing completed: free the segment inode */
3469
fsp_free_seg_inode(space, zip_size, inode, mtr);
3474
fseg_free_page_low(inode, space, zip_size,
3475
fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3477
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3479
if (n == ULINT_UNDEFINED) {
3480
/* Freeing completed: free the segment inode */
3481
fsp_free_seg_inode(space, zip_size, inode, mtr);
3489
/**************************************************************************
3490
Frees part of a segment. Differs from fseg_free_step because this function
3491
leaves the header page unfreed. */
3494
fseg_free_step_not_header(
3495
/*======================*/
3496
/* out: TRUE if freeing completed, except the
3498
fseg_header_t* header, /* in: segment header which must reside on
3499
the first fragment page of the segment */
3500
mtr_t* mtr) /* in: mtr */
3505
fseg_inode_t* inode;
3512
space = page_get_space_id(page_align(header));
3514
latch = fil_space_get_latch(space, &flags);
3515
zip_size = dict_table_flags_to_zip_size(flags);
3517
ut_ad(!mutex_own(&kernel_mutex)
3518
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3520
mtr_x_lock(latch, mtr);
3522
inode = fseg_inode_get(header, space, zip_size, mtr);
3524
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3526
if (descr != NULL) {
3527
/* Free the extent held by the segment */
3528
page = xdes_get_offset(descr);
3530
fseg_free_extent(inode, space, zip_size, page, mtr);
3535
/* Free a frag page */
3537
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3539
if (n == ULINT_UNDEFINED) {
3543
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3545
if (page_no == page_get_page_no(page_align(header))) {
3550
fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3555
/***********************************************************************
3556
Frees a segment. The freeing is performed in several mini-transactions,
3557
so that there is no danger of bufferfixing too many buffer pages. */
3562
ulint space, /* in: space id */
3563
ulint zip_size,/* in: compressed page size in bytes
3564
or 0 for uncompressed pages */
3565
ulint page_no,/* in: page number where the segment header is
3567
ulint offset) /* in: byte offset of the segment header on that
3572
fseg_header_t* header;
3575
addr.page = page_no;
3576
addr.boffset = offset;
3581
header = fut_get_ptr(space, zip_size, addr, RW_X_LATCH, &mtr);
3583
finished = fseg_free_step(header, &mtr);
3594
/**************************************************************************
3595
Returns the first extent descriptor for a segment. We think of the extent
3596
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
3600
fseg_get_first_extent(
3601
/*==================*/
3602
/* out: the first extent descriptor, or NULL if
3604
fseg_inode_t* inode, /* in: segment inode */
3605
ulint space, /* in: space id */
3606
ulint zip_size,/* in: compressed page size in bytes
3607
or 0 for uncompressed pages */
3608
mtr_t* mtr) /* in: mtr */
3613
ut_ad(inode && mtr);
3615
ut_ad(space == page_get_space_id(page_align(inode)));
3617
first = fil_addr_null;
3619
if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3621
first = flst_get_first(inode + FSEG_FULL, mtr);
3623
} else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3625
first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3627
} else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3629
first = flst_get_first(inode + FSEG_FREE, mtr);
3632
if (first.page == FIL_NULL) {
3636
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3641
/***********************************************************************
3642
Validates a segment. */
3647
/* out: TRUE if ok */
3648
fseg_inode_t* inode, /* in: segment inode */
3649
mtr_t* mtr2) /* in: mtr */
3655
fil_addr_t node_addr;
3659
ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3660
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3662
space = page_get_space_id(page_align(inode));
3664
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr2);
3665
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3667
flst_validate(inode + FSEG_FREE, mtr2);
3668
flst_validate(inode + FSEG_NOT_FULL, mtr2);
3669
flst_validate(inode + FSEG_FULL, mtr2);
3671
/* Validate FSEG_FREE list */
3672
node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3674
while (!fil_addr_is_null(node_addr)) {
3679
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3680
zip_size = dict_table_flags_to_zip_size(flags);
3682
descr = xdes_lst_get_descriptor(space, zip_size,
3685
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3686
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3687
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3690
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3694
/* Validate FSEG_NOT_FULL list */
3696
node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3698
while (!fil_addr_is_null(node_addr)) {
3703
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3704
zip_size = dict_table_flags_to_zip_size(flags);
3706
descr = xdes_lst_get_descriptor(space, zip_size,
3709
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3710
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3711
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3712
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3715
n_used2 += xdes_get_n_used(descr, &mtr);
3717
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3721
/* Validate FSEG_FULL list */
3723
node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3725
while (!fil_addr_is_null(node_addr)) {
3730
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3731
zip_size = dict_table_flags_to_zip_size(flags);
3733
descr = xdes_lst_get_descriptor(space, zip_size,
3736
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3737
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3738
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3741
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3745
ut_a(n_used == n_used2);
3750
/***********************************************************************
3751
Validates a segment. */
3756
/* out: TRUE if ok */
3757
fseg_header_t* header, /* in: segment header */
3758
mtr_t* mtr) /* in: mtr */
3760
fseg_inode_t* inode;
3766
space = page_get_space_id(page_align(header));
3768
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3769
zip_size = dict_table_flags_to_zip_size(flags);
3771
inode = fseg_inode_get(header, space, zip_size, mtr);
3773
ret = fseg_validate_low(inode, mtr);
3778
/***********************************************************************
3779
Writes info of a segment. */
3784
fseg_inode_t* inode, /* in: segment inode */
3785
mtr_t* mtr) /* in: mtr */
3800
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3801
space = page_get_space_id(page_align(inode));
3802
page_no = page_get_page_no(page_align(inode));
3804
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3806
d_var = mtr_read_dulint(inode + FSEG_ID, mtr);
3808
seg_id_low = ut_dulint_get_low(d_var);
3809
seg_id_high = ut_dulint_get_high(d_var);
3811
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3813
n_frag = fseg_get_n_frag_pages(inode, mtr);
3814
n_free = flst_get_len(inode + FSEG_FREE, mtr);
3815
n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3816
n_full = flst_get_len(inode + FSEG_FULL, mtr);
3819
"SEGMENT id %lu %lu space %lu; page %lu;"
3820
" res %lu used %lu; full ext %lu\n"
3821
"fragm pages %lu; free extents %lu;"
3822
" not full extents %lu: pages %lu\n",
3823
(ulong) seg_id_high, (ulong) seg_id_low,
3824
(ulong) space, (ulong) page_no,
3825
(ulong) reserved, (ulong) used, (ulong) n_full,
3826
(ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3830
#ifdef UNIV_BTR_PRINT
3831
/***********************************************************************
3832
Writes info of a segment. */
3837
fseg_header_t* header, /* in: segment header */
3838
mtr_t* mtr) /* in: mtr */
3840
fseg_inode_t* inode;
3845
space = page_get_space_id(page_align(header));
3847
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3848
zip_size = dict_table_flags_to_zip_size(flags);
3850
inode = fseg_inode_get(header, space, zip_size, mtr);
3852
fseg_print_low(inode, mtr);
3854
#endif /* UNIV_BTR_PRINT */
3856
/***********************************************************************
3857
Validates the file space system and its segments. */
3862
/* out: TRUE if ok */
3863
ulint space) /* in: space id */
3865
fsp_header_t* header;
3866
fseg_inode_t* seg_inode;
3867
page_t* seg_inode_page;
3877
fil_addr_t node_addr;
3878
fil_addr_t next_node_addr;
3879
ulint descr_count = 0;
3882
ulint n_full_frag_pages;
3884
ulint seg_inode_len_free;
3885
ulint seg_inode_len_full;
3887
latch = fil_space_get_latch(space, &flags);
3888
zip_size = dict_table_flags_to_zip_size(flags);
3889
ut_a(ut_is_2pow(zip_size));
3890
ut_a(zip_size <= UNIV_PAGE_SIZE);
3891
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
3893
/* Start first a mini-transaction mtr2 to lock out all other threads
3894
from the fsp system */
3896
mtr_x_lock(latch, &mtr2);
3899
mtr_x_lock(latch, &mtr);
3901
header = fsp_get_space_header(space, zip_size, &mtr);
3903
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3904
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3906
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3909
n_full_frag_pages = FSP_EXTENT_SIZE
3910
* flst_get_len(header + FSP_FULL_FRAG, &mtr);
3912
if (UNIV_UNLIKELY(free_limit > size)) {
3915
ut_a(size < FSP_EXTENT_SIZE);
3918
flst_validate(header + FSP_FREE, &mtr);
3919
flst_validate(header + FSP_FREE_FRAG, &mtr);
3920
flst_validate(header + FSP_FULL_FRAG, &mtr);
3924
/* Validate FSP_FREE list */
3926
mtr_x_lock(latch, &mtr);
3928
header = fsp_get_space_header(space, zip_size, &mtr);
3929
node_addr = flst_get_first(header + FSP_FREE, &mtr);
3933
while (!fil_addr_is_null(node_addr)) {
3935
mtr_x_lock(latch, &mtr);
3938
descr = xdes_lst_get_descriptor(space, zip_size,
3941
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3942
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3944
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3948
/* Validate FSP_FREE_FRAG list */
3950
mtr_x_lock(latch, &mtr);
3952
header = fsp_get_space_header(space, zip_size, &mtr);
3953
node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
3957
while (!fil_addr_is_null(node_addr)) {
3959
mtr_x_lock(latch, &mtr);
3962
descr = xdes_lst_get_descriptor(space, zip_size,
3965
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3966
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3967
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
3969
n_used += xdes_get_n_used(descr, &mtr);
3970
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3975
/* Validate FSP_FULL_FRAG list */
3977
mtr_x_lock(latch, &mtr);
3979
header = fsp_get_space_header(space, zip_size, &mtr);
3980
node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
3984
while (!fil_addr_is_null(node_addr)) {
3986
mtr_x_lock(latch, &mtr);
3989
descr = xdes_lst_get_descriptor(space, zip_size,
3992
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3993
ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
3995
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3999
/* Validate segments */
4001
mtr_x_lock(latch, &mtr);
4003
header = fsp_get_space_header(space, zip_size, &mtr);
4005
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4007
seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
4011
while (!fil_addr_is_null(node_addr)) {
4016
mtr_x_lock(latch, &mtr);
4018
seg_inode_page = fut_get_ptr(
4019
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4020
- FSEG_INODE_PAGE_NODE;
4022
seg_inode = fsp_seg_inode_page_get_nth_inode(
4023
seg_inode_page, n, zip_size, &mtr);
4024
ut_a(!ut_dulint_is_zero(
4025
mach_read_from_8(seg_inode + FSEG_ID)));
4026
fseg_validate_low(seg_inode, &mtr);
4028
descr_count += flst_get_len(seg_inode + FSEG_FREE,
4030
descr_count += flst_get_len(seg_inode + FSEG_FULL,
4032
descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
4035
n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
4037
next_node_addr = flst_get_next_addr(
4038
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4040
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4042
node_addr = next_node_addr;
4046
mtr_x_lock(latch, &mtr);
4048
header = fsp_get_space_header(space, zip_size, &mtr);
4050
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4052
seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
4056
while (!fil_addr_is_null(node_addr)) {
4062
mtr_x_lock(latch, &mtr);
4064
seg_inode_page = fut_get_ptr(
4065
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4066
- FSEG_INODE_PAGE_NODE;
4068
seg_inode = fsp_seg_inode_page_get_nth_inode(
4069
seg_inode_page, n, zip_size, &mtr);
4070
if (!ut_dulint_is_zero(
4071
mach_read_from_8(seg_inode + FSEG_ID))) {
4072
fseg_validate_low(seg_inode, &mtr);
4074
descr_count += flst_get_len(
4075
seg_inode + FSEG_FREE, &mtr);
4076
descr_count += flst_get_len(
4077
seg_inode + FSEG_FULL, &mtr);
4078
descr_count += flst_get_len(
4079
seg_inode + FSEG_NOT_FULL, &mtr);
4080
n_used2 += fseg_get_n_frag_pages(
4084
next_node_addr = flst_get_next_addr(
4085
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4087
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4089
node_addr = next_node_addr;
4092
ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
4094
ut_a(n_used + n_full_frag_pages
4095
== n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
4097
+ seg_inode_len_full + seg_inode_len_free);
4099
ut_a(n_used + n_full_frag_pages
4100
== n_used2 + 2 * ((free_limit + (zip_size - 1))
4102
+ seg_inode_len_full + seg_inode_len_free);
4104
ut_a(frag_n_used == n_used);
4111
/***********************************************************************
4112
Prints info of a file space. */
4117
ulint space) /* in: space id */
4119
fsp_header_t* header;
4120
fseg_inode_t* seg_inode;
4121
page_t* seg_inode_page;
4128
fil_addr_t node_addr;
4129
fil_addr_t next_node_addr;
4141
latch = fil_space_get_latch(space, &flags);
4142
zip_size = dict_table_flags_to_zip_size(flags);
4144
/* Start first a mini-transaction mtr2 to lock out all other threads
4145
from the fsp system */
4149
mtr_x_lock(latch, &mtr2);
4153
mtr_x_lock(latch, &mtr);
4155
header = fsp_get_space_header(space, zip_size, &mtr);
4157
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4159
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4161
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4163
n_free = flst_get_len(header + FSP_FREE, &mtr);
4164
n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4165
n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4167
d_var = mtr_read_dulint(header + FSP_SEG_ID, &mtr);
4169
seg_id_low = ut_dulint_get_low(d_var);
4170
seg_id_high = ut_dulint_get_high(d_var);
4173
"FILE SPACE INFO: id %lu\n"
4174
"size %lu, free limit %lu, free extents %lu\n"
4175
"not full frag extents %lu: used pages %lu,"
4176
" full frag extents %lu\n"
4177
"first seg id not used %lu %lu\n",
4179
(ulong) size, (ulong) free_limit, (ulong) n_free,
4180
(ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4181
(ulong) seg_id_high, (ulong) seg_id_low);
4185
/* Print segments */
4188
mtr_x_lock(latch, &mtr);
4190
header = fsp_get_space_header(space, zip_size, &mtr);
4192
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4196
while (!fil_addr_is_null(node_addr)) {
4203
mtr_x_lock(latch, &mtr);
4205
seg_inode_page = fut_get_ptr(
4206
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4207
- FSEG_INODE_PAGE_NODE;
4209
seg_inode = fsp_seg_inode_page_get_nth_inode(
4210
seg_inode_page, n, zip_size, &mtr);
4211
ut_a(!ut_dulint_is_zero(
4212
mach_read_from_8(seg_inode + FSEG_ID)));
4213
fseg_print_low(seg_inode, &mtr);
4217
next_node_addr = flst_get_next_addr(
4218
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4220
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4222
node_addr = next_node_addr;
4226
mtr_x_lock(latch, &mtr);
4228
header = fsp_get_space_header(space, zip_size, &mtr);
4230
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4234
while (!fil_addr_is_null(node_addr)) {
4241
mtr_x_lock(latch, &mtr);
4243
seg_inode_page = fut_get_ptr(
4244
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4245
- FSEG_INODE_PAGE_NODE;
4247
seg_inode = fsp_seg_inode_page_get_nth_inode(
4248
seg_inode_page, n, zip_size, &mtr);
4249
if (!ut_dulint_is_zero(
4250
mach_read_from_8(seg_inode + FSEG_ID))) {
4252
fseg_print_low(seg_inode, &mtr);
4256
next_node_addr = flst_get_next_addr(
4257
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4259
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4261
node_addr = next_node_addr;
4266
fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);