1
/*****************************************************************************
3
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/******************************************************************//**
23
Created 11/29/1995 Heikki Tuuri
24
***********************************************************************/
36
#include "page0page.h"
40
#else /* UNIV_HOTBACKUP */
41
# include "sync0sync.h"
44
# include "ibuf0ibuf.h"
47
# include "dict0boot.h"
49
#endif /* UNIV_HOTBACKUP */
53
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
56
/* The data structures in files are defined just as byte strings in C */
57
typedef byte fsp_header_t;
63
File space header data structure: this data structure is contained in the
64
first page of a space. The space for this header is reserved in every extent
65
descriptor page, but used only in the first. */
67
/*-------------------------------------*/
68
#define FSP_SPACE_ID 0 /* space id */
69
#define FSP_NOT_USED 4 /* this field contained a value up to
70
which we know that the modifications
71
in the database have been flushed to
72
the file space; not used now */
73
#define FSP_SIZE 8 /* Current size of the space in
75
#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
76
free list has not been initialized:
77
the pages >= this limit are, by
78
definition, free; note that in a
79
single-table tablespace where size
80
< 64 pages, this number is 64, i.e.,
81
we have initialized the space
82
about the first extent, but have not
83
physically allocted those pages to the
85
#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */
86
#define FSP_FRAG_N_USED 20 /* number of used pages in the
88
#define FSP_FREE 24 /* list of free extents */
89
#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
90
/* list of partially free extents not
91
belonging to any segment */
92
#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
93
/* list of full extents not belonging
95
#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
96
/* 8 bytes which give the first unused
98
#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
99
/* list of pages containing segment
100
headers, where all the segment inode
101
slots are reserved */
102
#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
103
/* list of pages containing segment
104
headers, where not all the segment
105
header slots are reserved */
106
/*-------------------------------------*/
107
/* File space header size */
108
#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
110
#define FSP_FREE_ADD 4 /* this many free extents are added
111
to the free list from above
112
FSP_FREE_LIMIT at a time */
114
/* FILE SEGMENT INODE
117
Segment inode which is created for each segment in a tablespace. NOTE: in
118
purge we assume that a segment having only one currently used page can be
119
freed in a few steps, so that the freeing cannot fill the file buffer with
120
bufferfixed file pages. */
122
typedef byte fseg_inode_t;
124
#define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
125
/* the list node for linking
126
segment inode pages */
128
#define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
129
/*-------------------------------------*/
130
#define FSEG_ID 0 /* 8 bytes of segment id: if this is
131
ut_dulint_zero, it means that the
133
#define FSEG_NOT_FULL_N_USED 8
134
/* number of used segment pages in
135
the FSEG_NOT_FULL list */
137
/* list of free extents of this
139
#define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
140
/* list of partially free extents */
141
#define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
142
/* list of full extents */
143
#define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
144
/* magic number used in debugging */
145
#define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
146
/* array of individual pages
147
belonging to this segment in fsp
148
fragment extent lists */
149
#define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
150
/* number of slots in the array for
151
the fragment pages */
152
#define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
153
page number within space, FIL_NULL
154
means that the slot is not in use */
155
/*-------------------------------------*/
156
#define FSEG_INODE_SIZE \
157
(16 + 3 * FLST_BASE_NODE_SIZE \
158
+ FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
160
#define FSP_SEG_INODES_PER_PAGE(zip_size) \
161
(((zip_size ? zip_size : UNIV_PAGE_SIZE) \
162
- FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
163
/* Number of segment inodes which fit on a
166
#define FSEG_MAGIC_N_VALUE 97937874
168
#define FSEG_FILLFACTOR 8 /* If this value is x, then if
169
the number of unused but reserved
170
pages in a segment is less than
171
reserved pages * 1/x, and there are
172
at least FSEG_FRAG_LIMIT used pages,
173
then we allow a new empty extent to
174
be added to the segment in
175
fseg_alloc_free_page. Otherwise, we
176
use unused pages of the segment. */
178
#define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
179
/* If the segment has >= this many
180
used pages, it may be expanded by
181
allocating extents to the segment;
182
until that only individual fragment
183
pages are allocated from the space */
185
#define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
186
is at least this many extents, we
187
allow extents to be put to the free
188
list of the extent: at most
189
FSEG_FREE_LIST_MAX_LEN many */
190
#define FSEG_FREE_LIST_MAX_LEN 4
196
File extent descriptor data structure: contains bits to tell which pages in
197
the extent are free and which contain old tuple version to clean. */
199
/*-------------------------------------*/
200
#define XDES_ID 0 /* The identifier of the segment
201
to which this extent belongs */
202
#define XDES_FLST_NODE 8 /* The list node data structure
203
for the descriptors */
204
#define XDES_STATE (FLST_NODE_SIZE + 8)
205
/* contains state information
207
#define XDES_BITMAP (FLST_NODE_SIZE + 12)
208
/* Descriptor bitmap of the pages
210
/*-------------------------------------*/
212
#define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
213
#define XDES_FREE_BIT 0 /* Index of the bit which tells if
215
#define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
216
Index of the bit which tells if
217
there are old versions of tuples
219
/* States of a descriptor */
220
#define XDES_FREE 1 /* extent is in free list of space */
221
#define XDES_FREE_FRAG 2 /* extent is in free fragment list of
223
#define XDES_FULL_FRAG 3 /* extent is in full fragment list of
225
#define XDES_FSEG 4 /* extent belongs to a segment */
227
/* File extent data structure size in bytes. */
229
(XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
231
/* Offset of the descriptor array on a descriptor page */
232
#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
234
#ifndef UNIV_HOTBACKUP
235
/**********************************************************************//**
236
Returns an extent to the free list of a space. */
241
ulint space, /*!< in: space id */
242
ulint zip_size,/*!< in: compressed page size in bytes
243
or 0 for uncompressed pages */
244
ulint page, /*!< in: page offset in the extent */
245
mtr_t* mtr); /*!< in: mtr */
246
/**********************************************************************//**
247
Frees an extent of a segment to the space free list. */
252
fseg_inode_t* seg_inode, /*!< in: segment inode */
253
ulint space, /*!< in: space id */
254
ulint zip_size,/*!< in: compressed page size in bytes
255
or 0 for uncompressed pages */
256
ulint page, /*!< in: page offset in the extent */
257
mtr_t* mtr); /*!< in: mtr handle */
258
/**********************************************************************//**
259
Calculates the number of pages reserved by a segment, and how
260
many pages are currently used.
261
@return number of reserved pages */
264
fseg_n_reserved_pages_low(
265
/*======================*/
266
fseg_inode_t* header, /*!< in: segment inode */
267
ulint* used, /*!< out: number of pages used (not
268
more than reserved) */
269
mtr_t* mtr); /*!< in: mtr handle */
270
/********************************************************************//**
271
Marks a page used. The page must reside within the extents of the given
277
fseg_inode_t* seg_inode,/*!< in: segment inode */
278
ulint space, /*!< in: space id */
279
ulint zip_size,/*!< in: compressed page size in bytes
280
or 0 for uncompressed pages */
281
ulint page, /*!< in: page offset */
282
mtr_t* mtr); /*!< in: mtr */
283
/**********************************************************************//**
284
Returns the first extent descriptor for a segment. We think of the extent
285
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
287
@return the first extent descriptor, or NULL if none */
290
fseg_get_first_extent(
291
/*==================*/
292
fseg_inode_t* inode, /*!< in: segment inode */
293
ulint space, /*!< in: space id */
294
ulint zip_size,/*!< in: compressed page size in bytes
295
or 0 for uncompressed pages */
296
mtr_t* mtr); /*!< in: mtr */
297
/**********************************************************************//**
298
Puts new extents to the free list if
299
there are free extents above the free limit. If an extent happens
300
to contain an extent descriptor page, the extent is put to
301
the FSP_FREE_FRAG list with the page marked as used. */
306
ibool init_space, /*!< in: TRUE if this is a single-table
307
tablespace and we are only initing
308
the tablespace's first extent
309
descriptor page and ibuf bitmap page;
310
then we do not allocate more extents */
311
ulint space, /*!< in: space */
312
fsp_header_t* header, /*!< in: space header */
313
mtr_t* mtr); /*!< in: mtr */
314
/**********************************************************************//**
315
Allocates a single free page from a segment. This function implements
316
the intelligent allocation strategy which tries to minimize file space
318
@return the allocated page number, FIL_NULL if no page could be allocated */
321
fseg_alloc_free_page_low(
322
/*=====================*/
323
ulint space, /*!< in: space */
324
ulint zip_size,/*!< in: compressed page size in bytes
325
or 0 for uncompressed pages */
326
fseg_inode_t* seg_inode, /*!< in: segment inode */
327
ulint hint, /*!< in: hint of which page would be desirable */
328
byte direction, /*!< in: if the new page is needed because
329
of an index page split, and records are
330
inserted there in order, into which
331
direction they go alphabetically: FSP_DOWN,
332
FSP_UP, FSP_NO_DIR */
333
mtr_t* mtr); /*!< in: mtr handle */
334
#endif /* !UNIV_HOTBACKUP */
336
/**********************************************************************//**
337
Reads the file space size stored in the header page.
338
@return tablespace size stored in the space header */
343
page_t* page) /*!< in: header page (page 0 in the tablespace) */
345
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
348
#ifndef UNIV_HOTBACKUP
349
/**********************************************************************//**
350
Gets a pointer to the space header and x-locks its page.
351
@return pointer to the space header, page x-locked */
354
fsp_get_space_header(
355
/*=================*/
356
ulint id, /*!< in: space id */
357
ulint zip_size,/*!< in: compressed page size in bytes
358
or 0 for uncompressed pages */
359
mtr_t* mtr) /*!< in: mtr */
362
fsp_header_t* header;
364
ut_ad(ut_is_2pow(zip_size));
365
ut_ad(zip_size <= UNIV_PAGE_SIZE);
366
ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
367
ut_ad(id || !zip_size);
369
block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
370
header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
371
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
373
ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
374
ut_ad(zip_size == dict_table_flags_to_zip_size(
375
mach_read_from_4(FSP_SPACE_FLAGS + header)));
379
/**********************************************************************//**
380
Gets a descriptor bit of a page.
381
@return TRUE if free */
386
xdes_t* descr, /*!< in: descriptor */
387
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
388
ulint offset, /*!< in: page offset within extent:
389
0 ... FSP_EXTENT_SIZE - 1 */
390
mtr_t* mtr) /*!< in: mtr */
396
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
397
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
398
ut_ad(offset < FSP_EXTENT_SIZE);
400
index = bit + XDES_BITS_PER_PAGE * offset;
402
byte_index = index / 8;
403
bit_index = index % 8;
405
return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
410
/**********************************************************************//**
411
Sets a descriptor bit of a page. */
416
xdes_t* descr, /*!< in: descriptor */
417
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
418
ulint offset, /*!< in: page offset within extent:
419
0 ... FSP_EXTENT_SIZE - 1 */
420
ibool val, /*!< in: bit value */
421
mtr_t* mtr) /*!< in: mtr */
428
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
429
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
430
ut_ad(offset < FSP_EXTENT_SIZE);
432
index = bit + XDES_BITS_PER_PAGE * offset;
434
byte_index = index / 8;
435
bit_index = index % 8;
437
descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
439
descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
441
mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
445
/**********************************************************************//**
446
Looks for a descriptor bit having the desired value. Starts from hint
447
and scans upward; at the end of the extent the search is wrapped to
448
the start of the extent.
449
@return bit index of the bit, ULINT_UNDEFINED if not found */
454
xdes_t* descr, /*!< in: descriptor */
455
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
456
ibool val, /*!< in: desired bit value */
457
ulint hint, /*!< in: hint of which bit position would be desirable */
458
mtr_t* mtr) /*!< in: mtr */
464
ut_ad(hint < FSP_EXTENT_SIZE);
465
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
466
for (i = hint; i < FSP_EXTENT_SIZE; i++) {
467
if (val == xdes_get_bit(descr, bit, i, mtr)) {
473
for (i = 0; i < hint; i++) {
474
if (val == xdes_get_bit(descr, bit, i, mtr)) {
480
return(ULINT_UNDEFINED);
483
/**********************************************************************//**
484
Looks for a descriptor bit having the desired value. Scans the extent in
485
a direction opposite to xdes_find_bit.
486
@return bit index of the bit, ULINT_UNDEFINED if not found */
489
xdes_find_bit_downward(
490
/*===================*/
491
xdes_t* descr, /*!< in: descriptor */
492
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
493
ibool val, /*!< in: desired bit value */
494
ulint hint, /*!< in: hint of which bit position would be desirable */
495
mtr_t* mtr) /*!< in: mtr */
501
ut_ad(hint < FSP_EXTENT_SIZE);
502
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
503
for (i = hint + 1; i > 0; i--) {
504
if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
510
for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
511
if (val == xdes_get_bit(descr, bit, i, mtr)) {
517
return(ULINT_UNDEFINED);
520
/**********************************************************************//**
521
Returns the number of used pages in a descriptor.
522
@return number of pages used */
527
xdes_t* descr, /*!< in: descriptor */
528
mtr_t* mtr) /*!< in: mtr */
534
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
535
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
536
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
544
/**********************************************************************//**
545
Returns true if extent contains no used pages.
546
@return TRUE if totally free */
551
xdes_t* descr, /*!< in: descriptor */
552
mtr_t* mtr) /*!< in: mtr */
554
if (0 == xdes_get_n_used(descr, mtr)) {
562
/**********************************************************************//**
563
Returns true if extent contains no free pages.
564
@return TRUE if full */
569
xdes_t* descr, /*!< in: descriptor */
570
mtr_t* mtr) /*!< in: mtr */
572
if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
580
/**********************************************************************//**
581
Sets the state of an xdes. */
586
xdes_t* descr, /*!< in: descriptor */
587
ulint state, /*!< in: state to set */
588
mtr_t* mtr) /*!< in: mtr handle */
591
ut_ad(state >= XDES_FREE);
592
ut_ad(state <= XDES_FSEG);
593
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
595
mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
598
/**********************************************************************//**
599
Gets the state of an xdes.
605
xdes_t* descr, /*!< in: descriptor */
606
mtr_t* mtr) /*!< in: mtr handle */
611
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
613
state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
614
ut_ad(state - 1 < XDES_FSEG);
618
/**********************************************************************//**
619
Inits an extent descriptor to the free and clean state. */
624
xdes_t* descr, /*!< in: descriptor */
625
mtr_t* mtr) /*!< in: mtr */
630
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
631
ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
633
for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
634
mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
637
xdes_set_state(descr, XDES_FREE, mtr);
640
/********************************************************************//**
641
Calculates the page where the descriptor of a page resides.
642
@return descriptor page offset */
645
xdes_calc_descriptor_page(
646
/*======================*/
647
ulint zip_size, /*!< in: compressed page size in bytes;
648
0 for uncompressed pages */
649
ulint offset) /*!< in: page offset */
651
#ifndef DOXYGEN /* Doxygen gets confused of these */
652
# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
653
+ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
656
# if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
657
+ (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
660
#endif /* !DOXYGEN */
661
ut_ad(ut_is_2pow(zip_size));
664
return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
666
ut_ad(zip_size > XDES_ARR_OFFSET
667
+ (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
668
return(ut_2pow_round(offset, zip_size));
672
/********************************************************************//**
673
Calculates the descriptor index within a descriptor page.
674
@return descriptor index */
677
xdes_calc_descriptor_index(
678
/*=======================*/
679
ulint zip_size, /*!< in: compressed page size in bytes;
680
0 for uncompressed pages */
681
ulint offset) /*!< in: page offset */
683
ut_ad(ut_is_2pow(zip_size));
686
return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
689
return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
693
/********************************************************************//**
694
Gets pointer to a the extent descriptor of a page. The page where the extent
695
descriptor resides is x-locked. If the page offset is equal to the free limit
696
of the space, adds new extents from above the free limit to the space free
697
list, if not free limit == space size. This adding is necessary to make the
698
descriptor defined, as they are uninitialized above the free limit.
699
@return pointer to the extent descriptor, NULL if the page does not
700
exist in the space or if the offset exceeds the free limit */
703
xdes_get_descriptor_with_space_hdr(
704
/*===============================*/
705
fsp_header_t* sp_header,/*!< in: space header, x-latched */
706
ulint space, /*!< in: space id */
707
ulint offset, /*!< in: page offset;
708
if equal to the free limit,
709
we try to add new extents to
710
the space free list */
711
mtr_t* mtr) /*!< in: mtr handle */
720
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
722
ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
723
|| mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
724
ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
725
/* Read free limit and space size */
726
limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
727
size = mach_read_from_4(sp_header + FSP_SIZE);
728
zip_size = dict_table_flags_to_zip_size(
729
mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
731
/* If offset is >= size or > limit, return NULL */
733
if ((offset >= size) || (offset > limit)) {
738
/* If offset is == limit, fill free list of the space. */
740
if (offset == limit) {
741
fsp_fill_free_list(FALSE, space, sp_header, mtr);
744
descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
746
if (descr_page_no == 0) {
747
/* It is on the space header page */
749
descr_page = page_align(sp_header);
753
block = buf_page_get(space, zip_size, descr_page_no,
755
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
757
descr_page = buf_block_get_frame(block);
760
return(descr_page + XDES_ARR_OFFSET
761
+ XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
764
/********************************************************************//**
765
Gets pointer to a the extent descriptor of a page. The page where the
766
extent descriptor resides is x-locked. If the page offset is equal to
767
the free limit of the space, adds new extents from above the free limit
768
to the space free list, if not free limit == space size. This adding
769
is necessary to make the descriptor defined, as they are uninitialized
770
above the free limit.
771
@return pointer to the extent descriptor, NULL if the page does not
772
exist in the space or if the offset exceeds the free limit */
777
ulint space, /*!< in: space id */
778
ulint zip_size,/*!< in: compressed page size in bytes
779
or 0 for uncompressed pages */
780
ulint offset, /*!< in: page offset; if equal to the free limit,
781
we try to add new extents to the space free list */
782
mtr_t* mtr) /*!< in: mtr handle */
785
fsp_header_t* sp_header;
787
block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
788
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
790
sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
791
return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
795
/********************************************************************//**
796
Gets pointer to a the extent descriptor if the file address
797
of the descriptor list node is known. The page where the
798
extent descriptor resides is x-locked.
799
@return pointer to the extent descriptor */
802
xdes_lst_get_descriptor(
803
/*====================*/
804
ulint space, /*!< in: space id */
805
ulint zip_size,/*!< in: compressed page size in bytes
806
or 0 for uncompressed pages */
807
fil_addr_t lst_node,/*!< in: file address of the list node
808
contained in the descriptor */
809
mtr_t* mtr) /*!< in: mtr handle */
814
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
816
descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
822
/********************************************************************//**
823
Returns page offset of the first page in extent described by a descriptor.
824
@return offset of the first page in extent */
829
xdes_t* descr) /*!< in: extent descriptor */
833
return(page_get_page_no(page_align(descr))
834
+ ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
837
#endif /* !UNIV_HOTBACKUP */
839
/***********************************************************//**
840
Inits a file page whose prior contents should be ignored. */
843
fsp_init_file_page_low(
844
/*===================*/
845
buf_block_t* block) /*!< in: pointer to a page */
847
page_t* page = buf_block_get_frame(block);
848
page_zip_des_t* page_zip= buf_block_get_page_zip(block);
850
#ifndef UNIV_HOTBACKUP
851
block->check_index_page_at_flush = FALSE;
852
#endif /* !UNIV_HOTBACKUP */
854
if (UNIV_LIKELY_NULL(page_zip)) {
855
memset(page, 0, UNIV_PAGE_SIZE);
856
memset(page_zip->data, 0, page_zip_get_size(page_zip));
857
mach_write_to_4(page + FIL_PAGE_OFFSET,
858
buf_block_get_page_no(block));
860
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
861
buf_block_get_space(block));
862
memcpy(page_zip->data + FIL_PAGE_OFFSET,
863
page + FIL_PAGE_OFFSET, 4);
864
memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
865
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
869
#ifdef UNIV_BASIC_LOG_DEBUG
870
memset(page, 0xff, UNIV_PAGE_SIZE);
872
mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
873
memset(page + FIL_PAGE_LSN, 0, 8);
874
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
875
buf_block_get_space(block));
876
memset(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, 0, 8);
879
#ifndef UNIV_HOTBACKUP
880
/***********************************************************//**
881
Inits a file page whose prior contents should be ignored. */
886
buf_block_t* block, /*!< in: pointer to a page */
887
mtr_t* mtr) /*!< in: mtr */
889
fsp_init_file_page_low(block);
891
mlog_write_initial_log_record(buf_block_get_frame(block),
892
MLOG_INIT_FILE_PAGE, mtr);
894
#endif /* !UNIV_HOTBACKUP */
896
/***********************************************************//**
897
Parses a redo log record of a file page init.
898
@return end of log record or NULL */
901
fsp_parse_init_file_page(
902
/*=====================*/
903
byte* ptr, /*!< in: buffer */
904
byte* end_ptr __attribute__((unused)), /*!< in: buffer end */
905
buf_block_t* block) /*!< in: block or NULL */
907
ut_ad(ptr && end_ptr);
910
fsp_init_file_page_low(block);
916
/**********************************************************************//**
917
Initializes the fsp system. */
923
/* Does nothing at the moment */
926
/**********************************************************************//**
927
Writes the space id and compressed page size to a tablespace header.
928
This function is used past the buffer pool when we in fil0fil.c create
929
a new single-table tablespace. */
932
fsp_header_init_fields(
933
/*===================*/
934
page_t* page, /*!< in/out: first page in the space */
935
ulint space_id, /*!< in: space id */
936
ulint flags) /*!< in: tablespace flags (FSP_SPACE_FLAGS):
937
0, or table->flags if newer than COMPACT */
939
/* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
940
ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
941
ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
942
format, the tablespace flags should equal table->flags. */
943
ut_a(flags != DICT_TF_COMPACT);
945
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
947
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
951
#ifndef UNIV_HOTBACKUP
952
/**********************************************************************//**
953
Initializes the space header of a new created space and creates also the
954
insert buffer tree root if space == 0. */
959
ulint space, /*!< in: space id */
960
ulint size, /*!< in: current size in blocks */
961
mtr_t* mtr) /*!< in: mini-transaction handle */
963
fsp_header_t* header;
971
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
973
zip_size = dict_table_flags_to_zip_size(flags);
974
block = buf_page_create(space, 0, zip_size, mtr);
975
buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
976
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
978
/* The prior contents of the file page should be ignored */
980
fsp_init_file_page(block, mtr);
981
page = buf_block_get_frame(block);
983
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
986
header = FSP_HEADER_OFFSET + page;
988
mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
989
mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
991
mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
992
mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
993
mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
995
mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
997
flst_init(header + FSP_FREE, mtr);
998
flst_init(header + FSP_FREE_FRAG, mtr);
999
flst_init(header + FSP_FULL_FRAG, mtr);
1000
flst_init(header + FSP_SEG_INODES_FULL, mtr);
1001
flst_init(header + FSP_SEG_INODES_FREE, mtr);
1003
mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), mtr);
1005
fsp_fill_free_list(FALSE, space, header, mtr);
1006
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
1007
0, 0, ut_dulint_add(DICT_IBUF_ID_MIN, space),
1008
dict_ind_redundant, mtr);
1010
fsp_fill_free_list(TRUE, space, header, mtr);
1013
#endif /* !UNIV_HOTBACKUP */
1015
/**********************************************************************//**
1016
Reads the space id from the first page of a tablespace.
1017
@return space id, ULINT UNDEFINED if error */
1020
fsp_header_get_space_id(
1021
/*====================*/
1022
const page_t* page) /*!< in: first page of a tablespace */
1027
fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
1029
id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
1033
"InnoDB: Error: space id in fsp header %lu,"
1034
" but in the page header %lu\n",
1035
(ulong) fsp_id, (ulong) id);
1037
return(ULINT_UNDEFINED);
1043
/**********************************************************************//**
1044
Reads the space flags from the first page of a tablespace.
1048
fsp_header_get_flags(
1049
/*=================*/
1050
const page_t* page) /*!< in: first page of a tablespace */
1052
ut_ad(!page_offset(page));
1054
return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
1057
/**********************************************************************//**
1058
Reads the compressed page size from the first page of a tablespace.
1059
@return compressed page size in bytes, or 0 if uncompressed */
1062
fsp_header_get_zip_size(
1063
/*====================*/
1064
const page_t* page) /*!< in: first page of a tablespace */
1066
ulint flags = fsp_header_get_flags(page);
1068
return(dict_table_flags_to_zip_size(flags));
1071
#ifndef UNIV_HOTBACKUP
1072
/**********************************************************************//**
1073
Increases the space size field of a space. */
1076
fsp_header_inc_size(
1077
/*================*/
1078
ulint space, /*!< in: space id */
1079
ulint size_inc,/*!< in: size increment in pages */
1080
mtr_t* mtr) /*!< in: mini-transaction handle */
1082
fsp_header_t* header;
1088
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
1090
header = fsp_get_space_header(space,
1091
dict_table_flags_to_zip_size(flags),
1094
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1096
mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
1100
/**********************************************************************//**
1101
Gets the current free limit of the system tablespace. The free limit
1102
means the place of the first page which has never been put to the the
1103
free list for allocation. The space above that address is initialized
1104
to zero. Sets also the global variable log_fsp_current_free_limit.
1105
@return free limit in megabytes */
1108
fsp_header_get_free_limit(void)
1109
/*===========================*/
1111
fsp_header_t* header;
1117
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1119
header = fsp_get_space_header(0, 0, &mtr);
1121
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1123
limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
1125
log_fsp_current_free_limit_set_and_checkpoint(limit);
1132
/**********************************************************************//**
1133
Gets the size of the system tablespace from the tablespace header. If
1134
we do not have an auto-extending data file, this should be equal to
1135
the size of the data files. If there is an auto-extending data file,
1136
this can be smaller.
1137
@return size in pages */
1140
fsp_header_get_tablespace_size(void)
1141
/*================================*/
1143
fsp_header_t* header;
1149
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1151
header = fsp_get_space_header(0, 0, &mtr);
1153
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1160
/***********************************************************************//**
1161
Tries to extend a single-table tablespace so that a page would fit in the
1163
@return TRUE if success */
1166
fsp_try_extend_data_file_with_pages(
1167
/*================================*/
1168
ulint space, /*!< in: space */
1169
ulint page_no, /*!< in: page number */
1170
fsp_header_t* header, /*!< in: space header */
1171
mtr_t* mtr) /*!< in: mtr */
1179
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1181
ut_a(page_no >= size);
1183
success = fil_extend_space_to_desired_size(&actual_size, space,
1185
/* actual_size now has the space size in pages; it may be less than
1186
we wanted if we ran out of disk space */
1188
mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1193
/***********************************************************************//**
1194
Tries to extend the last data file of a tablespace if it is auto-extending.
1195
@return FALSE if not auto-extending */
1198
fsp_try_extend_data_file(
1199
/*=====================*/
1200
ulint* actual_increase,/*!< out: actual increase in pages, where
1201
we measure the tablespace size from
1202
what the header field says; it may be
1203
the actual file size rounded down to
1205
ulint space, /*!< in: space */
1206
fsp_header_t* header, /*!< in: space header */
1207
mtr_t* mtr) /*!< in: mtr */
1213
ulint size_increase;
1217
*actual_increase = 0;
1219
if (space == 0 && !srv_auto_extend_last_data_file) {
1224
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1225
zip_size = dict_table_flags_to_zip_size(
1226
mach_read_from_4(header + FSP_SPACE_FLAGS));
1231
if (!srv_last_file_size_max) {
1232
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1234
if (srv_last_file_size_max
1235
< srv_data_file_sizes[srv_n_data_files - 1]) {
1238
"InnoDB: Error: Last data file size"
1239
" is %lu, max size allowed %lu\n",
1240
(ulong) srv_data_file_sizes[
1241
srv_n_data_files - 1],
1242
(ulong) srv_last_file_size_max);
1245
size_increase = srv_last_file_size_max
1246
- srv_data_file_sizes[srv_n_data_files - 1];
1247
if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1248
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1252
/* We extend single-table tablespaces first one extent
1253
at a time, but for bigger tablespaces more. It is not
1254
enough to extend always by one extent, because some
1255
extents are frag page extents. */
1256
ulint extent_size; /*!< one megabyte, in pages */
1259
extent_size = FSP_EXTENT_SIZE;
1261
extent_size = FSP_EXTENT_SIZE
1262
* UNIV_PAGE_SIZE / zip_size;
1265
if (size < extent_size) {
1266
/* Let us first extend the file to extent_size */
1267
success = fsp_try_extend_data_file_with_pages(
1268
space, extent_size - 1, header, mtr);
1270
new_size = mtr_read_ulint(header + FSP_SIZE,
1273
*actual_increase = new_size - old_size;
1281
if (size < 32 * extent_size) {
1282
size_increase = extent_size;
1284
/* Below in fsp_fill_free_list() we assume
1285
that we add at most FSP_FREE_ADD extents at
1287
size_increase = FSP_FREE_ADD * extent_size;
1291
if (size_increase == 0) {
1296
success = fil_extend_space_to_desired_size(&actual_size, space,
1297
size + size_increase);
1298
/* We ignore any fragments of a full megabyte when storing the size
1299
to the space header */
1302
new_size = ut_calc_align_down(actual_size,
1303
(1024 * 1024) / UNIV_PAGE_SIZE);
1305
new_size = ut_calc_align_down(actual_size,
1306
(1024 * 1024) / zip_size);
1308
mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1310
*actual_increase = new_size - old_size;
1315
/**********************************************************************//**
1316
Puts new extents to the free list if there are free extents above the free
1317
limit. If an extent happens to contain an extent descriptor page, the extent
1318
is put to the FSP_FREE_FRAG list with the page marked as used. */
1323
ibool init_space, /*!< in: TRUE if this is a single-table
1324
tablespace and we are only initing
1325
the tablespace's first extent
1326
descriptor page and ibuf bitmap page;
1327
then we do not allocate more extents */
1328
ulint space, /*!< in: space */
1329
fsp_header_t* header, /*!< in: space header */
1330
mtr_t* mtr) /*!< in: mtr */
1338
ulint actual_increase;
1342
ut_ad(header && mtr);
1343
ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
1345
/* Check if we can fill free list from above the free list limit */
1346
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1347
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1349
zip_size = dict_table_flags_to_zip_size(
1350
mach_read_from_4(FSP_SPACE_FLAGS + header));
1351
ut_a(ut_is_2pow(zip_size));
1352
ut_a(zip_size <= UNIV_PAGE_SIZE);
1353
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
1355
if (space == 0 && srv_auto_extend_last_data_file
1356
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1358
/* Try to increase the last data file size */
1359
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1360
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1363
if (space != 0 && !init_space
1364
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1366
/* Try to increase the .ibd file size */
1367
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1368
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1373
while ((init_space && i < 1)
1374
|| ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1378
init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1380
init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1383
mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1386
/* Update the free limit info in the log system and make
1390
log_fsp_current_free_limit_set_and_checkpoint(
1391
(i + FSP_EXTENT_SIZE)
1392
/ ((1024 * 1024) / UNIV_PAGE_SIZE));
1395
if (UNIV_UNLIKELY(init_xdes)) {
1399
/* We are going to initialize a new descriptor page
1400
and a new ibuf bitmap page: the prior contents of the
1401
pages should be ignored. */
1404
block = buf_page_create(
1405
space, i, zip_size, mtr);
1406
buf_page_get(space, zip_size, i,
1408
buf_block_dbg_add_level(block,
1411
fsp_init_file_page(block, mtr);
1412
mlog_write_ulint(buf_block_get_frame(block)
1418
/* Initialize the ibuf bitmap page in a separate
1419
mini-transaction because it is low in the latching
1420
order, and we must be able to release its latch
1421
before returning from the fsp routine */
1423
mtr_start(&ibuf_mtr);
1425
block = buf_page_create(space,
1426
i + FSP_IBUF_BITMAP_OFFSET,
1427
zip_size, &ibuf_mtr);
1428
buf_page_get(space, zip_size,
1429
i + FSP_IBUF_BITMAP_OFFSET,
1430
RW_X_LATCH, &ibuf_mtr);
1431
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1433
fsp_init_file_page(block, &ibuf_mtr);
1435
ibuf_bitmap_page_init(block, &ibuf_mtr);
1437
mtr_commit(&ibuf_mtr);
1440
descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1442
xdes_init(descr, mtr);
1444
#if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
1445
# error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
1447
#if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
1448
# error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
1451
if (UNIV_UNLIKELY(init_xdes)) {
1453
/* The first page in the extent is a descriptor page
1454
and the second is an ibuf bitmap page: mark them
1457
xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1458
xdes_set_bit(descr, XDES_FREE_BIT,
1459
FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1460
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1462
flst_add_last(header + FSP_FREE_FRAG,
1463
descr + XDES_FLST_NODE, mtr);
1464
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1466
mlog_write_ulint(header + FSP_FRAG_N_USED,
1467
frag_n_used + 2, MLOG_4BYTES, mtr);
1469
flst_add_last(header + FSP_FREE,
1470
descr + XDES_FLST_NODE, mtr);
1474
i += FSP_EXTENT_SIZE;
1478
/**********************************************************************//**
1479
Allocates a new free extent.
1480
@return extent descriptor, NULL if cannot be allocated */
1483
fsp_alloc_free_extent(
1484
/*==================*/
1485
ulint space, /*!< in: space id */
1486
ulint zip_size,/*!< in: compressed page size in bytes
1487
or 0 for uncompressed pages */
1488
ulint hint, /*!< in: hint of which extent would be desirable: any
1489
page offset in the extent goes; the hint must not
1490
be > FSP_FREE_LIMIT */
1491
mtr_t* mtr) /*!< in: mtr */
1493
fsp_header_t* header;
1499
header = fsp_get_space_header(space, zip_size, mtr);
1501
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1503
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1504
/* Ok, we can take this extent */
1506
/* Take the first extent in the free list */
1507
first = flst_get_first(header + FSP_FREE, mtr);
1509
if (fil_addr_is_null(first)) {
1510
fsp_fill_free_list(FALSE, space, header, mtr);
1512
first = flst_get_first(header + FSP_FREE, mtr);
1515
if (fil_addr_is_null(first)) {
1517
return(NULL); /* No free extents left */
1520
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1523
flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1528
/**********************************************************************//**
1529
Allocates a single free page from a space. The page is marked as used.
1530
@return the page offset, FIL_NULL if no page could be allocated */
1533
fsp_alloc_free_page(
1534
/*================*/
1535
ulint space, /*!< in: space id */
1536
ulint zip_size,/*!< in: compressed page size in bytes
1537
or 0 for uncompressed pages */
1538
ulint hint, /*!< in: hint of which page would be desirable */
1539
mtr_t* mtr) /*!< in: mtr handle */
1541
fsp_header_t* header;
1553
header = fsp_get_space_header(space, zip_size, mtr);
1555
/* Get the hinted descriptor */
1556
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1558
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1559
/* Ok, we can take this extent */
1561
/* Else take the first extent in free_frag list */
1562
first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1564
if (fil_addr_is_null(first)) {
1565
/* There are no partially full fragments: allocate
1566
a free extent and add it to the FREE_FRAG list. NOTE
1567
that the allocation may have as a side-effect that an
1568
extent containing a descriptor page is added to the
1569
FREE_FRAG list. But we will allocate our page from the
1570
the free extent anyway. */
1572
descr = fsp_alloc_free_extent(space, zip_size,
1575
if (descr == NULL) {
1576
/* No free space left */
1581
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1582
flst_add_last(header + FSP_FREE_FRAG,
1583
descr + XDES_FLST_NODE, mtr);
1585
descr = xdes_lst_get_descriptor(space, zip_size,
1589
/* Reset the hint */
1593
/* Now we have in descr an extent with at least one free page. Look
1594
for a free page in the extent. */
1596
free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1597
hint % FSP_EXTENT_SIZE, mtr);
1598
if (free == ULINT_UNDEFINED) {
1600
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1606
page_no = xdes_get_offset(descr) + free;
1608
space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1610
if (space_size <= page_no) {
1611
/* It must be that we are extending a single-table tablespace
1612
whose size is still < 64 pages */
1615
if (page_no >= FSP_EXTENT_SIZE) {
1617
"InnoDB: Error: trying to extend a"
1618
" single-table tablespace %lu\n"
1619
"InnoDB: by single page(s) though the"
1620
" space size %lu. Page no %lu.\n",
1621
(ulong) space, (ulong) space_size,
1625
success = fsp_try_extend_data_file_with_pages(space, page_no,
1628
/* No disk space left */
1633
xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1635
/* Update the FRAG_N_USED field */
1636
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1639
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1641
if (xdes_is_full(descr, mtr)) {
1642
/* The fragment is full: move it to another list */
1643
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1645
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1647
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1649
mlog_write_ulint(header + FSP_FRAG_N_USED,
1650
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1654
/* Initialize the allocated page to the buffer pool, so that it can
1655
be obtained immediately with buf_page_get without need for a disk
1658
buf_page_create(space, page_no, zip_size, mtr);
1660
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1661
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1663
/* Prior contents of the page should be ignored */
1664
fsp_init_file_page(block, mtr);
1669
/**********************************************************************//**
1670
Frees a single page of a space. The page is marked as free and clean. */
1675
ulint space, /*!< in: space id */
1676
ulint zip_size,/*!< in: compressed page size in bytes
1677
or 0 for uncompressed pages */
1678
ulint page, /*!< in: page offset */
1679
mtr_t* mtr) /*!< in: mtr handle */
1681
fsp_header_t* header;
1688
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1690
header = fsp_get_space_header(space, zip_size, mtr);
1692
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1694
state = xdes_get_state(descr, mtr);
1696
if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1698
"InnoDB: Error: File space extent descriptor"
1699
" of page %lu has state %lu\n",
1702
fputs("InnoDB: Dump of descriptor: ", stderr);
1703
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1706
if (state == XDES_FREE) {
1707
/* We put here some fault tolerance: if the page
1708
is already free, return without doing anything! */
1716
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1718
"InnoDB: Error: File space extent descriptor"
1719
" of page %lu says it is free\n"
1720
"InnoDB: Dump of descriptor: ", (ulong) page);
1721
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1724
/* We put here some fault tolerance: if the page
1725
is already free, return without doing anything! */
1730
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1731
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1733
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1735
if (state == XDES_FULL_FRAG) {
1736
/* The fragment was full: move it to another list */
1737
flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1739
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1740
flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1742
mlog_write_ulint(header + FSP_FRAG_N_USED,
1743
frag_n_used + FSP_EXTENT_SIZE - 1,
1746
ut_a(frag_n_used > 0);
1747
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1751
if (xdes_is_free(descr, mtr)) {
1752
/* The extent has become free: move it to another list */
1753
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1755
fsp_free_extent(space, zip_size, page, mtr);
1759
/**********************************************************************//**
1760
Returns an extent to the free list of a space. */
1765
ulint space, /*!< in: space id */
1766
ulint zip_size,/*!< in: compressed page size in bytes
1767
or 0 for uncompressed pages */
1768
ulint page, /*!< in: page offset in the extent */
1769
mtr_t* mtr) /*!< in: mtr */
1771
fsp_header_t* header;
1776
header = fsp_get_space_header(space, zip_size, mtr);
1778
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1780
if (xdes_get_state(descr, mtr) == XDES_FREE) {
1782
ut_print_buf(stderr, (byte*)descr - 500, 1000);
1788
xdes_init(descr, mtr);
1790
flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1793
/**********************************************************************//**
1794
Returns the nth inode slot on an inode page.
1795
@return segment inode */
1798
fsp_seg_inode_page_get_nth_inode(
1799
/*=============================*/
1800
page_t* page, /*!< in: segment inode page */
1801
ulint i, /*!< in: inode index on page */
1802
ulint zip_size __attribute__((unused)),
1803
/*!< in: compressed page size, or 0 */
1804
mtr_t* mtr __attribute__((unused)))
1805
/*!< in: mini-transaction handle */
1807
ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1808
ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1810
return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1813
/**********************************************************************//**
1814
Looks for a used segment inode on a segment inode page.
1815
@return segment inode index, or ULINT_UNDEFINED if not found */
1818
fsp_seg_inode_page_find_used(
1819
/*=========================*/
1820
page_t* page, /*!< in: segment inode page */
1821
ulint zip_size,/*!< in: compressed page size, or 0 */
1822
mtr_t* mtr) /*!< in: mini-transaction handle */
1825
fseg_inode_t* inode;
1827
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1829
inode = fsp_seg_inode_page_get_nth_inode(
1830
page, i, zip_size, mtr);
1832
if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
1839
return(ULINT_UNDEFINED);
1842
/**********************************************************************//**
1843
Looks for an unused segment inode on a segment inode page.
1844
@return segment inode index, or ULINT_UNDEFINED if not found */
1847
fsp_seg_inode_page_find_free(
1848
/*=========================*/
1849
page_t* page, /*!< in: segment inode page */
1850
ulint i, /*!< in: search forward starting from this index */
1851
ulint zip_size,/*!< in: compressed page size, or 0 */
1852
mtr_t* mtr) /*!< in: mini-transaction handle */
1854
fseg_inode_t* inode;
1856
for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1858
inode = fsp_seg_inode_page_get_nth_inode(
1859
page, i, zip_size, mtr);
1861
if (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
1862
/* This is unused */
1868
return(ULINT_UNDEFINED);
1871
/**********************************************************************//**
1872
Allocates a new file segment inode page.
1873
@return TRUE if could be allocated */
1876
fsp_alloc_seg_inode_page(
1877
/*=====================*/
1878
fsp_header_t* space_header, /*!< in: space header */
1879
mtr_t* mtr) /*!< in: mini-transaction handle */
1881
fseg_inode_t* inode;
1889
ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1891
space = page_get_space_id(page_align(space_header));
1892
zip_size = dict_table_flags_to_zip_size(
1893
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1895
page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
1897
if (page_no == FIL_NULL) {
1902
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1903
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1905
block->check_index_page_at_flush = FALSE;
1907
page = buf_block_get_frame(block);
1909
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
1912
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1914
inode = fsp_seg_inode_page_get_nth_inode(page, i,
1917
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
1920
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1921
page + FSEG_INODE_PAGE_NODE, mtr);
1925
/**********************************************************************//**
1926
Allocates a new file segment inode.
1927
@return segment inode, or NULL if not enough space */
1930
fsp_alloc_seg_inode(
1931
/*================*/
1932
fsp_header_t* space_header, /*!< in: space header */
1933
mtr_t* mtr) /*!< in: mini-transaction handle */
1938
fseg_inode_t* inode;
1943
ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1945
if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1946
/* Allocate a new segment inode page */
1948
success = fsp_alloc_seg_inode_page(space_header, mtr);
1956
page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1958
zip_size = dict_table_flags_to_zip_size(
1959
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1960
block = buf_page_get(page_get_space_id(page_align(space_header)),
1961
zip_size, page_no, RW_X_LATCH, mtr);
1962
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1964
page = buf_block_get_frame(block);
1966
n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1968
ut_a(n != ULINT_UNDEFINED);
1970
inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1972
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1974
/* There are no other unused headers left on the page: move it
1977
flst_remove(space_header + FSP_SEG_INODES_FREE,
1978
page + FSEG_INODE_PAGE_NODE, mtr);
1980
flst_add_last(space_header + FSP_SEG_INODES_FULL,
1981
page + FSEG_INODE_PAGE_NODE, mtr);
1987
/**********************************************************************//**
1988
Frees a file segment inode. */
1993
ulint space, /*!< in: space id */
1994
ulint zip_size,/*!< in: compressed page size in bytes
1995
or 0 for uncompressed pages */
1996
fseg_inode_t* inode, /*!< in: segment inode */
1997
mtr_t* mtr) /*!< in: mini-transaction handle */
2000
fsp_header_t* space_header;
2002
page = page_align(inode);
2004
space_header = fsp_get_space_header(space, zip_size, mtr);
2006
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2009
== fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
2011
/* Move the page to another list */
2013
flst_remove(space_header + FSP_SEG_INODES_FULL,
2014
page + FSEG_INODE_PAGE_NODE, mtr);
2016
flst_add_last(space_header + FSP_SEG_INODES_FREE,
2017
page + FSEG_INODE_PAGE_NODE, mtr);
2020
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
2021
mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr);
2024
== fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
2026
/* There are no other used headers left on the page: free it */
2028
flst_remove(space_header + FSP_SEG_INODES_FREE,
2029
page + FSEG_INODE_PAGE_NODE, mtr);
2031
fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
2035
/**********************************************************************//**
2036
Returns the file segment inode, page x-latched.
2037
@return segment inode, page x-latched */
2042
fseg_header_t* header, /*!< in: segment header */
2043
ulint space, /*!< in: space id */
2044
ulint zip_size,/*!< in: compressed page size in bytes
2045
or 0 for uncompressed pages */
2046
mtr_t* mtr) /*!< in: mtr handle */
2048
fil_addr_t inode_addr;
2049
fseg_inode_t* inode;
2051
inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
2052
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
2053
ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
2055
inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
2057
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2062
/**********************************************************************//**
2063
Gets the page number from the nth fragment page slot.
2064
@return page number, FIL_NULL if not in use */
2067
fseg_get_nth_frag_page_no(
2068
/*======================*/
2069
fseg_inode_t* inode, /*!< in: segment inode */
2070
ulint n, /*!< in: slot index */
2071
mtr_t* mtr __attribute__((unused))) /*!< in: mtr handle */
2073
ut_ad(inode && mtr);
2074
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2075
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2076
return(mach_read_from_4(inode + FSEG_FRAG_ARR
2077
+ n * FSEG_FRAG_SLOT_SIZE));
2080
/**********************************************************************//**
2081
Sets the page number in the nth fragment page slot. */
2084
fseg_set_nth_frag_page_no(
2085
/*======================*/
2086
fseg_inode_t* inode, /*!< in: segment inode */
2087
ulint n, /*!< in: slot index */
2088
ulint page_no,/*!< in: page number to set */
2089
mtr_t* mtr) /*!< in: mtr handle */
2091
ut_ad(inode && mtr);
2092
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2093
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2095
mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
2096
page_no, MLOG_4BYTES, mtr);
2099
/**********************************************************************//**
2100
Finds a fragment page slot which is free.
2101
@return slot index; ULINT_UNDEFINED if none found */
2104
fseg_find_free_frag_page_slot(
2105
/*==========================*/
2106
fseg_inode_t* inode, /*!< in: segment inode */
2107
mtr_t* mtr) /*!< in: mtr handle */
2112
ut_ad(inode && mtr);
2114
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2115
page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
2117
if (page_no == FIL_NULL) {
2123
return(ULINT_UNDEFINED);
2126
/**********************************************************************//**
2127
Finds a fragment page slot which is used and last in the array.
2128
@return slot index; ULINT_UNDEFINED if none found */
2131
fseg_find_last_used_frag_page_slot(
2132
/*===============================*/
2133
fseg_inode_t* inode, /*!< in: segment inode */
2134
mtr_t* mtr) /*!< in: mtr handle */
2139
ut_ad(inode && mtr);
2141
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2142
page_no = fseg_get_nth_frag_page_no(
2143
inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
2145
if (page_no != FIL_NULL) {
2147
return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
2151
return(ULINT_UNDEFINED);
2154
/**********************************************************************//**
2155
Calculates reserved fragment page slots.
2156
@return number of fragment pages */
2159
fseg_get_n_frag_pages(
2160
/*==================*/
2161
fseg_inode_t* inode, /*!< in: segment inode */
2162
mtr_t* mtr) /*!< in: mtr handle */
2167
ut_ad(inode && mtr);
2169
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2170
if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2178
/**********************************************************************//**
2179
Creates a new segment.
2180
@return the block where the segment header is placed, x-latched, NULL
2181
if could not create segment because of lack of space */
2184
fseg_create_general(
2185
/*================*/
2186
ulint space, /*!< in: space id */
2187
ulint page, /*!< in: page where the segment header is placed: if
2188
this is != 0, the page must belong to another segment,
2189
if this is 0, a new page will be allocated and it
2190
will belong to the created segment */
2191
ulint byte_offset, /*!< in: byte offset of the created segment header
2193
ibool has_done_reservation, /*!< in: TRUE if the caller has already
2194
done the reservation for the pages with
2195
fsp_reserve_free_extents (at least 2 extents: one for
2196
the inode and the other for the segment) then there is
2197
no need to do the check for this individual
2199
mtr_t* mtr) /*!< in: mtr */
2203
fsp_header_t* space_header;
2204
fseg_inode_t* inode;
2206
buf_block_t* block = 0; /* remove warning */
2207
fseg_header_t* header = 0; /* remove warning */
2214
ut_ad(byte_offset + FSEG_HEADER_SIZE
2215
<= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2217
latch = fil_space_get_latch(space, &flags);
2218
zip_size = dict_table_flags_to_zip_size(flags);
2221
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2222
header = byte_offset + buf_block_get_frame(block);
2225
ut_ad(!mutex_own(&kernel_mutex)
2226
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2228
mtr_x_lock(latch, mtr);
2230
if (rw_lock_get_x_lock_count(latch) == 1) {
2231
/* This thread did not own the latch before this call: free
2232
excess pages from the insert buffer free list */
2234
if (space == IBUF_SPACE_ID) {
2235
ibuf_free_excess_pages();
2239
if (!has_done_reservation) {
2240
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2247
space_header = fsp_get_space_header(space, zip_size, mtr);
2249
inode = fsp_alloc_seg_inode(space_header, mtr);
2251
if (inode == NULL) {
2256
/* Read the next segment id from space header and increment the
2257
value in space header */
2259
seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, mtr);
2261
mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1),
2264
mlog_write_dulint(inode + FSEG_ID, seg_id, mtr);
2265
mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2267
flst_init(inode + FSEG_FREE, mtr);
2268
flst_init(inode + FSEG_NOT_FULL, mtr);
2269
flst_init(inode + FSEG_FULL, mtr);
2271
mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2273
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2274
fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2278
page = fseg_alloc_free_page_low(space, zip_size,
2279
inode, 0, FSP_UP, mtr);
2281
if (page == FIL_NULL) {
2283
fsp_free_seg_inode(space, zip_size, inode, mtr);
2288
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2289
header = byte_offset + buf_block_get_frame(block);
2290
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2291
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
2294
mlog_write_ulint(header + FSEG_HDR_OFFSET,
2295
page_offset(inode), MLOG_2BYTES, mtr);
2297
mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2298
page_get_page_no(page_align(inode)),
2301
mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2304
if (!has_done_reservation) {
2306
fil_space_release_free_extents(space, n_reserved);
2312
/**********************************************************************//**
2313
Creates a new segment.
2314
@return the block where the segment header is placed, x-latched, NULL
2315
if could not create segment because of lack of space */
2320
ulint space, /*!< in: space id */
2321
ulint page, /*!< in: page where the segment header is placed: if
2322
this is != 0, the page must belong to another segment,
2323
if this is 0, a new page will be allocated and it
2324
will belong to the created segment */
2325
ulint byte_offset, /*!< in: byte offset of the created segment header
2327
mtr_t* mtr) /*!< in: mtr */
2329
return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2332
/**********************************************************************//**
2333
Calculates the number of pages reserved by a segment, and how many pages are
2335
@return number of reserved pages */
2338
fseg_n_reserved_pages_low(
2339
/*======================*/
2340
fseg_inode_t* inode, /*!< in: segment inode */
2341
ulint* used, /*!< out: number of pages used (not
2342
more than reserved) */
2343
mtr_t* mtr) /*!< in: mtr handle */
2347
ut_ad(inode && used && mtr);
2348
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2350
*used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2351
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2352
+ fseg_get_n_frag_pages(inode, mtr);
2354
ret = fseg_get_n_frag_pages(inode, mtr)
2355
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2356
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2357
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2362
/**********************************************************************//**
2363
Calculates the number of pages reserved by a segment, and how many pages are
2365
@return number of reserved pages */
2368
fseg_n_reserved_pages(
2369
/*==================*/
2370
fseg_header_t* header, /*!< in: segment header */
2371
ulint* used, /*!< out: number of pages used (<= reserved) */
2372
mtr_t* mtr) /*!< in: mtr handle */
2375
fseg_inode_t* inode;
2381
space = page_get_space_id(page_align(header));
2382
latch = fil_space_get_latch(space, &flags);
2383
zip_size = dict_table_flags_to_zip_size(flags);
2385
ut_ad(!mutex_own(&kernel_mutex)
2386
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2388
mtr_x_lock(latch, mtr);
2390
inode = fseg_inode_get(header, space, zip_size, mtr);
2392
ret = fseg_n_reserved_pages_low(inode, used, mtr);
2397
/*********************************************************************//**
2398
Tries to fill the free list of a segment with consecutive free extents.
2399
This happens if the segment is big enough to allow extents in the free list,
2400
the free list is empty, and the extents can be allocated consecutively from
2404
fseg_fill_free_list(
2405
/*================*/
2406
fseg_inode_t* inode, /*!< in: segment inode */
2407
ulint space, /*!< in: space id */
2408
ulint zip_size,/*!< in: compressed page size in bytes
2409
or 0 for uncompressed pages */
2410
ulint hint, /*!< in: hint which extent would be good as
2412
mtr_t* mtr) /*!< in: mtr */
2420
ut_ad(inode && mtr);
2421
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2423
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2425
if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2427
/* The segment is too small to allow extents in free list */
2432
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2433
/* Free list is not empty */
2438
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2439
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2442
|| (XDES_FREE != xdes_get_state(descr, mtr))) {
2444
/* We cannot allocate the desired extent: stop */
2449
descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2451
xdes_set_state(descr, XDES_FSEG, mtr);
2453
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2454
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2456
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2457
hint += FSP_EXTENT_SIZE;
2461
/*********************************************************************//**
2462
Allocates a free extent for the segment: looks first in the free list of the
2463
segment, then tries to allocate from the space free list. NOTE that the extent
2464
returned still resides in the segment free list, it is not yet taken off it!
2465
@return allocated extent, still placed in the segment free list, NULL
2466
if could not be allocated */
2469
fseg_alloc_free_extent(
2470
/*===================*/
2471
fseg_inode_t* inode, /*!< in: segment inode */
2472
ulint space, /*!< in: space id */
2473
ulint zip_size,/*!< in: compressed page size in bytes
2474
or 0 for uncompressed pages */
2475
mtr_t* mtr) /*!< in: mtr */
2481
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2483
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2484
/* Segment free list is not empty, allocate from it */
2486
first = flst_get_first(inode + FSEG_FREE, mtr);
2488
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2490
/* Segment free list was empty, allocate from space */
2491
descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2493
if (descr == NULL) {
2498
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2500
xdes_set_state(descr, XDES_FSEG, mtr);
2501
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2502
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2504
/* Try to fill the segment free list */
2505
fseg_fill_free_list(inode, space, zip_size,
2506
xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2513
/**********************************************************************//**
2514
Allocates a single free page from a segment. This function implements
2515
the intelligent allocation strategy which tries to minimize file space
2517
@return the allocated page number, FIL_NULL if no page could be allocated */
2520
fseg_alloc_free_page_low(
2521
/*=====================*/
2522
ulint space, /*!< in: space */
2523
ulint zip_size,/*!< in: compressed page size in bytes
2524
or 0 for uncompressed pages */
2525
fseg_inode_t* seg_inode, /*!< in: segment inode */
2526
ulint hint, /*!< in: hint of which page would be desirable */
2527
byte direction, /*!< in: if the new page is needed because
2528
of an index page split, and records are
2529
inserted there in order, into which
2530
direction they go alphabetically: FSP_DOWN,
2531
FSP_UP, FSP_NO_DIR */
2532
mtr_t* mtr) /*!< in: mtr handle */
2534
fsp_header_t* space_header;
2539
xdes_t* descr; /*!< extent of the hinted page */
2540
ulint ret_page; /*!< the allocated page offset, FIL_NULL
2541
if could not be allocated */
2542
xdes_t* ret_descr; /*!< the extent of the allocated page */
2543
ibool frag_page_allocated = FALSE;
2548
ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2549
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2550
== FSEG_MAGIC_N_VALUE);
2551
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2552
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
2554
ut_ad(!ut_dulint_is_zero(seg_id));
2556
reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2558
space_header = fsp_get_space_header(space, zip_size, mtr);
2560
descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2562
if (descr == NULL) {
2563
/* Hint outside space or too high above free limit: reset
2566
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2569
/* In the big if-else below we look for ret_page and ret_descr */
2570
/*-------------------------------------------------------------*/
2571
if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2572
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2574
&& (xdes_get_bit(descr, XDES_FREE_BIT,
2575
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2577
/* 1. We can take the hinted page
2578
=================================*/
2581
/*-----------------------------------------------------------*/
2582
} else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2583
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2584
&& (used >= FSEG_FRAG_LIMIT)) {
2586
/* 2. We allocate the free extent from space and can take
2587
=========================================================
2590
ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2592
ut_a(ret_descr == descr);
2594
xdes_set_state(ret_descr, XDES_FSEG, mtr);
2595
mlog_write_dulint(ret_descr + XDES_ID, seg_id, mtr);
2596
flst_add_last(seg_inode + FSEG_FREE,
2597
ret_descr + XDES_FLST_NODE, mtr);
2599
/* Try to fill the segment free list */
2600
fseg_fill_free_list(seg_inode, space, zip_size,
2601
hint + FSP_EXTENT_SIZE, mtr);
2603
/*-----------------------------------------------------------*/
2604
} else if ((direction != FSP_NO_DIR)
2605
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2606
&& (used >= FSEG_FRAG_LIMIT)
2608
= fseg_alloc_free_extent(seg_inode,
2609
space, zip_size, mtr)))) {
2611
/* 3. We take any free extent (which was already assigned above
2612
===============================================================
2613
in the if-condition to ret_descr) and take the lowest or
2614
========================================================
2615
highest page in it, depending on the direction
2616
==============================================*/
2617
ret_page = xdes_get_offset(ret_descr);
2619
if (direction == FSP_DOWN) {
2620
ret_page += FSP_EXTENT_SIZE - 1;
2622
/*-----------------------------------------------------------*/
2623
} else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2624
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2626
&& (!xdes_is_full(descr, mtr))) {
2628
/* 4. We can take the page from the same extent as the
2629
======================================================
2630
hinted page (and the extent already belongs to the
2631
==================================================
2635
ret_page = xdes_get_offset(ret_descr)
2636
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2637
hint % FSP_EXTENT_SIZE, mtr);
2638
/*-----------------------------------------------------------*/
2639
} else if (reserved - used > 0) {
2640
/* 5. We take any unused page from the segment
2641
==============================================*/
2644
if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2645
first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2647
} else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2648
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2654
ret_descr = xdes_lst_get_descriptor(space, zip_size,
2656
ret_page = xdes_get_offset(ret_descr)
2657
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2659
/*-----------------------------------------------------------*/
2660
} else if (used < FSEG_FRAG_LIMIT) {
2661
/* 6. We allocate an individual page from the space
2662
===================================================*/
2663
ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
2666
frag_page_allocated = TRUE;
2668
if (ret_page != FIL_NULL) {
2669
/* Put the page in the fragment page array of the
2671
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2672
ut_a(n != FIL_NULL);
2674
fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2677
/*-----------------------------------------------------------*/
2679
/* 7. We allocate a new extent and take its first page
2680
======================================================*/
2681
ret_descr = fseg_alloc_free_extent(seg_inode,
2682
space, zip_size, mtr);
2684
if (ret_descr == NULL) {
2685
ret_page = FIL_NULL;
2687
ret_page = xdes_get_offset(ret_descr);
2691
if (ret_page == FIL_NULL) {
2692
/* Page could not be allocated */
2698
space_size = fil_space_get_size(space);
2700
if (space_size <= ret_page) {
2701
/* It must be that we are extending a single-table
2702
tablespace whose size is still < 64 pages */
2704
if (ret_page >= FSP_EXTENT_SIZE) {
2706
"InnoDB: Error (2): trying to extend"
2707
" a single-table tablespace %lu\n"
2708
"InnoDB: by single page(s) though"
2709
" the space size %lu. Page no %lu.\n",
2710
(ulong) space, (ulong) space_size,
2715
success = fsp_try_extend_data_file_with_pages(
2716
space, ret_page, space_header, mtr);
2718
/* No disk space left */
2724
if (!frag_page_allocated) {
2725
/* Initialize the allocated page to buffer pool, so that it
2726
can be obtained immediately with buf_page_get without need
2729
ulint zip_size = dict_table_flags_to_zip_size(
2730
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
2732
block = buf_page_create(space, ret_page, zip_size, mtr);
2733
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
2735
if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
2736
ret_page, RW_X_LATCH,
2741
/* The prior contents of the page should be ignored */
2742
fsp_init_file_page(block, mtr);
2744
/* At this point we know the extent and the page offset.
2745
The extent is still in the appropriate list (FSEG_NOT_FULL
2746
or FSEG_FREE), and the page is not yet marked as used. */
2748
ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
2750
ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2751
ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2753
fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
2756
buf_reset_check_index_page_at_flush(space, ret_page);
2761
/**********************************************************************//**
2762
Allocates a single free page from a segment. This function implements
2763
the intelligent allocation strategy which tries to minimize file space
2765
@return allocated page offset, FIL_NULL if no page could be allocated */
2768
fseg_alloc_free_page_general(
2769
/*=========================*/
2770
fseg_header_t* seg_header,/*!< in: segment header */
2771
ulint hint, /*!< in: hint of which page would be desirable */
2772
byte direction,/*!< in: if the new page is needed because
2773
of an index page split, and records are
2774
inserted there in order, into which
2775
direction they go alphabetically: FSP_DOWN,
2776
FSP_UP, FSP_NO_DIR */
2777
ibool has_done_reservation, /*!< in: TRUE if the caller has
2778
already done the reservation for the page
2779
with fsp_reserve_free_extents, then there
2780
is no need to do the check for this individual
2782
mtr_t* mtr) /*!< in: mtr handle */
2784
fseg_inode_t* inode;
2793
space = page_get_space_id(page_align(seg_header));
2795
latch = fil_space_get_latch(space, &flags);
2797
zip_size = dict_table_flags_to_zip_size(flags);
2799
ut_ad(!mutex_own(&kernel_mutex)
2800
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2802
mtr_x_lock(latch, mtr);
2804
if (rw_lock_get_x_lock_count(latch) == 1) {
2805
/* This thread did not own the latch before this call: free
2806
excess pages from the insert buffer free list */
2808
if (space == IBUF_SPACE_ID) {
2809
ibuf_free_excess_pages();
2813
inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2815
if (!has_done_reservation) {
2816
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2823
page_no = fseg_alloc_free_page_low(space, zip_size,
2824
inode, hint, direction, mtr);
2825
if (!has_done_reservation) {
2826
fil_space_release_free_extents(space, n_reserved);
2832
/**********************************************************************//**
2833
Allocates a single free page from a segment. This function implements
2834
the intelligent allocation strategy which tries to minimize file space
2836
@return allocated page offset, FIL_NULL if no page could be allocated */
2839
fseg_alloc_free_page(
2840
/*=================*/
2841
fseg_header_t* seg_header,/*!< in: segment header */
2842
ulint hint, /*!< in: hint of which page would be desirable */
2843
byte direction,/*!< in: if the new page is needed because
2844
of an index page split, and records are
2845
inserted there in order, into which
2846
direction they go alphabetically: FSP_DOWN,
2847
FSP_UP, FSP_NO_DIR */
2848
mtr_t* mtr) /*!< in: mtr handle */
2850
return(fseg_alloc_free_page_general(seg_header, hint, direction,
2854
/**********************************************************************//**
2855
Checks that we have at least 2 frag pages free in the first extent of a
2856
single-table tablespace, and they are also physically initialized to the data
2857
file. That is we have already extended the data file so that those pages are
2858
inside the data file. If not, this function extends the tablespace with
2860
@return TRUE if there were >= 3 free pages, or we were able to extend */
2863
fsp_reserve_free_pages(
2864
/*===================*/
2865
ulint space, /*!< in: space id, must be != 0 */
2866
fsp_header_t* space_header, /*!< in: header of that space,
2868
ulint size, /*!< in: size of the tablespace in pages,
2869
must be < FSP_EXTENT_SIZE / 2 */
2870
mtr_t* mtr) /*!< in: mtr */
2876
ut_a(size < FSP_EXTENT_SIZE / 2);
2878
descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2880
n_used = xdes_get_n_used(descr, mtr);
2882
ut_a(n_used <= size);
2884
if (size >= n_used + 2) {
2889
return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2890
space_header, mtr));
2893
/**********************************************************************//**
2894
Reserves free pages from a tablespace. All mini-transactions which may
2895
use several pages from the tablespace should call this function beforehand
2896
and reserve enough free extents so that they certainly will be able
2897
to do their operation, like a B-tree page split, fully. Reservations
2898
must be released with function fil_space_release_free_extents!
2900
The alloc_type below has the following meaning: FSP_NORMAL means an
2901
operation which will probably result in more space usage, like an
2902
insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
2903
deleting rows, then this allocation will in the long run result in
2904
less space usage (after a purge); FSP_CLEANING means allocation done
2905
in a physical record delete (like in a purge) or other cleaning operation
2906
which will result in less space usage in the long run. We prefer the latter
2907
two types of allocation: when space is scarce, FSP_NORMAL allocations
2908
will not succeed, but the latter two allocations will succeed, if possible.
2909
The purpose is to avoid dead end where the database is full but the
2910
user cannot free any space because these freeing operations temporarily
2913
Single-table tablespaces whose size is < 32 pages are a special case. In this
2914
function we would liberally reserve several 64 page extents for every page
2915
split or merge in a B-tree. But we do not want to waste disk space if the table
2916
only occupies < 32 pages. That is why we apply different rules in that special
2917
case, just ensuring that there are 3 free pages available.
2918
@return TRUE if we were able to make the reservation */
2921
fsp_reserve_free_extents(
2922
/*=====================*/
2923
ulint* n_reserved,/*!< out: number of extents actually reserved; if we
2924
return TRUE and the tablespace size is < 64 pages,
2925
then this can be 0, otherwise it is n_ext */
2926
ulint space, /*!< in: space id */
2927
ulint n_ext, /*!< in: number of extents to reserve */
2928
ulint alloc_type,/*!< in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
2929
mtr_t* mtr) /*!< in: mtr */
2931
fsp_header_t* space_header;
2933
ulint n_free_list_ext;
2942
ulint n_pages_added;
2945
*n_reserved = n_ext;
2947
latch = fil_space_get_latch(space, &flags);
2948
zip_size = dict_table_flags_to_zip_size(flags);
2950
ut_ad(!mutex_own(&kernel_mutex)
2951
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2953
mtr_x_lock(latch, mtr);
2955
space_header = fsp_get_space_header(space, zip_size, mtr);
2957
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
2959
if (size < FSP_EXTENT_SIZE / 2) {
2960
/* Use different rules for small single-table tablespaces */
2962
return(fsp_reserve_free_pages(space, space_header, size, mtr));
2965
n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
2967
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
2970
/* Below we play safe when counting free extents above the free limit:
2971
some of them will contain extent descriptor pages, and therefore
2972
will not be free extents */
2974
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
2976
if (n_free_up > 0) {
2979
n_free_up -= n_free_up
2980
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
2982
n_free_up -= n_free_up
2983
/ (zip_size / FSP_EXTENT_SIZE);
2987
n_free = n_free_list_ext + n_free_up;
2989
if (alloc_type == FSP_NORMAL) {
2990
/* We reserve 1 extent + 0.5 % of the space size to undo logs
2991
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
2992
code is duplicated in the function below! */
2994
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
2996
if (n_free <= reserve + n_ext) {
3000
} else if (alloc_type == FSP_UNDO) {
3001
/* We reserve 0.5 % of the space size to cleaning operations */
3003
reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
3005
if (n_free <= reserve + n_ext) {
3010
ut_a(alloc_type == FSP_CLEANING);
3013
success = fil_space_reserve_free_extents(space, n_free, n_ext);
3019
success = fsp_try_extend_data_file(&n_pages_added, space,
3021
if (success && n_pages_added > 0) {
3029
/**********************************************************************//**
3030
This function should be used to get information on how much we still
3031
will be able to insert new data to the database without running out the
3032
tablespace. Only free extents are taken into account and we also subtract
3033
the safety margin required by the above function fsp_reserve_free_extents.
3034
@return available space in kB */
3037
fsp_get_available_space_in_free_extents(
3038
/*====================================*/
3039
ulint space) /*!< in: space id */
3041
fsp_header_t* space_header;
3042
ulint n_free_list_ext;
3053
ut_ad(!mutex_own(&kernel_mutex));
3057
latch = fil_space_get_latch(space, &flags);
3058
zip_size = dict_table_flags_to_zip_size(flags);
3060
mtr_x_lock(latch, &mtr);
3062
space_header = fsp_get_space_header(space, zip_size, &mtr);
3064
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
3066
n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
3068
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3072
if (size < FSP_EXTENT_SIZE) {
3073
ut_a(space != 0); /* This must be a single-table
3076
return(0); /* TODO: count free frag pages and
3077
return a value based on that */
3080
/* Below we play safe when counting free extents above the free limit:
3081
some of them will contain extent descriptor pages, and therefore
3082
will not be free extents */
3084
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3086
if (n_free_up > 0) {
3089
n_free_up -= n_free_up
3090
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3092
n_free_up -= n_free_up
3093
/ (zip_size / FSP_EXTENT_SIZE);
3097
n_free = n_free_list_ext + n_free_up;
3099
/* We reserve 1 extent + 0.5 % of the space size to undo logs
3100
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3101
code is duplicated in the function above! */
3103
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3105
if (reserve > n_free) {
3110
return((ullint) (n_free - reserve)
3112
* (UNIV_PAGE_SIZE / 1024));
3114
return((ullint) (n_free - reserve)
3116
* (zip_size / 1024));
3120
/********************************************************************//**
3121
Marks a page used. The page must reside within the extents of the given
3125
fseg_mark_page_used(
3126
/*================*/
3127
fseg_inode_t* seg_inode,/*!< in: segment inode */
3128
ulint space, /*!< in: space id */
3129
ulint zip_size,/*!< in: compressed page size in bytes
3130
or 0 for uncompressed pages */
3131
ulint page, /*!< in: page offset */
3132
mtr_t* mtr) /*!< in: mtr */
3135
ulint not_full_n_used;
3137
ut_ad(seg_inode && mtr);
3138
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3140
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3142
ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
3143
== mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
3145
if (xdes_is_free(descr, mtr)) {
3146
/* We move the extent from the free list to the
3148
flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3150
flst_add_last(seg_inode + FSEG_NOT_FULL,
3151
descr + XDES_FLST_NODE, mtr);
3154
ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
3156
/* We mark the page as used */
3157
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3159
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3162
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3164
if (xdes_is_full(descr, mtr)) {
3165
/* We move the extent from the NOT_FULL list to the
3167
flst_remove(seg_inode + FSEG_NOT_FULL,
3168
descr + XDES_FLST_NODE, mtr);
3169
flst_add_last(seg_inode + FSEG_FULL,
3170
descr + XDES_FLST_NODE, mtr);
3172
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3173
not_full_n_used - FSP_EXTENT_SIZE,
3178
/**********************************************************************//**
3179
Frees a single page of a segment. */
3184
fseg_inode_t* seg_inode, /*!< in: segment inode */
3185
ulint space, /*!< in: space id */
3186
ulint zip_size,/*!< in: compressed page size in bytes
3187
or 0 for uncompressed pages */
3188
ulint page, /*!< in: page offset */
3189
mtr_t* mtr) /*!< in: mtr handle */
3192
ulint not_full_n_used;
3198
ut_ad(seg_inode && mtr);
3199
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3200
== FSEG_MAGIC_N_VALUE);
3201
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3203
/* Drop search system page hash index if the page is found in
3204
the pool and is hashed */
3206
btr_search_drop_page_hash_when_freed(space, zip_size, page);
3208
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3211
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
3212
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3214
ut_print_buf(stderr, descr, 40);
3216
fprintf(stderr, "\n"
3217
"InnoDB: Serious error! InnoDB is trying to"
3219
"InnoDB: though it is already marked as free"
3220
" in the tablespace!\n"
3221
"InnoDB: The tablespace free space info is corrupt.\n"
3222
"InnoDB: You may need to dump your"
3223
" InnoDB tables and recreate the whole\n"
3224
"InnoDB: database!\n", (ulong) page);
3226
fputs("InnoDB: Please refer to\n"
3227
"InnoDB: " REFMAN "forcing-recovery.html\n"
3228
"InnoDB: about forcing recovery.\n", stderr);
3232
state = xdes_get_state(descr, mtr);
3234
if (state != XDES_FSEG) {
3235
/* The page is in the fragment pages of the segment */
3238
if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3241
fseg_set_nth_frag_page_no(seg_inode, i,
3247
fsp_free_page(space, zip_size, page, mtr);
3252
/* If we get here, the page is in some extent of the segment */
3254
descr_id = mtr_read_dulint(descr + XDES_ID, mtr);
3255
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
3258
"InnoDB: InnoDB is freeing space %lu page %lu,\n"
3259
"InnoDB: which belongs to descr seg %lu %lu\n"
3260
"InnoDB: segment %lu %lu.\n",
3261
(ulong) space, (ulong) page,
3262
(ulong) ut_dulint_get_high(descr_id),
3263
(ulong) ut_dulint_get_low(descr_id),
3264
(ulong) ut_dulint_get_high(seg_id),
3265
(ulong) ut_dulint_get_low(seg_id));
3267
if (0 != ut_dulint_cmp(descr_id, seg_id)) {
3268
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3270
ut_print_buf(stderr, descr, 40);
3271
fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3272
ut_print_buf(stderr, seg_inode, 40);
3276
"InnoDB: Serious error: InnoDB is trying to"
3277
" free space %lu page %lu,\n"
3278
"InnoDB: which does not belong to"
3279
" segment %lu %lu but belongs\n"
3280
"InnoDB: to segment %lu %lu.\n",
3281
(ulong) space, (ulong) page,
3282
(ulong) ut_dulint_get_high(descr_id),
3283
(ulong) ut_dulint_get_low(descr_id),
3284
(ulong) ut_dulint_get_high(seg_id),
3285
(ulong) ut_dulint_get_low(seg_id));
3289
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3291
if (xdes_is_full(descr, mtr)) {
3292
/* The fragment is full: move it to another list */
3293
flst_remove(seg_inode + FSEG_FULL,
3294
descr + XDES_FLST_NODE, mtr);
3295
flst_add_last(seg_inode + FSEG_NOT_FULL,
3296
descr + XDES_FLST_NODE, mtr);
3297
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3298
not_full_n_used + FSP_EXTENT_SIZE - 1,
3301
ut_a(not_full_n_used > 0);
3302
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3303
not_full_n_used - 1, MLOG_4BYTES, mtr);
3306
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3307
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3309
if (xdes_is_free(descr, mtr)) {
3310
/* The extent has become free: free it to space */
3311
flst_remove(seg_inode + FSEG_NOT_FULL,
3312
descr + XDES_FLST_NODE, mtr);
3313
fsp_free_extent(space, zip_size, page, mtr);
3317
/**********************************************************************//**
3318
Frees a single page of a segment. */
3323
fseg_header_t* seg_header, /*!< in: segment header */
3324
ulint space, /*!< in: space id */
3325
ulint page, /*!< in: page offset */
3326
mtr_t* mtr) /*!< in: mtr handle */
3330
fseg_inode_t* seg_inode;
3333
latch = fil_space_get_latch(space, &flags);
3334
zip_size = dict_table_flags_to_zip_size(flags);
3336
ut_ad(!mutex_own(&kernel_mutex)
3337
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3339
mtr_x_lock(latch, mtr);
3341
seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3343
fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3345
#ifdef UNIV_DEBUG_FILE_ACCESSES
3346
buf_page_set_file_page_was_freed(space, page);
3350
/**********************************************************************//**
3351
Frees an extent of a segment to the space free list. */
3356
fseg_inode_t* seg_inode, /*!< in: segment inode */
3357
ulint space, /*!< in: space id */
3358
ulint zip_size,/*!< in: compressed page size in bytes
3359
or 0 for uncompressed pages */
3360
ulint page, /*!< in: a page in the extent */
3361
mtr_t* mtr) /*!< in: mtr handle */
3363
ulint first_page_in_extent;
3365
ulint not_full_n_used;
3369
ut_ad(seg_inode && mtr);
3371
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3373
ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3374
ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr),
3375
mtr_read_dulint(seg_inode + FSEG_ID, mtr)));
3377
first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3379
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3380
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3382
/* Drop search system page hash index if the page is
3383
found in the pool and is hashed */
3385
btr_search_drop_page_hash_when_freed(
3386
space, zip_size, first_page_in_extent + i);
3390
if (xdes_is_full(descr, mtr)) {
3391
flst_remove(seg_inode + FSEG_FULL,
3392
descr + XDES_FLST_NODE, mtr);
3393
} else if (xdes_is_free(descr, mtr)) {
3394
flst_remove(seg_inode + FSEG_FREE,
3395
descr + XDES_FLST_NODE, mtr);
3397
flst_remove(seg_inode + FSEG_NOT_FULL,
3398
descr + XDES_FLST_NODE, mtr);
3400
not_full_n_used = mtr_read_ulint(
3401
seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3403
descr_n_used = xdes_get_n_used(descr, mtr);
3404
ut_a(not_full_n_used >= descr_n_used);
3405
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3406
not_full_n_used - descr_n_used,
3410
fsp_free_extent(space, zip_size, page, mtr);
3412
#ifdef UNIV_DEBUG_FILE_ACCESSES
3413
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3415
buf_page_set_file_page_was_freed(space,
3416
first_page_in_extent + i);
3421
/**********************************************************************//**
3422
Frees part of a segment. This function can be used to free a segment by
3423
repeatedly calling this function in different mini-transactions. Doing
3424
the freeing in a single mini-transaction might result in too big a
3426
@return TRUE if freeing completed */
3431
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
3432
resides on the first page of the frag list
3433
of the segment, this pointer becomes obsolete
3434
after the last freeing step */
3435
mtr_t* mtr) /*!< in: mtr */
3440
fseg_inode_t* inode;
3447
space = page_get_space_id(page_align(header));
3448
header_page = page_get_page_no(page_align(header));
3450
latch = fil_space_get_latch(space, &flags);
3451
zip_size = dict_table_flags_to_zip_size(flags);
3453
ut_ad(!mutex_own(&kernel_mutex)
3454
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3456
mtr_x_lock(latch, mtr);
3458
descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3460
/* Check that the header resides on a page which has not been
3464
ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
3465
header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3466
inode = fseg_inode_get(header, space, zip_size, mtr);
3468
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3470
if (descr != NULL) {
3471
/* Free the extent held by the segment */
3472
page = xdes_get_offset(descr);
3474
fseg_free_extent(inode, space, zip_size, page, mtr);
3479
/* Free a frag page */
3480
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3482
if (n == ULINT_UNDEFINED) {
3483
/* Freeing completed: free the segment inode */
3484
fsp_free_seg_inode(space, zip_size, inode, mtr);
3489
fseg_free_page_low(inode, space, zip_size,
3490
fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3492
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3494
if (n == ULINT_UNDEFINED) {
3495
/* Freeing completed: free the segment inode */
3496
fsp_free_seg_inode(space, zip_size, inode, mtr);
3504
/**********************************************************************//**
3505
Frees part of a segment. Differs from fseg_free_step because this function
3506
leaves the header page unfreed.
3507
@return TRUE if freeing completed, except the header page */
3510
fseg_free_step_not_header(
3511
/*======================*/
3512
fseg_header_t* header, /*!< in: segment header which must reside on
3513
the first fragment page of the segment */
3514
mtr_t* mtr) /*!< in: mtr */
3519
fseg_inode_t* inode;
3526
space = page_get_space_id(page_align(header));
3528
latch = fil_space_get_latch(space, &flags);
3529
zip_size = dict_table_flags_to_zip_size(flags);
3531
ut_ad(!mutex_own(&kernel_mutex)
3532
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3534
mtr_x_lock(latch, mtr);
3536
inode = fseg_inode_get(header, space, zip_size, mtr);
3538
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3540
if (descr != NULL) {
3541
/* Free the extent held by the segment */
3542
page = xdes_get_offset(descr);
3544
fseg_free_extent(inode, space, zip_size, page, mtr);
3549
/* Free a frag page */
3551
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3553
if (n == ULINT_UNDEFINED) {
3557
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3559
if (page_no == page_get_page_no(page_align(header))) {
3564
fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3569
/**********************************************************************//**
3570
Returns the first extent descriptor for a segment. We think of the extent
3571
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
3573
@return the first extent descriptor, or NULL if none */
3576
fseg_get_first_extent(
3577
/*==================*/
3578
fseg_inode_t* inode, /*!< in: segment inode */
3579
ulint space, /*!< in: space id */
3580
ulint zip_size,/*!< in: compressed page size in bytes
3581
or 0 for uncompressed pages */
3582
mtr_t* mtr) /*!< in: mtr */
3587
ut_ad(inode && mtr);
3589
ut_ad(space == page_get_space_id(page_align(inode)));
3591
first = fil_addr_null;
3593
if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3595
first = flst_get_first(inode + FSEG_FULL, mtr);
3597
} else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3599
first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3601
} else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3603
first = flst_get_first(inode + FSEG_FREE, mtr);
3606
if (first.page == FIL_NULL) {
3610
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3615
/*******************************************************************//**
3616
Validates a segment.
3617
@return TRUE if ok */
3622
fseg_inode_t* inode, /*!< in: segment inode */
3623
mtr_t* mtr2) /*!< in: mtr */
3629
fil_addr_t node_addr;
3633
ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3634
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3636
space = page_get_space_id(page_align(inode));
3638
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr2);
3639
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3641
flst_validate(inode + FSEG_FREE, mtr2);
3642
flst_validate(inode + FSEG_NOT_FULL, mtr2);
3643
flst_validate(inode + FSEG_FULL, mtr2);
3645
/* Validate FSEG_FREE list */
3646
node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3648
while (!fil_addr_is_null(node_addr)) {
3653
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3654
zip_size = dict_table_flags_to_zip_size(flags);
3656
descr = xdes_lst_get_descriptor(space, zip_size,
3659
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3660
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3661
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3664
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3668
/* Validate FSEG_NOT_FULL list */
3670
node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3672
while (!fil_addr_is_null(node_addr)) {
3677
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3678
zip_size = dict_table_flags_to_zip_size(flags);
3680
descr = xdes_lst_get_descriptor(space, zip_size,
3683
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3684
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3685
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3686
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3689
n_used2 += xdes_get_n_used(descr, &mtr);
3691
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3695
/* Validate FSEG_FULL list */
3697
node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3699
while (!fil_addr_is_null(node_addr)) {
3704
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3705
zip_size = dict_table_flags_to_zip_size(flags);
3707
descr = xdes_lst_get_descriptor(space, zip_size,
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
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3719
ut_a(n_used == n_used2);
3725
/*******************************************************************//**
3726
Validates a segment.
3727
@return TRUE if ok */
3732
fseg_header_t* header, /*!< in: segment header */
3733
mtr_t* mtr) /*!< in: mtr */
3735
fseg_inode_t* inode;
3741
space = page_get_space_id(page_align(header));
3743
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3744
zip_size = dict_table_flags_to_zip_size(flags);
3746
inode = fseg_inode_get(header, space, zip_size, mtr);
3748
ret = fseg_validate_low(inode, mtr);
3752
#endif /* UNIV_DEBUG */
3754
/*******************************************************************//**
3755
Writes info of a segment. */
3760
fseg_inode_t* inode, /*!< in: segment inode */
3761
mtr_t* mtr) /*!< in: mtr */
3776
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3777
space = page_get_space_id(page_align(inode));
3778
page_no = page_get_page_no(page_align(inode));
3780
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3782
d_var = mtr_read_dulint(inode + FSEG_ID, mtr);
3784
seg_id_low = ut_dulint_get_low(d_var);
3785
seg_id_high = ut_dulint_get_high(d_var);
3787
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3789
n_frag = fseg_get_n_frag_pages(inode, mtr);
3790
n_free = flst_get_len(inode + FSEG_FREE, mtr);
3791
n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3792
n_full = flst_get_len(inode + FSEG_FULL, mtr);
3795
"SEGMENT id %lu %lu space %lu; page %lu;"
3796
" res %lu used %lu; full ext %lu\n"
3797
"fragm pages %lu; free extents %lu;"
3798
" not full extents %lu: pages %lu\n",
3799
(ulong) seg_id_high, (ulong) seg_id_low,
3800
(ulong) space, (ulong) page_no,
3801
(ulong) reserved, (ulong) used, (ulong) n_full,
3802
(ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3806
#ifdef UNIV_BTR_PRINT
3807
/*******************************************************************//**
3808
Writes info of a segment. */
3813
fseg_header_t* header, /*!< in: segment header */
3814
mtr_t* mtr) /*!< in: mtr */
3816
fseg_inode_t* inode;
3821
space = page_get_space_id(page_align(header));
3823
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3824
zip_size = dict_table_flags_to_zip_size(flags);
3826
inode = fseg_inode_get(header, space, zip_size, mtr);
3828
fseg_print_low(inode, mtr);
3830
#endif /* UNIV_BTR_PRINT */
3832
/*******************************************************************//**
3833
Validates the file space system and its segments.
3834
@return TRUE if ok */
3839
ulint space) /*!< in: space id */
3841
fsp_header_t* header;
3842
fseg_inode_t* seg_inode;
3843
page_t* seg_inode_page;
3853
fil_addr_t node_addr;
3854
fil_addr_t next_node_addr;
3855
ulint descr_count = 0;
3858
ulint n_full_frag_pages;
3860
ulint seg_inode_len_free;
3861
ulint seg_inode_len_full;
3863
latch = fil_space_get_latch(space, &flags);
3864
zip_size = dict_table_flags_to_zip_size(flags);
3865
ut_a(ut_is_2pow(zip_size));
3866
ut_a(zip_size <= UNIV_PAGE_SIZE);
3867
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
3869
/* Start first a mini-transaction mtr2 to lock out all other threads
3870
from the fsp system */
3872
mtr_x_lock(latch, &mtr2);
3875
mtr_x_lock(latch, &mtr);
3877
header = fsp_get_space_header(space, zip_size, &mtr);
3879
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3880
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3882
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3885
n_full_frag_pages = FSP_EXTENT_SIZE
3886
* flst_get_len(header + FSP_FULL_FRAG, &mtr);
3888
if (UNIV_UNLIKELY(free_limit > size)) {
3891
ut_a(size < FSP_EXTENT_SIZE);
3894
flst_validate(header + FSP_FREE, &mtr);
3895
flst_validate(header + FSP_FREE_FRAG, &mtr);
3896
flst_validate(header + FSP_FULL_FRAG, &mtr);
3900
/* Validate FSP_FREE list */
3902
mtr_x_lock(latch, &mtr);
3904
header = fsp_get_space_header(space, zip_size, &mtr);
3905
node_addr = flst_get_first(header + FSP_FREE, &mtr);
3909
while (!fil_addr_is_null(node_addr)) {
3911
mtr_x_lock(latch, &mtr);
3914
descr = xdes_lst_get_descriptor(space, zip_size,
3917
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3918
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3920
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3924
/* Validate FSP_FREE_FRAG 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_FRAG, &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_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3943
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
3945
n_used += xdes_get_n_used(descr, &mtr);
3946
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3951
/* Validate FSP_FULL_FRAG list */
3953
mtr_x_lock(latch, &mtr);
3955
header = fsp_get_space_header(space, zip_size, &mtr);
3956
node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
3960
while (!fil_addr_is_null(node_addr)) {
3962
mtr_x_lock(latch, &mtr);
3965
descr = xdes_lst_get_descriptor(space, zip_size,
3968
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3969
ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
3971
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3975
/* Validate segments */
3977
mtr_x_lock(latch, &mtr);
3979
header = fsp_get_space_header(space, zip_size, &mtr);
3981
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
3983
seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
3987
while (!fil_addr_is_null(node_addr)) {
3992
mtr_x_lock(latch, &mtr);
3994
seg_inode_page = fut_get_ptr(
3995
space, zip_size, node_addr, RW_X_LATCH, &mtr)
3996
- FSEG_INODE_PAGE_NODE;
3998
seg_inode = fsp_seg_inode_page_get_nth_inode(
3999
seg_inode_page, n, zip_size, &mtr);
4000
ut_a(!ut_dulint_is_zero(
4001
mach_read_from_8(seg_inode + FSEG_ID)));
4002
fseg_validate_low(seg_inode, &mtr);
4004
descr_count += flst_get_len(seg_inode + FSEG_FREE,
4006
descr_count += flst_get_len(seg_inode + FSEG_FULL,
4008
descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
4011
n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
4013
next_node_addr = flst_get_next_addr(
4014
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4016
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4018
node_addr = next_node_addr;
4022
mtr_x_lock(latch, &mtr);
4024
header = fsp_get_space_header(space, zip_size, &mtr);
4026
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4028
seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
4032
while (!fil_addr_is_null(node_addr)) {
4038
mtr_x_lock(latch, &mtr);
4040
seg_inode_page = fut_get_ptr(
4041
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4042
- FSEG_INODE_PAGE_NODE;
4044
seg_inode = fsp_seg_inode_page_get_nth_inode(
4045
seg_inode_page, n, zip_size, &mtr);
4046
if (!ut_dulint_is_zero(
4047
mach_read_from_8(seg_inode + FSEG_ID))) {
4048
fseg_validate_low(seg_inode, &mtr);
4050
descr_count += flst_get_len(
4051
seg_inode + FSEG_FREE, &mtr);
4052
descr_count += flst_get_len(
4053
seg_inode + FSEG_FULL, &mtr);
4054
descr_count += flst_get_len(
4055
seg_inode + FSEG_NOT_FULL, &mtr);
4056
n_used2 += fseg_get_n_frag_pages(
4060
next_node_addr = flst_get_next_addr(
4061
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4063
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4065
node_addr = next_node_addr;
4068
ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
4070
ut_a(n_used + n_full_frag_pages
4071
== n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
4073
+ seg_inode_len_full + seg_inode_len_free);
4075
ut_a(n_used + n_full_frag_pages
4076
== n_used2 + 2 * ((free_limit + (zip_size - 1))
4078
+ seg_inode_len_full + seg_inode_len_free);
4080
ut_a(frag_n_used == n_used);
4087
/*******************************************************************//**
4088
Prints info of a file space. */
4093
ulint space) /*!< in: space id */
4095
fsp_header_t* header;
4096
fseg_inode_t* seg_inode;
4097
page_t* seg_inode_page;
4104
fil_addr_t node_addr;
4105
fil_addr_t next_node_addr;
4117
latch = fil_space_get_latch(space, &flags);
4118
zip_size = dict_table_flags_to_zip_size(flags);
4120
/* Start first a mini-transaction mtr2 to lock out all other threads
4121
from the fsp system */
4125
mtr_x_lock(latch, &mtr2);
4129
mtr_x_lock(latch, &mtr);
4131
header = fsp_get_space_header(space, zip_size, &mtr);
4133
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4135
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4137
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4139
n_free = flst_get_len(header + FSP_FREE, &mtr);
4140
n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4141
n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4143
d_var = mtr_read_dulint(header + FSP_SEG_ID, &mtr);
4145
seg_id_low = ut_dulint_get_low(d_var);
4146
seg_id_high = ut_dulint_get_high(d_var);
4149
"FILE SPACE INFO: id %lu\n"
4150
"size %lu, free limit %lu, free extents %lu\n"
4151
"not full frag extents %lu: used pages %lu,"
4152
" full frag extents %lu\n"
4153
"first seg id not used %lu %lu\n",
4155
(ulong) size, (ulong) free_limit, (ulong) n_free,
4156
(ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4157
(ulong) seg_id_high, (ulong) seg_id_low);
4161
/* Print segments */
4164
mtr_x_lock(latch, &mtr);
4166
header = fsp_get_space_header(space, zip_size, &mtr);
4168
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4172
while (!fil_addr_is_null(node_addr)) {
4179
mtr_x_lock(latch, &mtr);
4181
seg_inode_page = fut_get_ptr(
4182
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4183
- FSEG_INODE_PAGE_NODE;
4185
seg_inode = fsp_seg_inode_page_get_nth_inode(
4186
seg_inode_page, n, zip_size, &mtr);
4187
ut_a(!ut_dulint_is_zero(
4188
mach_read_from_8(seg_inode + FSEG_ID)));
4189
fseg_print_low(seg_inode, &mtr);
4193
next_node_addr = flst_get_next_addr(
4194
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4196
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4198
node_addr = next_node_addr;
4202
mtr_x_lock(latch, &mtr);
4204
header = fsp_get_space_header(space, zip_size, &mtr);
4206
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4210
while (!fil_addr_is_null(node_addr)) {
4217
mtr_x_lock(latch, &mtr);
4219
seg_inode_page = fut_get_ptr(
4220
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4221
- FSEG_INODE_PAGE_NODE;
4223
seg_inode = fsp_seg_inode_page_get_nth_inode(
4224
seg_inode_page, n, zip_size, &mtr);
4225
if (!ut_dulint_is_zero(
4226
mach_read_from_8(seg_inode + FSEG_ID))) {
4228
fseg_print_low(seg_inode, &mtr);
4232
next_node_addr = flst_get_next_addr(
4233
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4235
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4237
node_addr = next_node_addr;
4242
fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
4244
#endif /* !UNIV_HOTBACKUP */