1
/*****************************************************************************
3
Copyright (c) 1995, 2010, 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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 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 0,
131
it means that the header is unused */
132
#define FSEG_NOT_FULL_N_USED 8
133
/* number of used segment pages in
134
the FSEG_NOT_FULL list */
136
/* list of free extents of this
138
#define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
139
/* list of partially free extents */
140
#define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
141
/* list of full extents */
142
#define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
143
/* magic number used in debugging */
144
#define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
145
/* array of individual pages
146
belonging to this segment in fsp
147
fragment extent lists */
148
#define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
149
/* number of slots in the array for
150
the fragment pages */
151
#define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
152
page number within space, FIL_NULL
153
means that the slot is not in use */
154
/*-------------------------------------*/
155
#define FSEG_INODE_SIZE \
156
(16 + 3 * FLST_BASE_NODE_SIZE \
157
+ FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
159
#define FSP_SEG_INODES_PER_PAGE(zip_size) \
160
(((zip_size ? zip_size : UNIV_PAGE_SIZE) \
161
- FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
162
/* Number of segment inodes which fit on a
165
#define FSEG_MAGIC_N_VALUE 97937874
167
#define FSEG_FILLFACTOR 8 /* If this value is x, then if
168
the number of unused but reserved
169
pages in a segment is less than
170
reserved pages * 1/x, and there are
171
at least FSEG_FRAG_LIMIT used pages,
172
then we allow a new empty extent to
173
be added to the segment in
174
fseg_alloc_free_page. Otherwise, we
175
use unused pages of the segment. */
177
#define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
178
/* If the segment has >= this many
179
used pages, it may be expanded by
180
allocating extents to the segment;
181
until that only individual fragment
182
pages are allocated from the space */
184
#define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
185
is at least this many extents, we
186
allow extents to be put to the free
187
list of the extent: at most
188
FSEG_FREE_LIST_MAX_LEN many */
189
#define FSEG_FREE_LIST_MAX_LEN 4
195
File extent descriptor data structure: contains bits to tell which pages in
196
the extent are free and which contain old tuple version to clean. */
198
/*-------------------------------------*/
199
#define XDES_ID 0 /* The identifier of the segment
200
to which this extent belongs */
201
#define XDES_FLST_NODE 8 /* The list node data structure
202
for the descriptors */
203
#define XDES_STATE (FLST_NODE_SIZE + 8)
204
/* contains state information
206
#define XDES_BITMAP (FLST_NODE_SIZE + 12)
207
/* Descriptor bitmap of the pages
209
/*-------------------------------------*/
211
#define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
212
#define XDES_FREE_BIT 0 /* Index of the bit which tells if
214
#define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
215
Index of the bit which tells if
216
there are old versions of tuples
218
/* States of a descriptor */
219
#define XDES_FREE 1 /* extent is in free list of space */
220
#define XDES_FREE_FRAG 2 /* extent is in free fragment list of
222
#define XDES_FULL_FRAG 3 /* extent is in full fragment list of
224
#define XDES_FSEG 4 /* extent belongs to a segment */
226
/* File extent data structure size in bytes. */
228
(XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
230
/* Offset of the descriptor array on a descriptor page */
231
#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
233
#ifndef UNIV_HOTBACKUP
234
/* Flag to indicate if we have printed the tablespace full error. */
235
static ibool fsp_tbs_full_error_printed = FALSE;
237
/**********************************************************************//**
238
Returns an extent to the free list of a space. */
243
ulint space, /*!< in: space id */
244
ulint zip_size,/*!< in: compressed page size in bytes
245
or 0 for uncompressed pages */
246
ulint page, /*!< in: page offset in the extent */
247
mtr_t* mtr); /*!< in: mtr */
248
/**********************************************************************//**
249
Frees an extent of a segment to the space free list. */
254
fseg_inode_t* seg_inode, /*!< in: segment inode */
255
ulint space, /*!< in: space id */
256
ulint zip_size,/*!< in: compressed page size in bytes
257
or 0 for uncompressed pages */
258
ulint page, /*!< in: page offset in the extent */
259
mtr_t* mtr); /*!< in: mtr handle */
260
/**********************************************************************//**
261
Calculates the number of pages reserved by a segment, and how
262
many pages are currently used.
263
@return number of reserved pages */
266
fseg_n_reserved_pages_low(
267
/*======================*/
268
fseg_inode_t* header, /*!< in: segment inode */
269
ulint* used, /*!< out: number of pages used (not
270
more than reserved) */
271
mtr_t* mtr); /*!< in: mtr handle */
272
/********************************************************************//**
273
Marks a page used. The page must reside within the extents of the given
279
fseg_inode_t* seg_inode,/*!< in: segment inode */
280
ulint space, /*!< in: space id */
281
ulint zip_size,/*!< in: compressed page size in bytes
282
or 0 for uncompressed pages */
283
ulint page, /*!< in: page offset */
284
mtr_t* mtr); /*!< in: mtr */
285
/**********************************************************************//**
286
Returns the first extent descriptor for a segment. We think of the extent
287
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
289
@return the first extent descriptor, or NULL if none */
292
fseg_get_first_extent(
293
/*==================*/
294
fseg_inode_t* inode, /*!< in: segment inode */
295
ulint space, /*!< in: space id */
296
ulint zip_size,/*!< in: compressed page size in bytes
297
or 0 for uncompressed pages */
298
mtr_t* mtr); /*!< in: mtr */
299
/**********************************************************************//**
300
Puts new extents to the free list if
301
there are free extents above the free limit. If an extent happens
302
to contain an extent descriptor page, the extent is put to
303
the FSP_FREE_FRAG list with the page marked as used. */
308
ibool init_space, /*!< in: TRUE if this is a single-table
309
tablespace and we are only initing
310
the tablespace's first extent
311
descriptor page and ibuf bitmap page;
312
then we do not allocate more extents */
313
ulint space, /*!< in: space */
314
fsp_header_t* header, /*!< in: space header */
315
mtr_t* mtr); /*!< in: mtr */
316
/**********************************************************************//**
317
Allocates a single free page from a segment. This function implements
318
the intelligent allocation strategy which tries to minimize file space
320
@return the allocated page number, FIL_NULL if no page could be allocated */
323
fseg_alloc_free_page_low(
324
/*=====================*/
325
ulint space, /*!< in: space */
326
ulint zip_size,/*!< in: compressed page size in bytes
327
or 0 for uncompressed pages */
328
fseg_inode_t* seg_inode, /*!< in: segment inode */
329
ulint hint, /*!< in: hint of which page would be desirable */
330
byte direction, /*!< in: if the new page is needed because
331
of an index page split, and records are
332
inserted there in order, into which
333
direction they go alphabetically: FSP_DOWN,
334
FSP_UP, FSP_NO_DIR */
335
mtr_t* mtr); /*!< in: mtr handle */
336
#endif /* !UNIV_HOTBACKUP */
338
/**********************************************************************//**
339
Reads the file space size stored in the header page.
340
@return tablespace size stored in the space header */
345
page_t* page) /*!< in: header page (page 0 in the tablespace) */
347
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
350
#ifndef UNIV_HOTBACKUP
351
/**********************************************************************//**
352
Gets a pointer to the space header and x-locks its page.
353
@return pointer to the space header, page x-locked */
356
fsp_get_space_header(
357
/*=================*/
358
ulint id, /*!< in: space id */
359
ulint zip_size,/*!< in: compressed page size in bytes
360
or 0 for uncompressed pages */
361
mtr_t* mtr) /*!< in: mtr */
364
fsp_header_t* header;
366
ut_ad(ut_is_2pow(zip_size));
367
ut_ad(zip_size <= UNIV_PAGE_SIZE);
368
ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
369
ut_ad(id || !zip_size);
371
block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
372
header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
373
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
375
ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
376
ut_ad(zip_size == dict_table_flags_to_zip_size(
377
mach_read_from_4(FSP_SPACE_FLAGS + header)));
381
/**********************************************************************//**
382
Gets a descriptor bit of a page.
383
@return TRUE if free */
388
const xdes_t* descr, /*!< in: descriptor */
389
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
390
ulint offset, /*!< in: page offset within extent:
391
0 ... FSP_EXTENT_SIZE - 1 */
392
mtr_t* mtr) /*!< in: mtr */
398
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
399
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
400
ut_ad(offset < FSP_EXTENT_SIZE);
402
index = bit + XDES_BITS_PER_PAGE * offset;
404
byte_index = index / 8;
405
bit_index = index % 8;
407
return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
412
/**********************************************************************//**
413
Sets a descriptor bit of a page. */
418
xdes_t* descr, /*!< in: descriptor */
419
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
420
ulint offset, /*!< in: page offset within extent:
421
0 ... FSP_EXTENT_SIZE - 1 */
422
ibool val, /*!< in: bit value */
423
mtr_t* mtr) /*!< in: mtr */
430
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
431
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
432
ut_ad(offset < FSP_EXTENT_SIZE);
434
index = bit + XDES_BITS_PER_PAGE * offset;
436
byte_index = index / 8;
437
bit_index = index % 8;
439
descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
441
descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
443
mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
447
/**********************************************************************//**
448
Looks for a descriptor bit having the desired value. Starts from hint
449
and scans upward; at the end of the extent the search is wrapped to
450
the start of the extent.
451
@return bit index of the bit, ULINT_UNDEFINED if not found */
456
xdes_t* descr, /*!< in: descriptor */
457
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
458
ibool val, /*!< in: desired bit value */
459
ulint hint, /*!< in: hint of which bit position would be desirable */
460
mtr_t* mtr) /*!< in: mtr */
466
ut_ad(hint < FSP_EXTENT_SIZE);
467
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
468
for (i = hint; i < FSP_EXTENT_SIZE; i++) {
469
if (val == xdes_get_bit(descr, bit, i, mtr)) {
475
for (i = 0; i < hint; i++) {
476
if (val == xdes_get_bit(descr, bit, i, mtr)) {
482
return(ULINT_UNDEFINED);
485
/**********************************************************************//**
486
Looks for a descriptor bit having the desired value. Scans the extent in
487
a direction opposite to xdes_find_bit.
488
@return bit index of the bit, ULINT_UNDEFINED if not found */
491
xdes_find_bit_downward(
492
/*===================*/
493
xdes_t* descr, /*!< in: descriptor */
494
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
495
ibool val, /*!< in: desired bit value */
496
ulint hint, /*!< in: hint of which bit position would be desirable */
497
mtr_t* mtr) /*!< in: mtr */
503
ut_ad(hint < FSP_EXTENT_SIZE);
504
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
505
for (i = hint + 1; i > 0; i--) {
506
if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
512
for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
513
if (val == xdes_get_bit(descr, bit, i, mtr)) {
519
return(ULINT_UNDEFINED);
522
/**********************************************************************//**
523
Returns the number of used pages in a descriptor.
524
@return number of pages used */
529
const xdes_t* descr, /*!< in: descriptor */
530
mtr_t* mtr) /*!< in: mtr */
536
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
537
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
538
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
546
/**********************************************************************//**
547
Returns true if extent contains no used pages.
548
@return TRUE if totally free */
553
const xdes_t* descr, /*!< in: descriptor */
554
mtr_t* mtr) /*!< in: mtr */
556
if (0 == xdes_get_n_used(descr, mtr)) {
564
/**********************************************************************//**
565
Returns true if extent contains no free pages.
566
@return TRUE if full */
571
const xdes_t* descr, /*!< in: descriptor */
572
mtr_t* mtr) /*!< in: mtr */
574
if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
582
/**********************************************************************//**
583
Sets the state of an xdes. */
588
xdes_t* descr, /*!< in/out: descriptor */
589
ulint state, /*!< in: state to set */
590
mtr_t* mtr) /*!< in: mtr handle */
593
ut_ad(state >= XDES_FREE);
594
ut_ad(state <= XDES_FSEG);
595
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
597
mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
600
/**********************************************************************//**
601
Gets the state of an xdes.
607
const xdes_t* descr, /*!< in: descriptor */
608
mtr_t* mtr) /*!< in: mtr handle */
613
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
615
state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
616
ut_ad(state - 1 < XDES_FSEG);
620
/**********************************************************************//**
621
Inits an extent descriptor to the free and clean state. */
626
xdes_t* descr, /*!< in: descriptor */
627
mtr_t* mtr) /*!< in: mtr */
632
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
633
ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
635
for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
636
mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
639
xdes_set_state(descr, XDES_FREE, mtr);
642
/********************************************************************//**
643
Calculates the page where the descriptor of a page resides.
644
@return descriptor page offset */
647
xdes_calc_descriptor_page(
648
/*======================*/
649
ulint zip_size, /*!< in: compressed page size in bytes;
650
0 for uncompressed pages */
651
ulint offset) /*!< in: page offset */
653
#ifndef DOXYGEN /* Doxygen gets confused of these */
654
# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
655
+ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
658
# if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
659
+ (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
662
#endif /* !DOXYGEN */
663
ut_ad(ut_is_2pow(zip_size));
666
return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
668
ut_ad(zip_size > XDES_ARR_OFFSET
669
+ (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
670
return(ut_2pow_round(offset, zip_size));
674
/********************************************************************//**
675
Calculates the descriptor index within a descriptor page.
676
@return descriptor index */
679
xdes_calc_descriptor_index(
680
/*=======================*/
681
ulint zip_size, /*!< in: compressed page size in bytes;
682
0 for uncompressed pages */
683
ulint offset) /*!< in: page offset */
685
ut_ad(ut_is_2pow(zip_size));
688
return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
691
return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
695
/********************************************************************//**
696
Gets pointer to a the extent descriptor of a page. The page where the extent
697
descriptor resides is x-locked. If the page offset is equal to the free limit
698
of the space, adds new extents from above the free limit to the space free
699
list, if not free limit == space size. This adding is necessary to make the
700
descriptor defined, as they are uninitialized above the free limit.
701
@return pointer to the extent descriptor, NULL if the page does not
702
exist in the space or if the offset exceeds the free limit */
705
xdes_get_descriptor_with_space_hdr(
706
/*===============================*/
707
fsp_header_t* sp_header,/*!< in/out: space header, x-latched */
708
ulint space, /*!< in: space id */
709
ulint offset, /*!< in: page offset;
710
if equal to the free limit,
711
we try to add new extents to
712
the space free list */
713
mtr_t* mtr) /*!< in: mtr handle */
722
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
724
ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
725
|| mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
726
ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
727
/* Read free limit and space size */
728
limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
729
size = mach_read_from_4(sp_header + FSP_SIZE);
730
zip_size = dict_table_flags_to_zip_size(
731
mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
733
/* If offset is >= size or > limit, return NULL */
735
if ((offset >= size) || (offset > limit)) {
740
/* If offset is == limit, fill free list of the space. */
742
if (offset == limit) {
743
fsp_fill_free_list(FALSE, space, sp_header, mtr);
746
descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
748
if (descr_page_no == 0) {
749
/* It is on the space header page */
751
descr_page = page_align(sp_header);
755
block = buf_page_get(space, zip_size, descr_page_no,
757
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
759
descr_page = buf_block_get_frame(block);
762
return(descr_page + XDES_ARR_OFFSET
763
+ XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
766
/********************************************************************//**
767
Gets pointer to a the extent descriptor of a page. The page where the
768
extent descriptor resides is x-locked. If the page offset is equal to
769
the free limit of the space, adds new extents from above the free limit
770
to the space free list, if not free limit == space size. This adding
771
is necessary to make the descriptor defined, as they are uninitialized
772
above the free limit.
773
@return pointer to the extent descriptor, NULL if the page does not
774
exist in the space or if the offset exceeds the free limit */
779
ulint space, /*!< in: space id */
780
ulint zip_size,/*!< in: compressed page size in bytes
781
or 0 for uncompressed pages */
782
ulint offset, /*!< in: page offset; if equal to the free limit,
783
we try to add new extents to the space free list */
784
mtr_t* mtr) /*!< in: mtr handle */
787
fsp_header_t* sp_header;
789
block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
790
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
792
sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
793
return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
797
/********************************************************************//**
798
Gets pointer to a the extent descriptor if the file address
799
of the descriptor list node is known. The page where the
800
extent descriptor resides is x-locked.
801
@return pointer to the extent descriptor */
804
xdes_lst_get_descriptor(
805
/*====================*/
806
ulint space, /*!< in: space id */
807
ulint zip_size,/*!< in: compressed page size in bytes
808
or 0 for uncompressed pages */
809
fil_addr_t lst_node,/*!< in: file address of the list node
810
contained in the descriptor */
811
mtr_t* mtr) /*!< in: mtr handle */
816
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
818
descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
824
/********************************************************************//**
825
Returns page offset of the first page in extent described by a descriptor.
826
@return offset of the first page in extent */
831
xdes_t* descr) /*!< in: extent descriptor */
835
return(page_get_page_no(page_align(descr))
836
+ ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
839
#endif /* !UNIV_HOTBACKUP */
841
/***********************************************************//**
842
Inits a file page whose prior contents should be ignored. */
845
fsp_init_file_page_low(
846
/*===================*/
847
buf_block_t* block) /*!< in: pointer to a page */
849
page_t* page = buf_block_get_frame(block);
850
page_zip_des_t* page_zip= buf_block_get_page_zip(block);
852
#ifndef UNIV_HOTBACKUP
853
block->check_index_page_at_flush = FALSE;
854
#endif /* !UNIV_HOTBACKUP */
856
if (UNIV_LIKELY_NULL(page_zip)) {
857
memset(page, 0, UNIV_PAGE_SIZE);
858
memset(page_zip->data, 0, page_zip_get_size(page_zip));
859
mach_write_to_4(page + FIL_PAGE_OFFSET,
860
buf_block_get_page_no(block));
862
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
863
buf_block_get_space(block));
864
memcpy(page_zip->data + FIL_PAGE_OFFSET,
865
page + FIL_PAGE_OFFSET, 4);
866
memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
867
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
871
memset(page, 0, UNIV_PAGE_SIZE);
872
mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
873
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
874
buf_block_get_space(block));
877
#ifndef UNIV_HOTBACKUP
878
/***********************************************************//**
879
Inits a file page whose prior contents should be ignored. */
884
buf_block_t* block, /*!< in: pointer to a page */
885
mtr_t* mtr) /*!< in: mtr */
887
fsp_init_file_page_low(block);
889
mlog_write_initial_log_record(buf_block_get_frame(block),
890
MLOG_INIT_FILE_PAGE, mtr);
892
#endif /* !UNIV_HOTBACKUP */
894
/***********************************************************//**
895
Parses a redo log record of a file page init.
896
@return end of log record or NULL */
899
fsp_parse_init_file_page(
900
/*=====================*/
901
byte* ptr, /*!< in: buffer */
902
byte* end_ptr __attribute__((unused)), /*!< in: buffer end */
903
buf_block_t* block) /*!< in: block or NULL */
905
ut_ad(ptr && end_ptr);
908
fsp_init_file_page_low(block);
914
/**********************************************************************//**
915
Initializes the fsp system. */
921
/* Does nothing at the moment */
924
/**********************************************************************//**
925
Writes the space id and compressed page size to a tablespace header.
926
This function is used past the buffer pool when we in fil0fil.c create
927
a new single-table tablespace. */
930
fsp_header_init_fields(
931
/*===================*/
932
page_t* page, /*!< in/out: first page in the space */
933
ulint space_id, /*!< in: space id */
934
ulint flags) /*!< in: tablespace flags (FSP_SPACE_FLAGS):
935
0, or table->flags if newer than COMPACT */
937
/* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
938
ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
939
ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
940
format, the tablespace flags should equal table->flags. */
941
ut_a(flags != DICT_TF_COMPACT);
943
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
945
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
949
#ifndef UNIV_HOTBACKUP
950
/**********************************************************************//**
951
Initializes the space header of a new created space and creates also the
952
insert buffer tree root if space == 0. */
957
ulint space, /*!< in: space id */
958
ulint size, /*!< in: current size in blocks */
959
mtr_t* mtr) /*!< in: mini-transaction handle */
961
fsp_header_t* header;
969
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
971
zip_size = dict_table_flags_to_zip_size(flags);
972
block = buf_page_create(space, 0, zip_size, mtr);
973
buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
974
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
976
/* The prior contents of the file page should be ignored */
978
fsp_init_file_page(block, mtr);
979
page = buf_block_get_frame(block);
981
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
984
header = FSP_HEADER_OFFSET + page;
986
mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
987
mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
989
mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
990
mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
991
mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
993
mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
995
flst_init(header + FSP_FREE, mtr);
996
flst_init(header + FSP_FREE_FRAG, mtr);
997
flst_init(header + FSP_FULL_FRAG, mtr);
998
flst_init(header + FSP_SEG_INODES_FULL, mtr);
999
flst_init(header + FSP_SEG_INODES_FREE, mtr);
1001
mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
1003
fsp_fill_free_list(FALSE, space, header, mtr);
1004
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
1005
0, 0, DICT_IBUF_ID_MIN + space,
1006
dict_ind_redundant, mtr);
1008
fsp_fill_free_list(TRUE, space, header, mtr);
1011
#endif /* !UNIV_HOTBACKUP */
1013
/**********************************************************************//**
1014
Reads the space id from the first page of a tablespace.
1015
@return space id, ULINT UNDEFINED if error */
1018
fsp_header_get_space_id(
1019
/*====================*/
1020
const page_t* page) /*!< in: first page of a tablespace */
1025
fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
1027
id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
1031
"InnoDB: Error: space id in fsp header %lu,"
1032
" but in the page header %lu\n",
1033
(ulong) fsp_id, (ulong) id);
1035
return(ULINT_UNDEFINED);
1041
/**********************************************************************//**
1042
Reads the space flags from the first page of a tablespace.
1046
fsp_header_get_flags(
1047
/*=================*/
1048
const page_t* page) /*!< in: first page of a tablespace */
1050
ut_ad(!page_offset(page));
1052
return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
1055
/**********************************************************************//**
1056
Reads the compressed page size from the first page of a tablespace.
1057
@return compressed page size in bytes, or 0 if uncompressed */
1060
fsp_header_get_zip_size(
1061
/*====================*/
1062
const page_t* page) /*!< in: first page of a tablespace */
1064
ulint flags = fsp_header_get_flags(page);
1066
return(dict_table_flags_to_zip_size(flags));
1069
#ifndef UNIV_HOTBACKUP
1070
/**********************************************************************//**
1071
Increases the space size field of a space. */
1074
fsp_header_inc_size(
1075
/*================*/
1076
ulint space, /*!< in: space id */
1077
ulint size_inc,/*!< in: size increment in pages */
1078
mtr_t* mtr) /*!< in: mini-transaction handle */
1080
fsp_header_t* header;
1086
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
1088
header = fsp_get_space_header(space,
1089
dict_table_flags_to_zip_size(flags),
1092
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1094
mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
1098
/**********************************************************************//**
1099
Gets the current free limit of the system tablespace. The free limit
1100
means the place of the first page which has never been put to the the
1101
free list for allocation. The space above that address is initialized
1102
to zero. Sets also the global variable log_fsp_current_free_limit.
1103
@return free limit in megabytes */
1106
fsp_header_get_free_limit(void)
1107
/*===========================*/
1109
fsp_header_t* header;
1115
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1117
header = fsp_get_space_header(0, 0, &mtr);
1119
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1121
limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
1123
log_fsp_current_free_limit_set_and_checkpoint(limit);
1130
/**********************************************************************//**
1131
Gets the size of the system tablespace from the tablespace header. If
1132
we do not have an auto-extending data file, this should be equal to
1133
the size of the data files. If there is an auto-extending data file,
1134
this can be smaller.
1135
@return size in pages */
1138
fsp_header_get_tablespace_size(void)
1139
/*================================*/
1141
fsp_header_t* header;
1147
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1149
header = fsp_get_space_header(0, 0, &mtr);
1151
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1158
/***********************************************************************//**
1159
Tries to extend a single-table tablespace so that a page would fit in the
1161
@return TRUE if success */
1164
fsp_try_extend_data_file_with_pages(
1165
/*================================*/
1166
ulint space, /*!< in: space */
1167
ulint page_no, /*!< in: page number */
1168
fsp_header_t* header, /*!< in: space header */
1169
mtr_t* mtr) /*!< in: mtr */
1177
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1179
ut_a(page_no >= size);
1181
success = fil_extend_space_to_desired_size(&actual_size, space,
1183
/* actual_size now has the space size in pages; it may be less than
1184
we wanted if we ran out of disk space */
1186
mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1191
/***********************************************************************//**
1192
Tries to extend the last data file of a tablespace if it is auto-extending.
1193
@return FALSE if not auto-extending */
1196
fsp_try_extend_data_file(
1197
/*=====================*/
1198
ulint* actual_increase,/*!< out: actual increase in pages, where
1199
we measure the tablespace size from
1200
what the header field says; it may be
1201
the actual file size rounded down to
1203
ulint space, /*!< in: space */
1204
fsp_header_t* header, /*!< in: space header */
1205
mtr_t* mtr) /*!< in: mtr */
1211
ulint size_increase;
1215
*actual_increase = 0;
1217
if (space == 0 && !srv_auto_extend_last_data_file) {
1219
/* We print the error message only once to avoid
1220
spamming the error log. Note that we don't need
1221
to reset the flag to FALSE as dealing with this
1222
error requires server restart. */
1223
if (fsp_tbs_full_error_printed == FALSE) {
1225
"InnoDB: Error: Data file(s) ran"
1227
"Please add another data file or"
1228
" use \'autoextend\' for the last"
1230
fsp_tbs_full_error_printed = TRUE;
1235
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1236
zip_size = dict_table_flags_to_zip_size(
1237
mach_read_from_4(header + FSP_SPACE_FLAGS));
1242
if (!srv_last_file_size_max) {
1243
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1245
if (srv_last_file_size_max
1246
< srv_data_file_sizes[srv_n_data_files - 1]) {
1249
"InnoDB: Error: Last data file size"
1250
" is %lu, max size allowed %lu\n",
1251
(ulong) srv_data_file_sizes[
1252
srv_n_data_files - 1],
1253
(ulong) srv_last_file_size_max);
1256
size_increase = srv_last_file_size_max
1257
- srv_data_file_sizes[srv_n_data_files - 1];
1258
if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1259
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1263
/* We extend single-table tablespaces first one extent
1264
at a time, but for bigger tablespaces more. It is not
1265
enough to extend always by one extent, because some
1266
extents are frag page extents. */
1267
ulint extent_size; /*!< one megabyte, in pages */
1270
extent_size = FSP_EXTENT_SIZE;
1272
extent_size = FSP_EXTENT_SIZE
1273
* UNIV_PAGE_SIZE / zip_size;
1276
if (size < extent_size) {
1277
/* Let us first extend the file to extent_size */
1278
success = fsp_try_extend_data_file_with_pages(
1279
space, extent_size - 1, header, mtr);
1281
new_size = mtr_read_ulint(header + FSP_SIZE,
1284
*actual_increase = new_size - old_size;
1292
if (size < 32 * extent_size) {
1293
size_increase = extent_size;
1295
/* Below in fsp_fill_free_list() we assume
1296
that we add at most FSP_FREE_ADD extents at
1298
size_increase = FSP_FREE_ADD * extent_size;
1302
if (size_increase == 0) {
1307
success = fil_extend_space_to_desired_size(&actual_size, space,
1308
size + size_increase);
1309
/* We ignore any fragments of a full megabyte when storing the size
1310
to the space header */
1313
new_size = ut_calc_align_down(actual_size,
1314
(1024 * 1024) / UNIV_PAGE_SIZE);
1316
new_size = ut_calc_align_down(actual_size,
1317
(1024 * 1024) / zip_size);
1319
mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1321
*actual_increase = new_size - old_size;
1326
/**********************************************************************//**
1327
Puts new extents to the free list if there are free extents above the free
1328
limit. If an extent happens to contain an extent descriptor page, the extent
1329
is put to the FSP_FREE_FRAG list with the page marked as used. */
1334
ibool init_space, /*!< in: TRUE if this is a single-table
1335
tablespace and we are only initing
1336
the tablespace's first extent
1337
descriptor page and ibuf bitmap page;
1338
then we do not allocate more extents */
1339
ulint space, /*!< in: space */
1340
fsp_header_t* header, /*!< in/out: space header */
1341
mtr_t* mtr) /*!< in: mtr */
1349
ulint actual_increase;
1353
ut_ad(header && mtr);
1354
ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
1356
/* Check if we can fill free list from above the free list limit */
1357
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1358
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1360
zip_size = dict_table_flags_to_zip_size(
1361
mach_read_from_4(FSP_SPACE_FLAGS + header));
1362
ut_a(ut_is_2pow(zip_size));
1363
ut_a(zip_size <= UNIV_PAGE_SIZE);
1364
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
1366
if (space == 0 && srv_auto_extend_last_data_file
1367
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1369
/* Try to increase the last data file size */
1370
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1371
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1374
if (space != 0 && !init_space
1375
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1377
/* Try to increase the .ibd file size */
1378
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1379
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1384
while ((init_space && i < 1)
1385
|| ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1389
init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1391
init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1394
mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1397
/* Update the free limit info in the log system and make
1401
log_fsp_current_free_limit_set_and_checkpoint(
1402
(i + FSP_EXTENT_SIZE)
1403
/ ((1024 * 1024) / UNIV_PAGE_SIZE));
1406
if (UNIV_UNLIKELY(init_xdes)) {
1410
/* We are going to initialize a new descriptor page
1411
and a new ibuf bitmap page: the prior contents of the
1412
pages should be ignored. */
1415
block = buf_page_create(
1416
space, i, zip_size, mtr);
1417
buf_page_get(space, zip_size, i,
1419
buf_block_dbg_add_level(block,
1422
fsp_init_file_page(block, mtr);
1423
mlog_write_ulint(buf_block_get_frame(block)
1429
/* Initialize the ibuf bitmap page in a separate
1430
mini-transaction because it is low in the latching
1431
order, and we must be able to release its latch
1432
before returning from the fsp routine */
1434
mtr_start(&ibuf_mtr);
1436
block = buf_page_create(space,
1437
i + FSP_IBUF_BITMAP_OFFSET,
1438
zip_size, &ibuf_mtr);
1439
buf_page_get(space, zip_size,
1440
i + FSP_IBUF_BITMAP_OFFSET,
1441
RW_X_LATCH, &ibuf_mtr);
1442
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1444
fsp_init_file_page(block, &ibuf_mtr);
1446
ibuf_bitmap_page_init(block, &ibuf_mtr);
1448
mtr_commit(&ibuf_mtr);
1451
descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1453
xdes_init(descr, mtr);
1455
#if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
1456
# error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
1458
#if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
1459
# error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
1462
if (UNIV_UNLIKELY(init_xdes)) {
1464
/* The first page in the extent is a descriptor page
1465
and the second is an ibuf bitmap page: mark them
1468
xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1469
xdes_set_bit(descr, XDES_FREE_BIT,
1470
FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1471
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1473
flst_add_last(header + FSP_FREE_FRAG,
1474
descr + XDES_FLST_NODE, mtr);
1475
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1477
mlog_write_ulint(header + FSP_FRAG_N_USED,
1478
frag_n_used + 2, MLOG_4BYTES, mtr);
1480
flst_add_last(header + FSP_FREE,
1481
descr + XDES_FLST_NODE, mtr);
1485
i += FSP_EXTENT_SIZE;
1489
/**********************************************************************//**
1490
Allocates a new free extent.
1491
@return extent descriptor, NULL if cannot be allocated */
1494
fsp_alloc_free_extent(
1495
/*==================*/
1496
ulint space, /*!< in: space id */
1497
ulint zip_size,/*!< in: compressed page size in bytes
1498
or 0 for uncompressed pages */
1499
ulint hint, /*!< in: hint of which extent would be desirable: any
1500
page offset in the extent goes; the hint must not
1501
be > FSP_FREE_LIMIT */
1502
mtr_t* mtr) /*!< in: mtr */
1504
fsp_header_t* header;
1510
header = fsp_get_space_header(space, zip_size, mtr);
1512
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1514
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1515
/* Ok, we can take this extent */
1517
/* Take the first extent in the free list */
1518
first = flst_get_first(header + FSP_FREE, mtr);
1520
if (fil_addr_is_null(first)) {
1521
fsp_fill_free_list(FALSE, space, header, mtr);
1523
first = flst_get_first(header + FSP_FREE, mtr);
1526
if (fil_addr_is_null(first)) {
1528
return(NULL); /* No free extents left */
1531
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1534
flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1539
/**********************************************************************//**
1540
Allocates a single free page from a space. The page is marked as used.
1541
@return the page offset, FIL_NULL if no page could be allocated */
1544
fsp_alloc_free_page(
1545
/*================*/
1546
ulint space, /*!< in: space id */
1547
ulint zip_size,/*!< in: compressed page size in bytes
1548
or 0 for uncompressed pages */
1549
ulint hint, /*!< in: hint of which page would be desirable */
1550
mtr_t* mtr) /*!< in: mtr handle */
1552
fsp_header_t* header;
1564
header = fsp_get_space_header(space, zip_size, mtr);
1566
/* Get the hinted descriptor */
1567
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1569
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1570
/* Ok, we can take this extent */
1572
/* Else take the first extent in free_frag list */
1573
first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1575
if (fil_addr_is_null(first)) {
1576
/* There are no partially full fragments: allocate
1577
a free extent and add it to the FREE_FRAG list. NOTE
1578
that the allocation may have as a side-effect that an
1579
extent containing a descriptor page is added to the
1580
FREE_FRAG list. But we will allocate our page from the
1581
the free extent anyway. */
1583
descr = fsp_alloc_free_extent(space, zip_size,
1586
if (descr == NULL) {
1587
/* No free space left */
1592
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1593
flst_add_last(header + FSP_FREE_FRAG,
1594
descr + XDES_FLST_NODE, mtr);
1596
descr = xdes_lst_get_descriptor(space, zip_size,
1600
/* Reset the hint */
1604
/* Now we have in descr an extent with at least one free page. Look
1605
for a free page in the extent. */
1607
free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1608
hint % FSP_EXTENT_SIZE, mtr);
1609
if (free == ULINT_UNDEFINED) {
1611
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1617
page_no = xdes_get_offset(descr) + free;
1619
space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1621
if (space_size <= page_no) {
1622
/* It must be that we are extending a single-table tablespace
1623
whose size is still < 64 pages */
1626
if (page_no >= FSP_EXTENT_SIZE) {
1628
"InnoDB: Error: trying to extend a"
1629
" single-table tablespace %lu\n"
1630
"InnoDB: by single page(s) though the"
1631
" space size %lu. Page no %lu.\n",
1632
(ulong) space, (ulong) space_size,
1636
success = fsp_try_extend_data_file_with_pages(space, page_no,
1639
/* No disk space left */
1644
xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1646
/* Update the FRAG_N_USED field */
1647
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1650
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1652
if (xdes_is_full(descr, mtr)) {
1653
/* The fragment is full: move it to another list */
1654
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1656
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1658
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1660
mlog_write_ulint(header + FSP_FRAG_N_USED,
1661
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1665
/* Initialize the allocated page to the buffer pool, so that it can
1666
be obtained immediately with buf_page_get without need for a disk
1669
buf_page_create(space, page_no, zip_size, mtr);
1671
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1672
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1674
/* Prior contents of the page should be ignored */
1675
fsp_init_file_page(block, mtr);
1680
/**********************************************************************//**
1681
Frees a single page of a space. The page is marked as free and clean. */
1686
ulint space, /*!< in: space id */
1687
ulint zip_size,/*!< in: compressed page size in bytes
1688
or 0 for uncompressed pages */
1689
ulint page, /*!< in: page offset */
1690
mtr_t* mtr) /*!< in: mtr handle */
1692
fsp_header_t* header;
1699
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1701
header = fsp_get_space_header(space, zip_size, mtr);
1703
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1705
state = xdes_get_state(descr, mtr);
1707
if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1709
"InnoDB: Error: File space extent descriptor"
1710
" of page %lu has state %lu\n",
1713
fputs("InnoDB: Dump of descriptor: ", stderr);
1714
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1717
if (state == XDES_FREE) {
1718
/* We put here some fault tolerance: if the page
1719
is already free, return without doing anything! */
1727
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1729
"InnoDB: Error: File space extent descriptor"
1730
" of page %lu says it is free\n"
1731
"InnoDB: Dump of descriptor: ", (ulong) page);
1732
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1735
/* We put here some fault tolerance: if the page
1736
is already free, return without doing anything! */
1741
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1742
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1744
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1746
if (state == XDES_FULL_FRAG) {
1747
/* The fragment was full: move it to another list */
1748
flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1750
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1751
flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1753
mlog_write_ulint(header + FSP_FRAG_N_USED,
1754
frag_n_used + FSP_EXTENT_SIZE - 1,
1757
ut_a(frag_n_used > 0);
1758
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1762
if (xdes_is_free(descr, mtr)) {
1763
/* The extent has become free: move it to another list */
1764
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1766
fsp_free_extent(space, zip_size, page, mtr);
1770
/**********************************************************************//**
1771
Returns an extent to the free list of a space. */
1776
ulint space, /*!< in: space id */
1777
ulint zip_size,/*!< in: compressed page size in bytes
1778
or 0 for uncompressed pages */
1779
ulint page, /*!< in: page offset in the extent */
1780
mtr_t* mtr) /*!< in: mtr */
1782
fsp_header_t* header;
1787
header = fsp_get_space_header(space, zip_size, mtr);
1789
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1791
if (xdes_get_state(descr, mtr) == XDES_FREE) {
1793
ut_print_buf(stderr, (byte*)descr - 500, 1000);
1799
xdes_init(descr, mtr);
1801
flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1804
/**********************************************************************//**
1805
Returns the nth inode slot on an inode page.
1806
@return segment inode */
1809
fsp_seg_inode_page_get_nth_inode(
1810
/*=============================*/
1811
page_t* page, /*!< in: segment inode page */
1812
ulint i, /*!< in: inode index on page */
1813
ulint zip_size __attribute__((unused)),
1814
/*!< in: compressed page size, or 0 */
1815
mtr_t* mtr __attribute__((unused)))
1816
/*!< in: mini-transaction handle */
1818
ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1819
ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1821
return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1824
/**********************************************************************//**
1825
Looks for a used segment inode on a segment inode page.
1826
@return segment inode index, or ULINT_UNDEFINED if not found */
1829
fsp_seg_inode_page_find_used(
1830
/*=========================*/
1831
page_t* page, /*!< in: segment inode page */
1832
ulint zip_size,/*!< in: compressed page size, or 0 */
1833
mtr_t* mtr) /*!< in: mini-transaction handle */
1836
fseg_inode_t* inode;
1838
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1840
inode = fsp_seg_inode_page_get_nth_inode(
1841
page, i, zip_size, mtr);
1843
if (mach_read_from_8(inode + FSEG_ID)) {
1846
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1847
== FSEG_MAGIC_N_VALUE);
1852
return(ULINT_UNDEFINED);
1855
/**********************************************************************//**
1856
Looks for an unused segment inode on a segment inode page.
1857
@return segment inode index, or ULINT_UNDEFINED if not found */
1860
fsp_seg_inode_page_find_free(
1861
/*=========================*/
1862
page_t* page, /*!< in: segment inode page */
1863
ulint i, /*!< in: search forward starting from this index */
1864
ulint zip_size,/*!< in: compressed page size, or 0 */
1865
mtr_t* mtr) /*!< in: mini-transaction handle */
1867
fseg_inode_t* inode;
1869
for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1871
inode = fsp_seg_inode_page_get_nth_inode(
1872
page, i, zip_size, mtr);
1874
if (!mach_read_from_8(inode + FSEG_ID)) {
1875
/* This is unused */
1880
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1881
== FSEG_MAGIC_N_VALUE);
1884
return(ULINT_UNDEFINED);
1887
/**********************************************************************//**
1888
Allocates a new file segment inode page.
1889
@return TRUE if could be allocated */
1892
fsp_alloc_seg_inode_page(
1893
/*=====================*/
1894
fsp_header_t* space_header, /*!< in: space header */
1895
mtr_t* mtr) /*!< in: mini-transaction handle */
1897
fseg_inode_t* inode;
1905
ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1907
space = page_get_space_id(page_align(space_header));
1908
zip_size = dict_table_flags_to_zip_size(
1909
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1911
page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
1913
if (page_no == FIL_NULL) {
1918
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1919
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1921
block->check_index_page_at_flush = FALSE;
1923
page = buf_block_get_frame(block);
1925
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
1928
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1930
inode = fsp_seg_inode_page_get_nth_inode(page, i,
1933
mlog_write_ull(inode + FSEG_ID, 0, mtr);
1936
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1937
page + FSEG_INODE_PAGE_NODE, mtr);
1941
/**********************************************************************//**
1942
Allocates a new file segment inode.
1943
@return segment inode, or NULL if not enough space */
1946
fsp_alloc_seg_inode(
1947
/*================*/
1948
fsp_header_t* space_header, /*!< in: space header */
1949
mtr_t* mtr) /*!< in: mini-transaction handle */
1954
fseg_inode_t* inode;
1959
ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1961
if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1962
/* Allocate a new segment inode page */
1964
success = fsp_alloc_seg_inode_page(space_header, mtr);
1972
page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1974
zip_size = dict_table_flags_to_zip_size(
1975
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1976
block = buf_page_get(page_get_space_id(page_align(space_header)),
1977
zip_size, page_no, RW_X_LATCH, mtr);
1978
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1980
page = buf_block_get_frame(block);
1982
n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1984
ut_a(n != ULINT_UNDEFINED);
1986
inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1988
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1990
/* There are no other unused headers left on the page: move it
1993
flst_remove(space_header + FSP_SEG_INODES_FREE,
1994
page + FSEG_INODE_PAGE_NODE, mtr);
1996
flst_add_last(space_header + FSP_SEG_INODES_FULL,
1997
page + FSEG_INODE_PAGE_NODE, mtr);
2000
ut_ad(!mach_read_from_8(inode + FSEG_ID)
2001
|| mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2005
/**********************************************************************//**
2006
Frees a file segment inode. */
2011
ulint space, /*!< in: space id */
2012
ulint zip_size,/*!< in: compressed page size in bytes
2013
or 0 for uncompressed pages */
2014
fseg_inode_t* inode, /*!< in: segment inode */
2015
mtr_t* mtr) /*!< in: mini-transaction handle */
2018
fsp_header_t* space_header;
2020
page = page_align(inode);
2022
space_header = fsp_get_space_header(space, zip_size, mtr);
2024
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2027
== fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
2029
/* Move the page to another list */
2031
flst_remove(space_header + FSP_SEG_INODES_FULL,
2032
page + FSEG_INODE_PAGE_NODE, mtr);
2034
flst_add_last(space_header + FSP_SEG_INODES_FREE,
2035
page + FSEG_INODE_PAGE_NODE, mtr);
2038
mlog_write_ull(inode + FSEG_ID, 0, mtr);
2039
mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
2042
== fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
2044
/* There are no other used headers left on the page: free it */
2046
flst_remove(space_header + FSP_SEG_INODES_FREE,
2047
page + FSEG_INODE_PAGE_NODE, mtr);
2049
fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
2053
/**********************************************************************//**
2054
Returns the file segment inode, page x-latched.
2055
@return segment inode, page x-latched; NULL if the inode is free */
2060
fseg_header_t* header, /*!< in: segment header */
2061
ulint space, /*!< in: space id */
2062
ulint zip_size,/*!< in: compressed page size in bytes
2063
or 0 for uncompressed pages */
2064
mtr_t* mtr) /*!< in: mtr handle */
2066
fil_addr_t inode_addr;
2067
fseg_inode_t* inode;
2069
inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
2070
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
2071
ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
2073
inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
2075
if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
2079
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2080
== FSEG_MAGIC_N_VALUE);
2086
/**********************************************************************//**
2087
Returns the file segment inode, page x-latched.
2088
@return segment inode, page x-latched */
2093
fseg_header_t* header, /*!< in: segment header */
2094
ulint space, /*!< in: space id */
2095
ulint zip_size,/*!< in: compressed page size in bytes
2096
or 0 for uncompressed pages */
2097
mtr_t* mtr) /*!< in: mtr handle */
2100
= fseg_inode_try_get(header, space, zip_size, mtr);
2105
/**********************************************************************//**
2106
Gets the page number from the nth fragment page slot.
2107
@return page number, FIL_NULL if not in use */
2110
fseg_get_nth_frag_page_no(
2111
/*======================*/
2112
fseg_inode_t* inode, /*!< in: segment inode */
2113
ulint n, /*!< in: slot index */
2114
mtr_t* mtr __attribute__((unused))) /*!< in: mtr handle */
2116
ut_ad(inode && mtr);
2117
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2118
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2119
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2120
return(mach_read_from_4(inode + FSEG_FRAG_ARR
2121
+ n * FSEG_FRAG_SLOT_SIZE));
2124
/**********************************************************************//**
2125
Sets the page number in the nth fragment page slot. */
2128
fseg_set_nth_frag_page_no(
2129
/*======================*/
2130
fseg_inode_t* inode, /*!< in: segment inode */
2131
ulint n, /*!< in: slot index */
2132
ulint page_no,/*!< in: page number to set */
2133
mtr_t* mtr) /*!< in: mtr handle */
2135
ut_ad(inode && mtr);
2136
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2137
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2138
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2140
mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
2141
page_no, MLOG_4BYTES, mtr);
2144
/**********************************************************************//**
2145
Finds a fragment page slot which is free.
2146
@return slot index; ULINT_UNDEFINED if none found */
2149
fseg_find_free_frag_page_slot(
2150
/*==========================*/
2151
fseg_inode_t* inode, /*!< in: segment inode */
2152
mtr_t* mtr) /*!< in: mtr handle */
2157
ut_ad(inode && mtr);
2159
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2160
page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
2162
if (page_no == FIL_NULL) {
2168
return(ULINT_UNDEFINED);
2171
/**********************************************************************//**
2172
Finds a fragment page slot which is used and last in the array.
2173
@return slot index; ULINT_UNDEFINED if none found */
2176
fseg_find_last_used_frag_page_slot(
2177
/*===============================*/
2178
fseg_inode_t* inode, /*!< in: segment inode */
2179
mtr_t* mtr) /*!< in: mtr handle */
2184
ut_ad(inode && mtr);
2186
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2187
page_no = fseg_get_nth_frag_page_no(
2188
inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
2190
if (page_no != FIL_NULL) {
2192
return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
2196
return(ULINT_UNDEFINED);
2199
/**********************************************************************//**
2200
Calculates reserved fragment page slots.
2201
@return number of fragment pages */
2204
fseg_get_n_frag_pages(
2205
/*==================*/
2206
fseg_inode_t* inode, /*!< in: segment inode */
2207
mtr_t* mtr) /*!< in: mtr handle */
2212
ut_ad(inode && mtr);
2214
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2215
if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2223
/**********************************************************************//**
2224
Creates a new segment.
2225
@return the block where the segment header is placed, x-latched, NULL
2226
if could not create segment because of lack of space */
2229
fseg_create_general(
2230
/*================*/
2231
ulint space, /*!< in: space id */
2232
ulint page, /*!< in: page where the segment header is placed: if
2233
this is != 0, the page must belong to another segment,
2234
if this is 0, a new page will be allocated and it
2235
will belong to the created segment */
2236
ulint byte_offset, /*!< in: byte offset of the created segment header
2238
ibool has_done_reservation, /*!< in: TRUE if the caller has already
2239
done the reservation for the pages with
2240
fsp_reserve_free_extents (at least 2 extents: one for
2241
the inode and the other for the segment) then there is
2242
no need to do the check for this individual
2244
mtr_t* mtr) /*!< in: mtr */
2248
fsp_header_t* space_header;
2249
fseg_inode_t* inode;
2251
buf_block_t* block = 0; /* remove warning */
2252
fseg_header_t* header = 0; /* remove warning */
2259
ut_ad(byte_offset + FSEG_HEADER_SIZE
2260
<= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2262
latch = fil_space_get_latch(space, &flags);
2263
zip_size = dict_table_flags_to_zip_size(flags);
2266
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2267
header = byte_offset + buf_block_get_frame(block);
2270
ut_ad(!mutex_own(&kernel_mutex)
2271
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2273
mtr_x_lock(latch, mtr);
2275
if (rw_lock_get_x_lock_count(latch) == 1) {
2276
/* This thread did not own the latch before this call: free
2277
excess pages from the insert buffer free list */
2279
if (space == IBUF_SPACE_ID) {
2280
ibuf_free_excess_pages();
2284
if (!has_done_reservation) {
2285
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2292
space_header = fsp_get_space_header(space, zip_size, mtr);
2294
inode = fsp_alloc_seg_inode(space_header, mtr);
2296
if (inode == NULL) {
2301
/* Read the next segment id from space header and increment the
2302
value in space header */
2304
seg_id = mach_read_from_8(space_header + FSP_SEG_ID);
2306
mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr);
2308
mlog_write_ull(inode + FSEG_ID, seg_id, mtr);
2309
mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2311
flst_init(inode + FSEG_FREE, mtr);
2312
flst_init(inode + FSEG_NOT_FULL, mtr);
2313
flst_init(inode + FSEG_FULL, mtr);
2315
mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2317
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2318
fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2322
page = fseg_alloc_free_page_low(space, zip_size,
2323
inode, 0, FSP_UP, mtr);
2325
if (page == FIL_NULL) {
2327
fsp_free_seg_inode(space, zip_size, inode, mtr);
2332
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2333
header = byte_offset + buf_block_get_frame(block);
2334
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2335
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
2338
mlog_write_ulint(header + FSEG_HDR_OFFSET,
2339
page_offset(inode), MLOG_2BYTES, mtr);
2341
mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2342
page_get_page_no(page_align(inode)),
2345
mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2348
if (!has_done_reservation) {
2350
fil_space_release_free_extents(space, n_reserved);
2356
/**********************************************************************//**
2357
Creates a new segment.
2358
@return the block where the segment header is placed, x-latched, NULL
2359
if could not create segment because of lack of space */
2364
ulint space, /*!< in: space id */
2365
ulint page, /*!< in: page where the segment header is placed: if
2366
this is != 0, the page must belong to another segment,
2367
if this is 0, a new page will be allocated and it
2368
will belong to the created segment */
2369
ulint byte_offset, /*!< in: byte offset of the created segment header
2371
mtr_t* mtr) /*!< in: mtr */
2373
return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2376
/**********************************************************************//**
2377
Calculates the number of pages reserved by a segment, and how many pages are
2379
@return number of reserved pages */
2382
fseg_n_reserved_pages_low(
2383
/*======================*/
2384
fseg_inode_t* inode, /*!< in: segment inode */
2385
ulint* used, /*!< out: number of pages used (not
2386
more than reserved) */
2387
mtr_t* mtr) /*!< in: mtr handle */
2391
ut_ad(inode && used && mtr);
2392
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2394
*used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2395
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2396
+ fseg_get_n_frag_pages(inode, mtr);
2398
ret = fseg_get_n_frag_pages(inode, mtr)
2399
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2400
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2401
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2406
/**********************************************************************//**
2407
Calculates the number of pages reserved by a segment, and how many pages are
2409
@return number of reserved pages */
2412
fseg_n_reserved_pages(
2413
/*==================*/
2414
fseg_header_t* header, /*!< in: segment header */
2415
ulint* used, /*!< out: number of pages used (<= reserved) */
2416
mtr_t* mtr) /*!< in: mtr handle */
2419
fseg_inode_t* inode;
2425
space = page_get_space_id(page_align(header));
2426
latch = fil_space_get_latch(space, &flags);
2427
zip_size = dict_table_flags_to_zip_size(flags);
2429
ut_ad(!mutex_own(&kernel_mutex)
2430
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2432
mtr_x_lock(latch, mtr);
2434
inode = fseg_inode_get(header, space, zip_size, mtr);
2436
ret = fseg_n_reserved_pages_low(inode, used, mtr);
2441
/*********************************************************************//**
2442
Tries to fill the free list of a segment with consecutive free extents.
2443
This happens if the segment is big enough to allow extents in the free list,
2444
the free list is empty, and the extents can be allocated consecutively from
2448
fseg_fill_free_list(
2449
/*================*/
2450
fseg_inode_t* inode, /*!< in: segment inode */
2451
ulint space, /*!< in: space id */
2452
ulint zip_size,/*!< in: compressed page size in bytes
2453
or 0 for uncompressed pages */
2454
ulint hint, /*!< in: hint which extent would be good as
2456
mtr_t* mtr) /*!< in: mtr */
2464
ut_ad(inode && mtr);
2465
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2467
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2469
if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2471
/* The segment is too small to allow extents in free list */
2476
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2477
/* Free list is not empty */
2482
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2483
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2486
|| (XDES_FREE != xdes_get_state(descr, mtr))) {
2488
/* We cannot allocate the desired extent: stop */
2493
descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2495
xdes_set_state(descr, XDES_FSEG, mtr);
2497
seg_id = mach_read_from_8(inode + FSEG_ID);
2498
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2499
== FSEG_MAGIC_N_VALUE);
2500
mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2502
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2503
hint += FSP_EXTENT_SIZE;
2507
/*********************************************************************//**
2508
Allocates a free extent for the segment: looks first in the free list of the
2509
segment, then tries to allocate from the space free list. NOTE that the extent
2510
returned still resides in the segment free list, it is not yet taken off it!
2511
@return allocated extent, still placed in the segment free list, NULL
2512
if could not be allocated */
2515
fseg_alloc_free_extent(
2516
/*===================*/
2517
fseg_inode_t* inode, /*!< in: segment inode */
2518
ulint space, /*!< in: space id */
2519
ulint zip_size,/*!< in: compressed page size in bytes
2520
or 0 for uncompressed pages */
2521
mtr_t* mtr) /*!< in: mtr */
2527
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2528
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2530
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2531
/* Segment free list is not empty, allocate from it */
2533
first = flst_get_first(inode + FSEG_FREE, mtr);
2535
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2537
/* Segment free list was empty, allocate from space */
2538
descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2540
if (descr == NULL) {
2545
seg_id = mach_read_from_8(inode + FSEG_ID);
2547
xdes_set_state(descr, XDES_FSEG, mtr);
2548
mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2549
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2551
/* Try to fill the segment free list */
2552
fseg_fill_free_list(inode, space, zip_size,
2553
xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2560
/**********************************************************************//**
2561
Allocates a single free page from a segment. This function implements
2562
the intelligent allocation strategy which tries to minimize file space
2564
@return the allocated page number, FIL_NULL if no page could be allocated */
2567
fseg_alloc_free_page_low(
2568
/*=====================*/
2569
ulint space, /*!< in: space */
2570
ulint zip_size,/*!< in: compressed page size in bytes
2571
or 0 for uncompressed pages */
2572
fseg_inode_t* seg_inode, /*!< in: segment inode */
2573
ulint hint, /*!< in: hint of which page would be desirable */
2574
byte direction, /*!< in: if the new page is needed because
2575
of an index page split, and records are
2576
inserted there in order, into which
2577
direction they go alphabetically: FSP_DOWN,
2578
FSP_UP, FSP_NO_DIR */
2579
mtr_t* mtr) /*!< in: mtr handle */
2581
fsp_header_t* space_header;
2586
xdes_t* descr; /*!< extent of the hinted page */
2587
ulint ret_page; /*!< the allocated page offset, FIL_NULL
2588
if could not be allocated */
2589
xdes_t* ret_descr; /*!< the extent of the allocated page */
2590
ibool frag_page_allocated = FALSE;
2595
ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2596
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2597
== FSEG_MAGIC_N_VALUE);
2598
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2599
seg_id = mach_read_from_8(seg_inode + FSEG_ID);
2603
reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2605
space_header = fsp_get_space_header(space, zip_size, mtr);
2607
descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2609
if (descr == NULL) {
2610
/* Hint outside space or too high above free limit: reset
2613
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2616
/* In the big if-else below we look for ret_page and ret_descr */
2617
/*-------------------------------------------------------------*/
2618
if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2619
&& mach_read_from_8(descr + XDES_ID) == seg_id
2620
&& (xdes_get_bit(descr, XDES_FREE_BIT,
2621
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2623
/* 1. We can take the hinted page
2624
=================================*/
2627
/*-----------------------------------------------------------*/
2628
} else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2629
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2630
&& (used >= FSEG_FRAG_LIMIT)) {
2632
/* 2. We allocate the free extent from space and can take
2633
=========================================================
2636
ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2638
ut_a(ret_descr == descr);
2640
xdes_set_state(ret_descr, XDES_FSEG, mtr);
2641
mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
2642
flst_add_last(seg_inode + FSEG_FREE,
2643
ret_descr + XDES_FLST_NODE, mtr);
2645
/* Try to fill the segment free list */
2646
fseg_fill_free_list(seg_inode, space, zip_size,
2647
hint + FSP_EXTENT_SIZE, mtr);
2649
/*-----------------------------------------------------------*/
2650
} else if ((direction != FSP_NO_DIR)
2651
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2652
&& (used >= FSEG_FRAG_LIMIT)
2654
= fseg_alloc_free_extent(seg_inode,
2655
space, zip_size, mtr)))) {
2657
/* 3. We take any free extent (which was already assigned above
2658
===============================================================
2659
in the if-condition to ret_descr) and take the lowest or
2660
========================================================
2661
highest page in it, depending on the direction
2662
==============================================*/
2663
ret_page = xdes_get_offset(ret_descr);
2665
if (direction == FSP_DOWN) {
2666
ret_page += FSP_EXTENT_SIZE - 1;
2668
/*-----------------------------------------------------------*/
2669
} else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2670
&& mach_read_from_8(descr + XDES_ID) == seg_id
2671
&& (!xdes_is_full(descr, mtr))) {
2673
/* 4. We can take the page from the same extent as the
2674
======================================================
2675
hinted page (and the extent already belongs to the
2676
==================================================
2680
ret_page = xdes_get_offset(ret_descr)
2681
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2682
hint % FSP_EXTENT_SIZE, mtr);
2683
/*-----------------------------------------------------------*/
2684
} else if (reserved - used > 0) {
2685
/* 5. We take any unused page from the segment
2686
==============================================*/
2689
if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2690
first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2692
} else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2693
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2699
ret_descr = xdes_lst_get_descriptor(space, zip_size,
2701
ret_page = xdes_get_offset(ret_descr)
2702
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2704
/*-----------------------------------------------------------*/
2705
} else if (used < FSEG_FRAG_LIMIT) {
2706
/* 6. We allocate an individual page from the space
2707
===================================================*/
2708
ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
2711
frag_page_allocated = TRUE;
2713
if (ret_page != FIL_NULL) {
2714
/* Put the page in the fragment page array of the
2716
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2717
ut_a(n != FIL_NULL);
2719
fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2722
/*-----------------------------------------------------------*/
2724
/* 7. We allocate a new extent and take its first page
2725
======================================================*/
2726
ret_descr = fseg_alloc_free_extent(seg_inode,
2727
space, zip_size, mtr);
2729
if (ret_descr == NULL) {
2730
ret_page = FIL_NULL;
2732
ret_page = xdes_get_offset(ret_descr);
2736
if (ret_page == FIL_NULL) {
2737
/* Page could not be allocated */
2743
space_size = fil_space_get_size(space);
2745
if (space_size <= ret_page) {
2746
/* It must be that we are extending a single-table
2747
tablespace whose size is still < 64 pages */
2749
if (ret_page >= FSP_EXTENT_SIZE) {
2751
"InnoDB: Error (2): trying to extend"
2752
" a single-table tablespace %lu\n"
2753
"InnoDB: by single page(s) though"
2754
" the space size %lu. Page no %lu.\n",
2755
(ulong) space, (ulong) space_size,
2760
success = fsp_try_extend_data_file_with_pages(
2761
space, ret_page, space_header, mtr);
2763
/* No disk space left */
2769
if (!frag_page_allocated) {
2770
/* Initialize the allocated page to buffer pool, so that it
2771
can be obtained immediately with buf_page_get without need
2774
ulint zip_size = dict_table_flags_to_zip_size(
2775
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
2777
block = buf_page_create(space, ret_page, zip_size, mtr);
2778
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
2780
if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
2781
ret_page, RW_X_LATCH,
2786
/* The prior contents of the page should be ignored */
2787
fsp_init_file_page(block, mtr);
2789
/* At this point we know the extent and the page offset.
2790
The extent is still in the appropriate list (FSEG_NOT_FULL
2791
or FSEG_FREE), and the page is not yet marked as used. */
2793
ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
2795
ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2796
ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2798
fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
2801
buf_reset_check_index_page_at_flush(space, ret_page);
2806
/**********************************************************************//**
2807
Allocates a single free page from a segment. This function implements
2808
the intelligent allocation strategy which tries to minimize file space
2810
@return allocated page offset, FIL_NULL if no page could be allocated */
2813
fseg_alloc_free_page_general(
2814
/*=========================*/
2815
fseg_header_t* seg_header,/*!< in: segment header */
2816
ulint hint, /*!< in: hint of which page would be desirable */
2817
byte direction,/*!< in: if the new page is needed because
2818
of an index page split, and records are
2819
inserted there in order, into which
2820
direction they go alphabetically: FSP_DOWN,
2821
FSP_UP, FSP_NO_DIR */
2822
ibool has_done_reservation, /*!< in: TRUE if the caller has
2823
already done the reservation for the page
2824
with fsp_reserve_free_extents, then there
2825
is no need to do the check for this individual
2827
mtr_t* mtr) /*!< in: mtr handle */
2829
fseg_inode_t* inode;
2838
space = page_get_space_id(page_align(seg_header));
2840
latch = fil_space_get_latch(space, &flags);
2842
zip_size = dict_table_flags_to_zip_size(flags);
2844
ut_ad(!mutex_own(&kernel_mutex)
2845
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2847
mtr_x_lock(latch, mtr);
2849
if (rw_lock_get_x_lock_count(latch) == 1) {
2850
/* This thread did not own the latch before this call: free
2851
excess pages from the insert buffer free list */
2853
if (space == IBUF_SPACE_ID) {
2854
ibuf_free_excess_pages();
2858
inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2860
if (!has_done_reservation) {
2861
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2868
page_no = fseg_alloc_free_page_low(space, zip_size,
2869
inode, hint, direction, mtr);
2870
if (!has_done_reservation) {
2871
fil_space_release_free_extents(space, n_reserved);
2877
/**********************************************************************//**
2878
Allocates a single free page from a segment. This function implements
2879
the intelligent allocation strategy which tries to minimize file space
2881
@return allocated page offset, FIL_NULL if no page could be allocated */
2884
fseg_alloc_free_page(
2885
/*=================*/
2886
fseg_header_t* seg_header,/*!< in: segment header */
2887
ulint hint, /*!< in: hint of which page would be desirable */
2888
byte direction,/*!< in: if the new page is needed because
2889
of an index page split, and records are
2890
inserted there in order, into which
2891
direction they go alphabetically: FSP_DOWN,
2892
FSP_UP, FSP_NO_DIR */
2893
mtr_t* mtr) /*!< in: mtr handle */
2895
return(fseg_alloc_free_page_general(seg_header, hint, direction,
2899
/**********************************************************************//**
2900
Checks that we have at least 2 frag pages free in the first extent of a
2901
single-table tablespace, and they are also physically initialized to the data
2902
file. That is we have already extended the data file so that those pages are
2903
inside the data file. If not, this function extends the tablespace with
2905
@return TRUE if there were >= 3 free pages, or we were able to extend */
2908
fsp_reserve_free_pages(
2909
/*===================*/
2910
ulint space, /*!< in: space id, must be != 0 */
2911
fsp_header_t* space_header, /*!< in: header of that space,
2913
ulint size, /*!< in: size of the tablespace in pages,
2914
must be < FSP_EXTENT_SIZE / 2 */
2915
mtr_t* mtr) /*!< in: mtr */
2921
ut_a(size < FSP_EXTENT_SIZE / 2);
2923
descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2925
n_used = xdes_get_n_used(descr, mtr);
2927
ut_a(n_used <= size);
2929
if (size >= n_used + 2) {
2934
return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2935
space_header, mtr));
2938
/**********************************************************************//**
2939
Reserves free pages from a tablespace. All mini-transactions which may
2940
use several pages from the tablespace should call this function beforehand
2941
and reserve enough free extents so that they certainly will be able
2942
to do their operation, like a B-tree page split, fully. Reservations
2943
must be released with function fil_space_release_free_extents!
2945
The alloc_type below has the following meaning: FSP_NORMAL means an
2946
operation which will probably result in more space usage, like an
2947
insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
2948
deleting rows, then this allocation will in the long run result in
2949
less space usage (after a purge); FSP_CLEANING means allocation done
2950
in a physical record delete (like in a purge) or other cleaning operation
2951
which will result in less space usage in the long run. We prefer the latter
2952
two types of allocation: when space is scarce, FSP_NORMAL allocations
2953
will not succeed, but the latter two allocations will succeed, if possible.
2954
The purpose is to avoid dead end where the database is full but the
2955
user cannot free any space because these freeing operations temporarily
2958
Single-table tablespaces whose size is < 32 pages are a special case. In this
2959
function we would liberally reserve several 64 page extents for every page
2960
split or merge in a B-tree. But we do not want to waste disk space if the table
2961
only occupies < 32 pages. That is why we apply different rules in that special
2962
case, just ensuring that there are 3 free pages available.
2963
@return TRUE if we were able to make the reservation */
2966
fsp_reserve_free_extents(
2967
/*=====================*/
2968
ulint* n_reserved,/*!< out: number of extents actually reserved; if we
2969
return TRUE and the tablespace size is < 64 pages,
2970
then this can be 0, otherwise it is n_ext */
2971
ulint space, /*!< in: space id */
2972
ulint n_ext, /*!< in: number of extents to reserve */
2973
ulint alloc_type,/*!< in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
2974
mtr_t* mtr) /*!< in: mtr */
2976
fsp_header_t* space_header;
2978
ulint n_free_list_ext;
2987
ulint n_pages_added;
2990
*n_reserved = n_ext;
2992
latch = fil_space_get_latch(space, &flags);
2993
zip_size = dict_table_flags_to_zip_size(flags);
2995
ut_ad(!mutex_own(&kernel_mutex)
2996
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2998
mtr_x_lock(latch, mtr);
3000
space_header = fsp_get_space_header(space, zip_size, mtr);
3002
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
3004
if (size < FSP_EXTENT_SIZE / 2) {
3005
/* Use different rules for small single-table tablespaces */
3007
return(fsp_reserve_free_pages(space, space_header, size, mtr));
3010
n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
3012
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3015
/* Below we play safe when counting free extents above the free limit:
3016
some of them will contain extent descriptor pages, and therefore
3017
will not be free extents */
3019
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3021
if (n_free_up > 0) {
3024
n_free_up -= n_free_up
3025
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3027
n_free_up -= n_free_up
3028
/ (zip_size / FSP_EXTENT_SIZE);
3032
n_free = n_free_list_ext + n_free_up;
3034
if (alloc_type == FSP_NORMAL) {
3035
/* We reserve 1 extent + 0.5 % of the space size to undo logs
3036
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3037
code is duplicated in the function below! */
3039
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3041
if (n_free <= reserve + n_ext) {
3045
} else if (alloc_type == FSP_UNDO) {
3046
/* We reserve 0.5 % of the space size to cleaning operations */
3048
reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
3050
if (n_free <= reserve + n_ext) {
3055
ut_a(alloc_type == FSP_CLEANING);
3058
success = fil_space_reserve_free_extents(space, n_free, n_ext);
3064
success = fsp_try_extend_data_file(&n_pages_added, space,
3066
if (success && n_pages_added > 0) {
3074
/**********************************************************************//**
3075
This function should be used to get information on how much we still
3076
will be able to insert new data to the database without running out the
3077
tablespace. Only free extents are taken into account and we also subtract
3078
the safety margin required by the above function fsp_reserve_free_extents.
3079
@return available space in kB */
3082
fsp_get_available_space_in_free_extents(
3083
/*====================================*/
3084
ulint space) /*!< in: space id */
3086
fsp_header_t* space_header;
3087
ulint n_free_list_ext;
3098
ut_ad(!mutex_own(&kernel_mutex));
3102
latch = fil_space_get_latch(space, &flags);
3103
zip_size = dict_table_flags_to_zip_size(flags);
3105
mtr_x_lock(latch, &mtr);
3107
space_header = fsp_get_space_header(space, zip_size, &mtr);
3109
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
3111
n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
3113
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3117
if (size < FSP_EXTENT_SIZE) {
3118
ut_a(space != 0); /* This must be a single-table
3121
return(0); /* TODO: count free frag pages and
3122
return a value based on that */
3125
/* Below we play safe when counting free extents above the free limit:
3126
some of them will contain extent descriptor pages, and therefore
3127
will not be free extents */
3129
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3131
if (n_free_up > 0) {
3134
n_free_up -= n_free_up
3135
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3137
n_free_up -= n_free_up
3138
/ (zip_size / FSP_EXTENT_SIZE);
3142
n_free = n_free_list_ext + n_free_up;
3144
/* We reserve 1 extent + 0.5 % of the space size to undo logs
3145
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3146
code is duplicated in the function above! */
3148
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3150
if (reserve > n_free) {
3155
return((ullint) (n_free - reserve)
3157
* (UNIV_PAGE_SIZE / 1024));
3159
return((ullint) (n_free - reserve)
3161
* (zip_size / 1024));
3165
/********************************************************************//**
3166
Marks a page used. The page must reside within the extents of the given
3170
fseg_mark_page_used(
3171
/*================*/
3172
fseg_inode_t* seg_inode,/*!< in: segment inode */
3173
ulint space, /*!< in: space id */
3174
ulint zip_size,/*!< in: compressed page size in bytes
3175
or 0 for uncompressed pages */
3176
ulint page, /*!< in: page offset */
3177
mtr_t* mtr) /*!< in: mtr */
3180
ulint not_full_n_used;
3182
ut_ad(seg_inode && mtr);
3183
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3184
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3185
== FSEG_MAGIC_N_VALUE);
3187
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3189
ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
3190
== mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
3192
if (xdes_is_free(descr, mtr)) {
3193
/* We move the extent from the free list to the
3195
flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3197
flst_add_last(seg_inode + FSEG_NOT_FULL,
3198
descr + XDES_FLST_NODE, mtr);
3201
ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
3203
/* We mark the page as used */
3204
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3206
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3209
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3211
if (xdes_is_full(descr, mtr)) {
3212
/* We move the extent from the NOT_FULL list to the
3214
flst_remove(seg_inode + FSEG_NOT_FULL,
3215
descr + XDES_FLST_NODE, mtr);
3216
flst_add_last(seg_inode + FSEG_FULL,
3217
descr + XDES_FLST_NODE, mtr);
3219
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3220
not_full_n_used - FSP_EXTENT_SIZE,
3225
/**********************************************************************//**
3226
Frees a single page of a segment. */
3231
fseg_inode_t* seg_inode, /*!< in: segment inode */
3232
ulint space, /*!< in: space id */
3233
ulint zip_size,/*!< in: compressed page size in bytes
3234
or 0 for uncompressed pages */
3235
ulint page, /*!< in: page offset */
3236
mtr_t* mtr) /*!< in: mtr handle */
3239
ulint not_full_n_used;
3245
ut_ad(seg_inode && mtr);
3246
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3247
== FSEG_MAGIC_N_VALUE);
3248
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3250
/* Drop search system page hash index if the page is found in
3251
the pool and is hashed */
3253
btr_search_drop_page_hash_when_freed(space, zip_size, page);
3255
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3258
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
3259
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3261
ut_print_buf(stderr, descr, 40);
3263
fprintf(stderr, "\n"
3264
"InnoDB: Serious error! InnoDB is trying to"
3266
"InnoDB: though it is already marked as free"
3267
" in the tablespace!\n"
3268
"InnoDB: The tablespace free space info is corrupt.\n"
3269
"InnoDB: You may need to dump your"
3270
" InnoDB tables and recreate the whole\n"
3271
"InnoDB: database!\n", (ulong) page);
3273
fputs("InnoDB: Please refer to\n"
3274
"InnoDB: " REFMAN "forcing-recovery.html\n"
3275
"InnoDB: about forcing recovery.\n", stderr);
3279
state = xdes_get_state(descr, mtr);
3281
if (state != XDES_FSEG) {
3282
/* The page is in the fragment pages of the segment */
3285
if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3288
fseg_set_nth_frag_page_no(seg_inode, i,
3294
fsp_free_page(space, zip_size, page, mtr);
3299
/* If we get here, the page is in some extent of the segment */
3301
descr_id = mach_read_from_8(descr + XDES_ID);
3302
seg_id = mach_read_from_8(seg_inode + FSEG_ID);
3305
"InnoDB: InnoDB is freeing space %lu page %lu,\n"
3306
"InnoDB: which belongs to descr seg %llu\n"
3307
"InnoDB: segment %llu.\n",
3308
(ulong) space, (ulong) page,
3312
if (UNIV_UNLIKELY(descr_id != seg_id)) {
3313
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3315
ut_print_buf(stderr, descr, 40);
3316
fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3317
ut_print_buf(stderr, seg_inode, 40);
3321
"InnoDB: Serious error: InnoDB is trying to"
3322
" free space %lu page %lu,\n"
3323
"InnoDB: which does not belong to"
3324
" segment %llu but belongs\n"
3325
"InnoDB: to segment %llu.\n",
3326
(ulong) space, (ulong) page,
3332
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3334
if (xdes_is_full(descr, mtr)) {
3335
/* The fragment is full: move it to another list */
3336
flst_remove(seg_inode + FSEG_FULL,
3337
descr + XDES_FLST_NODE, mtr);
3338
flst_add_last(seg_inode + FSEG_NOT_FULL,
3339
descr + XDES_FLST_NODE, mtr);
3340
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3341
not_full_n_used + FSP_EXTENT_SIZE - 1,
3344
ut_a(not_full_n_used > 0);
3345
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3346
not_full_n_used - 1, MLOG_4BYTES, mtr);
3349
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3350
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3352
if (xdes_is_free(descr, mtr)) {
3353
/* The extent has become free: free it to space */
3354
flst_remove(seg_inode + FSEG_NOT_FULL,
3355
descr + XDES_FLST_NODE, mtr);
3356
fsp_free_extent(space, zip_size, page, mtr);
3360
/**********************************************************************//**
3361
Frees a single page of a segment. */
3366
fseg_header_t* seg_header, /*!< in: segment header */
3367
ulint space, /*!< in: space id */
3368
ulint page, /*!< in: page offset */
3369
mtr_t* mtr) /*!< in: mtr handle */
3373
fseg_inode_t* seg_inode;
3376
latch = fil_space_get_latch(space, &flags);
3377
zip_size = dict_table_flags_to_zip_size(flags);
3379
ut_ad(!mutex_own(&kernel_mutex)
3380
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3382
mtr_x_lock(latch, mtr);
3384
seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3386
fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3388
#ifdef UNIV_DEBUG_FILE_ACCESSES
3389
buf_page_set_file_page_was_freed(space, page);
3393
/**********************************************************************//**
3394
Frees an extent of a segment to the space free list. */
3399
fseg_inode_t* seg_inode, /*!< in: segment inode */
3400
ulint space, /*!< in: space id */
3401
ulint zip_size,/*!< in: compressed page size in bytes
3402
or 0 for uncompressed pages */
3403
ulint page, /*!< in: a page in the extent */
3404
mtr_t* mtr) /*!< in: mtr handle */
3406
ulint first_page_in_extent;
3408
ulint not_full_n_used;
3412
ut_ad(seg_inode && mtr);
3414
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3416
ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3417
ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
3418
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3419
== FSEG_MAGIC_N_VALUE);
3421
first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3423
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3424
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3426
/* Drop search system page hash index if the page is
3427
found in the pool and is hashed */
3429
btr_search_drop_page_hash_when_freed(
3430
space, zip_size, first_page_in_extent + i);
3434
if (xdes_is_full(descr, mtr)) {
3435
flst_remove(seg_inode + FSEG_FULL,
3436
descr + XDES_FLST_NODE, mtr);
3437
} else if (xdes_is_free(descr, mtr)) {
3438
flst_remove(seg_inode + FSEG_FREE,
3439
descr + XDES_FLST_NODE, mtr);
3441
flst_remove(seg_inode + FSEG_NOT_FULL,
3442
descr + XDES_FLST_NODE, mtr);
3444
not_full_n_used = mtr_read_ulint(
3445
seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3447
descr_n_used = xdes_get_n_used(descr, mtr);
3448
ut_a(not_full_n_used >= descr_n_used);
3449
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3450
not_full_n_used - descr_n_used,
3454
fsp_free_extent(space, zip_size, page, mtr);
3456
#ifdef UNIV_DEBUG_FILE_ACCESSES
3457
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3459
buf_page_set_file_page_was_freed(space,
3460
first_page_in_extent + i);
3465
/**********************************************************************//**
3466
Frees part of a segment. This function can be used to free a segment by
3467
repeatedly calling this function in different mini-transactions. Doing
3468
the freeing in a single mini-transaction might result in too big a
3470
@return TRUE if freeing completed */
3475
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
3476
resides on the first page of the frag list
3477
of the segment, this pointer becomes obsolete
3478
after the last freeing step */
3479
mtr_t* mtr) /*!< in: mtr */
3484
fseg_inode_t* inode;
3491
space = page_get_space_id(page_align(header));
3492
header_page = page_get_page_no(page_align(header));
3494
latch = fil_space_get_latch(space, &flags);
3495
zip_size = dict_table_flags_to_zip_size(flags);
3497
ut_ad(!mutex_own(&kernel_mutex)
3498
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3500
mtr_x_lock(latch, mtr);
3502
descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3504
/* Check that the header resides on a page which has not been
3508
ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
3509
header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3510
inode = fseg_inode_try_get(header, space, zip_size, mtr);
3512
if (UNIV_UNLIKELY(inode == NULL)) {
3513
fprintf(stderr, "double free of inode from %u:%u\n",
3514
(unsigned) space, (unsigned) header_page);
3518
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3520
if (descr != NULL) {
3521
/* Free the extent held by the segment */
3522
page = xdes_get_offset(descr);
3524
fseg_free_extent(inode, space, zip_size, page, mtr);
3529
/* Free a frag page */
3530
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3532
if (n == ULINT_UNDEFINED) {
3533
/* Freeing completed: free the segment inode */
3534
fsp_free_seg_inode(space, zip_size, inode, mtr);
3539
fseg_free_page_low(inode, space, zip_size,
3540
fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3542
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3544
if (n == ULINT_UNDEFINED) {
3545
/* Freeing completed: free the segment inode */
3546
fsp_free_seg_inode(space, zip_size, inode, mtr);
3554
/**********************************************************************//**
3555
Frees part of a segment. Differs from fseg_free_step because this function
3556
leaves the header page unfreed.
3557
@return TRUE if freeing completed, except the header page */
3560
fseg_free_step_not_header(
3561
/*======================*/
3562
fseg_header_t* header, /*!< in: segment header which must reside on
3563
the first fragment page of the segment */
3564
mtr_t* mtr) /*!< in: mtr */
3569
fseg_inode_t* inode;
3576
space = page_get_space_id(page_align(header));
3578
latch = fil_space_get_latch(space, &flags);
3579
zip_size = dict_table_flags_to_zip_size(flags);
3581
ut_ad(!mutex_own(&kernel_mutex)
3582
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3584
mtr_x_lock(latch, mtr);
3586
inode = fseg_inode_get(header, space, zip_size, mtr);
3588
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3590
if (descr != NULL) {
3591
/* Free the extent held by the segment */
3592
page = xdes_get_offset(descr);
3594
fseg_free_extent(inode, space, zip_size, page, mtr);
3599
/* Free a frag page */
3601
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3603
if (n == ULINT_UNDEFINED) {
3607
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3609
if (page_no == page_get_page_no(page_align(header))) {
3614
fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3619
/**********************************************************************//**
3620
Returns the first extent descriptor for a segment. We think of the extent
3621
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
3623
@return the first extent descriptor, or NULL if none */
3626
fseg_get_first_extent(
3627
/*==================*/
3628
fseg_inode_t* inode, /*!< in: segment inode */
3629
ulint space, /*!< in: space id */
3630
ulint zip_size,/*!< in: compressed page size in bytes
3631
or 0 for uncompressed pages */
3632
mtr_t* mtr) /*!< in: mtr */
3637
ut_ad(inode && mtr);
3639
ut_ad(space == page_get_space_id(page_align(inode)));
3640
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3642
first = fil_addr_null;
3644
if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3646
first = flst_get_first(inode + FSEG_FULL, mtr);
3648
} else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3650
first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3652
} else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3654
first = flst_get_first(inode + FSEG_FREE, mtr);
3657
if (first.page == FIL_NULL) {
3661
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3666
/*******************************************************************//**
3667
Validates a segment.
3668
@return TRUE if ok */
3673
fseg_inode_t* inode, /*!< in: segment inode */
3674
mtr_t* mtr2) /*!< in: mtr */
3680
fil_addr_t node_addr;
3684
ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3685
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3687
space = page_get_space_id(page_align(inode));
3689
seg_id = mach_read_from_8(inode + FSEG_ID);
3690
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3692
flst_validate(inode + FSEG_FREE, mtr2);
3693
flst_validate(inode + FSEG_NOT_FULL, mtr2);
3694
flst_validate(inode + FSEG_FULL, mtr2);
3696
/* Validate FSEG_FREE list */
3697
node_addr = flst_get_first(inode + FSEG_FREE, 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) == 0);
3711
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3712
ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3714
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3718
/* Validate FSEG_NOT_FULL list */
3720
node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3722
while (!fil_addr_is_null(node_addr)) {
3727
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3728
zip_size = dict_table_flags_to_zip_size(flags);
3730
descr = xdes_lst_get_descriptor(space, zip_size,
3733
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3734
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3735
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3736
ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3738
n_used2 += xdes_get_n_used(descr, &mtr);
3740
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3744
/* Validate FSEG_FULL list */
3746
node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3748
while (!fil_addr_is_null(node_addr)) {
3753
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3754
zip_size = dict_table_flags_to_zip_size(flags);
3756
descr = xdes_lst_get_descriptor(space, zip_size,
3759
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3760
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3761
ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3763
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3767
ut_a(n_used == n_used2);
3773
/*******************************************************************//**
3774
Validates a segment.
3775
@return TRUE if ok */
3780
fseg_header_t* header, /*!< in: segment header */
3781
mtr_t* mtr) /*!< in: mtr */
3783
fseg_inode_t* inode;
3789
space = page_get_space_id(page_align(header));
3791
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3792
zip_size = dict_table_flags_to_zip_size(flags);
3794
inode = fseg_inode_get(header, space, zip_size, mtr);
3796
ret = fseg_validate_low(inode, mtr);
3800
#endif /* UNIV_DEBUG */
3802
/*******************************************************************//**
3803
Writes info of a segment. */
3808
fseg_inode_t* inode, /*!< in: segment inode */
3809
mtr_t* mtr) /*!< in: mtr */
3822
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3823
space = page_get_space_id(page_align(inode));
3824
page_no = page_get_page_no(page_align(inode));
3826
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3828
seg_id = mach_read_from_8(inode + FSEG_ID);
3830
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3832
n_frag = fseg_get_n_frag_pages(inode, mtr);
3833
n_free = flst_get_len(inode + FSEG_FREE, mtr);
3834
n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3835
n_full = flst_get_len(inode + FSEG_FULL, mtr);
3838
"SEGMENT id %llu space %lu; page %lu;"
3839
" res %lu used %lu; full ext %lu\n"
3840
"fragm pages %lu; free extents %lu;"
3841
" not full extents %lu: pages %lu\n",
3843
(ulong) space, (ulong) page_no,
3844
(ulong) reserved, (ulong) used, (ulong) n_full,
3845
(ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3847
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3850
#ifdef UNIV_BTR_PRINT
3851
/*******************************************************************//**
3852
Writes info of a segment. */
3857
fseg_header_t* header, /*!< in: segment header */
3858
mtr_t* mtr) /*!< in: mtr */
3860
fseg_inode_t* inode;
3865
space = page_get_space_id(page_align(header));
3867
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3868
zip_size = dict_table_flags_to_zip_size(flags);
3870
inode = fseg_inode_get(header, space, zip_size, mtr);
3872
fseg_print_low(inode, mtr);
3874
#endif /* UNIV_BTR_PRINT */
3876
/*******************************************************************//**
3877
Validates the file space system and its segments.
3878
@return TRUE if ok */
3883
ulint space) /*!< in: space id */
3885
fsp_header_t* header;
3886
fseg_inode_t* seg_inode;
3887
page_t* seg_inode_page;
3897
fil_addr_t node_addr;
3898
fil_addr_t next_node_addr;
3899
ulint descr_count = 0;
3902
ulint n_full_frag_pages;
3904
ulint seg_inode_len_free;
3905
ulint seg_inode_len_full;
3907
latch = fil_space_get_latch(space, &flags);
3908
zip_size = dict_table_flags_to_zip_size(flags);
3909
ut_a(ut_is_2pow(zip_size));
3910
ut_a(zip_size <= UNIV_PAGE_SIZE);
3911
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
3913
/* Start first a mini-transaction mtr2 to lock out all other threads
3914
from the fsp system */
3916
mtr_x_lock(latch, &mtr2);
3919
mtr_x_lock(latch, &mtr);
3921
header = fsp_get_space_header(space, zip_size, &mtr);
3923
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3924
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3926
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3929
n_full_frag_pages = FSP_EXTENT_SIZE
3930
* flst_get_len(header + FSP_FULL_FRAG, &mtr);
3932
if (UNIV_UNLIKELY(free_limit > size)) {
3935
ut_a(size < FSP_EXTENT_SIZE);
3938
flst_validate(header + FSP_FREE, &mtr);
3939
flst_validate(header + FSP_FREE_FRAG, &mtr);
3940
flst_validate(header + FSP_FULL_FRAG, &mtr);
3944
/* Validate FSP_FREE list */
3946
mtr_x_lock(latch, &mtr);
3948
header = fsp_get_space_header(space, zip_size, &mtr);
3949
node_addr = flst_get_first(header + FSP_FREE, &mtr);
3953
while (!fil_addr_is_null(node_addr)) {
3955
mtr_x_lock(latch, &mtr);
3958
descr = xdes_lst_get_descriptor(space, zip_size,
3961
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3962
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3964
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3968
/* Validate FSP_FREE_FRAG list */
3970
mtr_x_lock(latch, &mtr);
3972
header = fsp_get_space_header(space, zip_size, &mtr);
3973
node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
3977
while (!fil_addr_is_null(node_addr)) {
3979
mtr_x_lock(latch, &mtr);
3982
descr = xdes_lst_get_descriptor(space, zip_size,
3985
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3986
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3987
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
3989
n_used += xdes_get_n_used(descr, &mtr);
3990
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3995
/* Validate FSP_FULL_FRAG list */
3997
mtr_x_lock(latch, &mtr);
3999
header = fsp_get_space_header(space, zip_size, &mtr);
4000
node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
4004
while (!fil_addr_is_null(node_addr)) {
4006
mtr_x_lock(latch, &mtr);
4009
descr = xdes_lst_get_descriptor(space, zip_size,
4012
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
4013
ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
4015
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4019
/* Validate segments */
4021
mtr_x_lock(latch, &mtr);
4023
header = fsp_get_space_header(space, zip_size, &mtr);
4025
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4027
seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
4031
while (!fil_addr_is_null(node_addr)) {
4036
mtr_x_lock(latch, &mtr);
4038
seg_inode_page = fut_get_ptr(
4039
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4040
- FSEG_INODE_PAGE_NODE;
4042
seg_inode = fsp_seg_inode_page_get_nth_inode(
4043
seg_inode_page, n, zip_size, &mtr);
4044
ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4045
fseg_validate_low(seg_inode, &mtr);
4047
descr_count += flst_get_len(seg_inode + FSEG_FREE,
4049
descr_count += flst_get_len(seg_inode + FSEG_FULL,
4051
descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
4054
n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
4056
next_node_addr = flst_get_next_addr(
4057
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4059
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4061
node_addr = next_node_addr;
4065
mtr_x_lock(latch, &mtr);
4067
header = fsp_get_space_header(space, zip_size, &mtr);
4069
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4071
seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
4075
while (!fil_addr_is_null(node_addr)) {
4081
mtr_x_lock(latch, &mtr);
4083
seg_inode_page = fut_get_ptr(
4084
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4085
- FSEG_INODE_PAGE_NODE;
4087
seg_inode = fsp_seg_inode_page_get_nth_inode(
4088
seg_inode_page, n, zip_size, &mtr);
4089
if (mach_read_from_8(seg_inode + FSEG_ID)) {
4090
fseg_validate_low(seg_inode, &mtr);
4092
descr_count += flst_get_len(
4093
seg_inode + FSEG_FREE, &mtr);
4094
descr_count += flst_get_len(
4095
seg_inode + FSEG_FULL, &mtr);
4096
descr_count += flst_get_len(
4097
seg_inode + FSEG_NOT_FULL, &mtr);
4098
n_used2 += fseg_get_n_frag_pages(
4102
next_node_addr = flst_get_next_addr(
4103
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4105
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4107
node_addr = next_node_addr;
4110
ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
4112
ut_a(n_used + n_full_frag_pages
4113
== n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
4115
+ seg_inode_len_full + seg_inode_len_free);
4117
ut_a(n_used + n_full_frag_pages
4118
== n_used2 + 2 * ((free_limit + (zip_size - 1))
4120
+ seg_inode_len_full + seg_inode_len_free);
4122
ut_a(frag_n_used == n_used);
4129
/*******************************************************************//**
4130
Prints info of a file space. */
4135
ulint space) /*!< in: space id */
4137
fsp_header_t* header;
4138
fseg_inode_t* seg_inode;
4139
page_t* seg_inode_page;
4146
fil_addr_t node_addr;
4147
fil_addr_t next_node_addr;
4157
latch = fil_space_get_latch(space, &flags);
4158
zip_size = dict_table_flags_to_zip_size(flags);
4160
/* Start first a mini-transaction mtr2 to lock out all other threads
4161
from the fsp system */
4165
mtr_x_lock(latch, &mtr2);
4169
mtr_x_lock(latch, &mtr);
4171
header = fsp_get_space_header(space, zip_size, &mtr);
4173
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4175
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4177
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4179
n_free = flst_get_len(header + FSP_FREE, &mtr);
4180
n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4181
n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4183
seg_id = mach_read_from_8(header + FSP_SEG_ID);
4186
"FILE SPACE INFO: id %lu\n"
4187
"size %lu, free limit %lu, free extents %lu\n"
4188
"not full frag extents %lu: used pages %lu,"
4189
" full frag extents %lu\n"
4190
"first seg id not used %llu\n",
4192
(ulong) size, (ulong) free_limit, (ulong) n_free,
4193
(ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4198
/* Print segments */
4201
mtr_x_lock(latch, &mtr);
4203
header = fsp_get_space_header(space, zip_size, &mtr);
4205
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4209
while (!fil_addr_is_null(node_addr)) {
4216
mtr_x_lock(latch, &mtr);
4218
seg_inode_page = fut_get_ptr(
4219
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4220
- FSEG_INODE_PAGE_NODE;
4222
seg_inode = fsp_seg_inode_page_get_nth_inode(
4223
seg_inode_page, n, zip_size, &mtr);
4224
ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4225
fseg_print_low(seg_inode, &mtr);
4229
next_node_addr = flst_get_next_addr(
4230
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4232
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4234
node_addr = next_node_addr;
4238
mtr_x_lock(latch, &mtr);
4240
header = fsp_get_space_header(space, zip_size, &mtr);
4242
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4246
while (!fil_addr_is_null(node_addr)) {
4253
mtr_x_lock(latch, &mtr);
4255
seg_inode_page = fut_get_ptr(
4256
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4257
- FSEG_INODE_PAGE_NODE;
4259
seg_inode = fsp_seg_inode_page_get_nth_inode(
4260
seg_inode_page, n, zip_size, &mtr);
4261
if (mach_read_from_8(seg_inode + FSEG_ID)) {
4263
fseg_print_low(seg_inode, &mtr);
4267
next_node_addr = flst_get_next_addr(
4268
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4270
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4272
node_addr = next_node_addr;
4277
fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
4279
#endif /* !UNIV_HOTBACKUP */