1
/*****************************************************************************
3
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/******************************************************************//**
23
Created 11/29/1995 Heikki Tuuri
24
***********************************************************************/
36
#include "page0page.h"
40
#else /* UNIV_HOTBACKUP */
41
# include "sync0sync.h"
44
# include "ibuf0ibuf.h"
47
# include "dict0boot.h"
49
#endif /* UNIV_HOTBACKUP */
53
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
56
/* The data structures in files are defined just as byte strings in C */
57
typedef byte fsp_header_t;
63
File space header data structure: this data structure is contained in the
64
first page of a space. The space for this header is reserved in every extent
65
descriptor page, but used only in the first. */
67
/*-------------------------------------*/
68
#define FSP_SPACE_ID 0 /* space id */
69
#define FSP_NOT_USED 4 /* this field contained a value up to
70
which we know that the modifications
71
in the database have been flushed to
72
the file space; not used now */
73
#define FSP_SIZE 8 /* Current size of the space in
75
#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
76
free list has not been initialized:
77
the pages >= this limit are, by
78
definition, free; note that in a
79
single-table tablespace where size
80
< 64 pages, this number is 64, i.e.,
81
we have initialized the space
82
about the first extent, but have not
83
physically allocted those pages to the
85
#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */
86
#define FSP_FRAG_N_USED 20 /* number of used pages in the
88
#define FSP_FREE 24 /* list of free extents */
89
#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
90
/* list of partially free extents not
91
belonging to any segment */
92
#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
93
/* list of full extents not belonging
95
#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
96
/* 8 bytes which give the first unused
98
#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
99
/* list of pages containing segment
100
headers, where all the segment inode
101
slots are reserved */
102
#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
103
/* list of pages containing segment
104
headers, where not all the segment
105
header slots are reserved */
106
/*-------------------------------------*/
107
/* File space header size */
108
#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
110
#define FSP_FREE_ADD 4 /* this many free extents are added
111
to the free list from above
112
FSP_FREE_LIMIT at a time */
114
/* FILE SEGMENT INODE
117
Segment inode which is created for each segment in a tablespace. NOTE: in
118
purge we assume that a segment having only one currently used page can be
119
freed in a few steps, so that the freeing cannot fill the file buffer with
120
bufferfixed file pages. */
122
typedef byte fseg_inode_t;
124
#define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
125
/* the list node for linking
126
segment inode pages */
128
#define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
129
/*-------------------------------------*/
130
#define FSEG_ID 0 /* 8 bytes of segment id: if this is
131
ut_dulint_zero, it means that the
133
#define FSEG_NOT_FULL_N_USED 8
134
/* number of used segment pages in
135
the FSEG_NOT_FULL list */
137
/* list of free extents of this
139
#define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
140
/* list of partially free extents */
141
#define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
142
/* list of full extents */
143
#define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
144
/* magic number used in debugging */
145
#define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
146
/* array of individual pages
147
belonging to this segment in fsp
148
fragment extent lists */
149
#define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
150
/* number of slots in the array for
151
the fragment pages */
152
#define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
153
page number within space, FIL_NULL
154
means that the slot is not in use */
155
/*-------------------------------------*/
156
#define FSEG_INODE_SIZE \
157
(16 + 3 * FLST_BASE_NODE_SIZE \
158
+ FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
160
#define FSP_SEG_INODES_PER_PAGE(zip_size) \
161
(((zip_size ? zip_size : UNIV_PAGE_SIZE) \
162
- FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
163
/* Number of segment inodes which fit on a
166
#define FSEG_MAGIC_N_VALUE 97937874
168
#define FSEG_FILLFACTOR 8 /* If this value is x, then if
169
the number of unused but reserved
170
pages in a segment is less than
171
reserved pages * 1/x, and there are
172
at least FSEG_FRAG_LIMIT used pages,
173
then we allow a new empty extent to
174
be added to the segment in
175
fseg_alloc_free_page. Otherwise, we
176
use unused pages of the segment. */
178
#define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
179
/* If the segment has >= this many
180
used pages, it may be expanded by
181
allocating extents to the segment;
182
until that only individual fragment
183
pages are allocated from the space */
185
#define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
186
is at least this many extents, we
187
allow extents to be put to the free
188
list of the extent: at most
189
FSEG_FREE_LIST_MAX_LEN many */
190
#define FSEG_FREE_LIST_MAX_LEN 4
196
File extent descriptor data structure: contains bits to tell which pages in
197
the extent are free and which contain old tuple version to clean. */
199
/*-------------------------------------*/
200
#define XDES_ID 0 /* The identifier of the segment
201
to which this extent belongs */
202
#define XDES_FLST_NODE 8 /* The list node data structure
203
for the descriptors */
204
#define XDES_STATE (FLST_NODE_SIZE + 8)
205
/* contains state information
207
#define XDES_BITMAP (FLST_NODE_SIZE + 12)
208
/* Descriptor bitmap of the pages
210
/*-------------------------------------*/
212
#define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
213
#define XDES_FREE_BIT 0 /* Index of the bit which tells if
215
#define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
216
Index of the bit which tells if
217
there are old versions of tuples
219
/* States of a descriptor */
220
#define XDES_FREE 1 /* extent is in free list of space */
221
#define XDES_FREE_FRAG 2 /* extent is in free fragment list of
223
#define XDES_FULL_FRAG 3 /* extent is in full fragment list of
225
#define XDES_FSEG 4 /* extent belongs to a segment */
227
/* File extent data structure size in bytes. */
229
(XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
231
/* Offset of the descriptor array on a descriptor page */
232
#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
234
#ifndef UNIV_HOTBACKUP
235
/* Flag to indicate if we have printed the tablespace full error. */
236
static ibool fsp_tbs_full_error_printed = FALSE;
238
/**********************************************************************//**
239
Returns an extent to the free list of a space. */
244
ulint space, /*!< in: space id */
245
ulint zip_size,/*!< in: compressed page size in bytes
246
or 0 for uncompressed pages */
247
ulint page, /*!< in: page offset in the extent */
248
mtr_t* mtr); /*!< in: mtr */
249
/**********************************************************************//**
250
Frees an extent of a segment to the space free list. */
255
fseg_inode_t* seg_inode, /*!< in: segment inode */
256
ulint space, /*!< in: space id */
257
ulint zip_size,/*!< in: compressed page size in bytes
258
or 0 for uncompressed pages */
259
ulint page, /*!< in: page offset in the extent */
260
mtr_t* mtr); /*!< in: mtr handle */
261
/**********************************************************************//**
262
Calculates the number of pages reserved by a segment, and how
263
many pages are currently used.
264
@return number of reserved pages */
267
fseg_n_reserved_pages_low(
268
/*======================*/
269
fseg_inode_t* header, /*!< in: segment inode */
270
ulint* used, /*!< out: number of pages used (not
271
more than reserved) */
272
mtr_t* mtr); /*!< in: mtr handle */
273
/********************************************************************//**
274
Marks a page used. The page must reside within the extents of the given
280
fseg_inode_t* seg_inode,/*!< in: segment inode */
281
ulint space, /*!< in: space id */
282
ulint zip_size,/*!< in: compressed page size in bytes
283
or 0 for uncompressed pages */
284
ulint page, /*!< in: page offset */
285
mtr_t* mtr); /*!< in: mtr */
286
/**********************************************************************//**
287
Returns the first extent descriptor for a segment. We think of the extent
288
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
290
@return the first extent descriptor, or NULL if none */
293
fseg_get_first_extent(
294
/*==================*/
295
fseg_inode_t* inode, /*!< in: segment inode */
296
ulint space, /*!< in: space id */
297
ulint zip_size,/*!< in: compressed page size in bytes
298
or 0 for uncompressed pages */
299
mtr_t* mtr); /*!< in: mtr */
300
/**********************************************************************//**
301
Puts new extents to the free list if
302
there are free extents above the free limit. If an extent happens
303
to contain an extent descriptor page, the extent is put to
304
the FSP_FREE_FRAG list with the page marked as used. */
309
ibool init_space, /*!< in: TRUE if this is a single-table
310
tablespace and we are only initing
311
the tablespace's first extent
312
descriptor page and ibuf bitmap page;
313
then we do not allocate more extents */
314
ulint space, /*!< in: space */
315
fsp_header_t* header, /*!< in: space header */
316
mtr_t* mtr); /*!< in: mtr */
317
/**********************************************************************//**
318
Allocates a single free page from a segment. This function implements
319
the intelligent allocation strategy which tries to minimize file space
321
@return the allocated page number, FIL_NULL if no page could be allocated */
324
fseg_alloc_free_page_low(
325
/*=====================*/
326
ulint space, /*!< in: space */
327
ulint zip_size,/*!< in: compressed page size in bytes
328
or 0 for uncompressed pages */
329
fseg_inode_t* seg_inode, /*!< in: segment inode */
330
ulint hint, /*!< in: hint of which page would be desirable */
331
byte direction, /*!< in: if the new page is needed because
332
of an index page split, and records are
333
inserted there in order, into which
334
direction they go alphabetically: FSP_DOWN,
335
FSP_UP, FSP_NO_DIR */
336
mtr_t* mtr); /*!< in: mtr handle */
337
#endif /* !UNIV_HOTBACKUP */
339
/**********************************************************************//**
340
Reads the file space size stored in the header page.
341
@return tablespace size stored in the space header */
346
page_t* page) /*!< in: header page (page 0 in the tablespace) */
348
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
351
#ifndef UNIV_HOTBACKUP
352
/**********************************************************************//**
353
Gets a pointer to the space header and x-locks its page.
354
@return pointer to the space header, page x-locked */
357
fsp_get_space_header(
358
/*=================*/
359
ulint id, /*!< in: space id */
360
ulint zip_size,/*!< in: compressed page size in bytes
361
or 0 for uncompressed pages */
362
mtr_t* mtr) /*!< in: mtr */
365
fsp_header_t* header;
367
ut_ad(ut_is_2pow(zip_size));
368
ut_ad(zip_size <= UNIV_PAGE_SIZE);
369
ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
370
ut_ad(id || !zip_size);
372
block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
373
header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
374
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
376
ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
377
ut_ad(zip_size == dict_table_flags_to_zip_size(
378
mach_read_from_4(FSP_SPACE_FLAGS + header)));
382
/**********************************************************************//**
383
Gets a descriptor bit of a page.
384
@return TRUE if free */
389
xdes_t* descr, /*!< in: descriptor */
390
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
391
ulint offset, /*!< in: page offset within extent:
392
0 ... FSP_EXTENT_SIZE - 1 */
393
mtr_t* mtr) /*!< in: mtr */
399
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
400
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
401
ut_ad(offset < FSP_EXTENT_SIZE);
403
index = bit + XDES_BITS_PER_PAGE * offset;
405
byte_index = index / 8;
406
bit_index = index % 8;
408
return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
413
/**********************************************************************//**
414
Sets a descriptor bit of a page. */
419
xdes_t* descr, /*!< in: descriptor */
420
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
421
ulint offset, /*!< in: page offset within extent:
422
0 ... FSP_EXTENT_SIZE - 1 */
423
ibool val, /*!< in: bit value */
424
mtr_t* mtr) /*!< in: mtr */
431
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
432
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
433
ut_ad(offset < FSP_EXTENT_SIZE);
435
index = bit + XDES_BITS_PER_PAGE * offset;
437
byte_index = index / 8;
438
bit_index = index % 8;
440
descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
442
descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
444
mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
448
/**********************************************************************//**
449
Looks for a descriptor bit having the desired value. Starts from hint
450
and scans upward; at the end of the extent the search is wrapped to
451
the start of the extent.
452
@return bit index of the bit, ULINT_UNDEFINED if not found */
457
xdes_t* descr, /*!< in: descriptor */
458
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
459
ibool val, /*!< in: desired bit value */
460
ulint hint, /*!< in: hint of which bit position would be desirable */
461
mtr_t* mtr) /*!< in: mtr */
467
ut_ad(hint < FSP_EXTENT_SIZE);
468
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
469
for (i = hint; i < FSP_EXTENT_SIZE; i++) {
470
if (val == xdes_get_bit(descr, bit, i, mtr)) {
476
for (i = 0; i < hint; i++) {
477
if (val == xdes_get_bit(descr, bit, i, mtr)) {
483
return(ULINT_UNDEFINED);
486
/**********************************************************************//**
487
Looks for a descriptor bit having the desired value. Scans the extent in
488
a direction opposite to xdes_find_bit.
489
@return bit index of the bit, ULINT_UNDEFINED if not found */
492
xdes_find_bit_downward(
493
/*===================*/
494
xdes_t* descr, /*!< in: descriptor */
495
ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
496
ibool val, /*!< in: desired bit value */
497
ulint hint, /*!< in: hint of which bit position would be desirable */
498
mtr_t* mtr) /*!< in: mtr */
504
ut_ad(hint < FSP_EXTENT_SIZE);
505
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
506
for (i = hint + 1; i > 0; i--) {
507
if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
513
for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
514
if (val == xdes_get_bit(descr, bit, i, mtr)) {
520
return(ULINT_UNDEFINED);
523
/**********************************************************************//**
524
Returns the number of used pages in a descriptor.
525
@return number of pages used */
530
xdes_t* descr, /*!< in: descriptor */
531
mtr_t* mtr) /*!< in: mtr */
537
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
538
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
539
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
547
/**********************************************************************//**
548
Returns true if extent contains no used pages.
549
@return TRUE if totally free */
554
xdes_t* descr, /*!< in: descriptor */
555
mtr_t* mtr) /*!< in: mtr */
557
if (0 == xdes_get_n_used(descr, mtr)) {
565
/**********************************************************************//**
566
Returns true if extent contains no free pages.
567
@return TRUE if full */
572
xdes_t* descr, /*!< in: descriptor */
573
mtr_t* mtr) /*!< in: mtr */
575
if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
583
/**********************************************************************//**
584
Sets the state of an xdes. */
589
xdes_t* descr, /*!< in: descriptor */
590
ulint state, /*!< in: state to set */
591
mtr_t* mtr) /*!< in: mtr handle */
594
ut_ad(state >= XDES_FREE);
595
ut_ad(state <= XDES_FSEG);
596
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
598
mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
601
/**********************************************************************//**
602
Gets the state of an xdes.
608
xdes_t* descr, /*!< in: descriptor */
609
mtr_t* mtr) /*!< in: mtr handle */
614
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
616
state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
617
ut_ad(state - 1 < XDES_FSEG);
621
/**********************************************************************//**
622
Inits an extent descriptor to the free and clean state. */
627
xdes_t* descr, /*!< in: descriptor */
628
mtr_t* mtr) /*!< in: mtr */
633
ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
634
ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
636
for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
637
mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
640
xdes_set_state(descr, XDES_FREE, mtr);
643
/********************************************************************//**
644
Calculates the page where the descriptor of a page resides.
645
@return descriptor page offset */
648
xdes_calc_descriptor_page(
649
/*======================*/
650
ulint zip_size, /*!< in: compressed page size in bytes;
651
0 for uncompressed pages */
652
ulint offset) /*!< in: page offset */
654
#ifndef DOXYGEN /* Doxygen gets confused of these */
655
# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
656
+ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
659
# if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
660
+ (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
663
#endif /* !DOXYGEN */
664
ut_ad(ut_is_2pow(zip_size));
667
return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
669
ut_ad(zip_size > XDES_ARR_OFFSET
670
+ (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
671
return(ut_2pow_round(offset, zip_size));
675
/********************************************************************//**
676
Calculates the descriptor index within a descriptor page.
677
@return descriptor index */
680
xdes_calc_descriptor_index(
681
/*=======================*/
682
ulint zip_size, /*!< in: compressed page size in bytes;
683
0 for uncompressed pages */
684
ulint offset) /*!< in: page offset */
686
ut_ad(ut_is_2pow(zip_size));
689
return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
692
return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
696
/********************************************************************//**
697
Gets pointer to a the extent descriptor of a page. The page where the extent
698
descriptor resides is x-locked. If the page offset is equal to the free limit
699
of the space, adds new extents from above the free limit to the space free
700
list, if not free limit == space size. This adding is necessary to make the
701
descriptor defined, as they are uninitialized above the free limit.
702
@return pointer to the extent descriptor, NULL if the page does not
703
exist in the space or if the offset exceeds the free limit */
706
xdes_get_descriptor_with_space_hdr(
707
/*===============================*/
708
fsp_header_t* sp_header,/*!< in: space header, x-latched */
709
ulint space, /*!< in: space id */
710
ulint offset, /*!< in: page offset;
711
if equal to the free limit,
712
we try to add new extents to
713
the space free list */
714
mtr_t* mtr) /*!< in: mtr handle */
723
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
725
ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
726
|| mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
727
ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
728
/* Read free limit and space size */
729
limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
730
size = mach_read_from_4(sp_header + FSP_SIZE);
731
zip_size = dict_table_flags_to_zip_size(
732
mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
734
/* If offset is >= size or > limit, return NULL */
736
if ((offset >= size) || (offset > limit)) {
741
/* If offset is == limit, fill free list of the space. */
743
if (offset == limit) {
744
fsp_fill_free_list(FALSE, space, sp_header, mtr);
747
descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
749
if (descr_page_no == 0) {
750
/* It is on the space header page */
752
descr_page = page_align(sp_header);
756
block = buf_page_get(space, zip_size, descr_page_no,
758
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
760
descr_page = buf_block_get_frame(block);
763
return(descr_page + XDES_ARR_OFFSET
764
+ XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
767
/********************************************************************//**
768
Gets pointer to a the extent descriptor of a page. The page where the
769
extent descriptor resides is x-locked. If the page offset is equal to
770
the free limit of the space, adds new extents from above the free limit
771
to the space free list, if not free limit == space size. This adding
772
is necessary to make the descriptor defined, as they are uninitialized
773
above the free limit.
774
@return pointer to the extent descriptor, NULL if the page does not
775
exist in the space or if the offset exceeds the free limit */
780
ulint space, /*!< in: space id */
781
ulint zip_size,/*!< in: compressed page size in bytes
782
or 0 for uncompressed pages */
783
ulint offset, /*!< in: page offset; if equal to the free limit,
784
we try to add new extents to the space free list */
785
mtr_t* mtr) /*!< in: mtr handle */
788
fsp_header_t* sp_header;
790
block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
791
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
793
sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
794
return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
798
/********************************************************************//**
799
Gets pointer to a the extent descriptor if the file address
800
of the descriptor list node is known. The page where the
801
extent descriptor resides is x-locked.
802
@return pointer to the extent descriptor */
805
xdes_lst_get_descriptor(
806
/*====================*/
807
ulint space, /*!< in: space id */
808
ulint zip_size,/*!< in: compressed page size in bytes
809
or 0 for uncompressed pages */
810
fil_addr_t lst_node,/*!< in: file address of the list node
811
contained in the descriptor */
812
mtr_t* mtr) /*!< in: mtr handle */
817
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
819
descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
825
/********************************************************************//**
826
Returns page offset of the first page in extent described by a descriptor.
827
@return offset of the first page in extent */
832
xdes_t* descr) /*!< in: extent descriptor */
836
return(page_get_page_no(page_align(descr))
837
+ ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
840
#endif /* !UNIV_HOTBACKUP */
842
/***********************************************************//**
843
Inits a file page whose prior contents should be ignored. */
846
fsp_init_file_page_low(
847
/*===================*/
848
buf_block_t* block) /*!< in: pointer to a page */
850
page_t* page = buf_block_get_frame(block);
851
page_zip_des_t* page_zip= buf_block_get_page_zip(block);
853
#ifndef UNIV_HOTBACKUP
854
block->check_index_page_at_flush = FALSE;
855
#endif /* !UNIV_HOTBACKUP */
857
if (UNIV_LIKELY_NULL(page_zip)) {
858
memset(page, 0, UNIV_PAGE_SIZE);
859
memset(page_zip->data, 0, page_zip_get_size(page_zip));
860
mach_write_to_4(page + FIL_PAGE_OFFSET,
861
buf_block_get_page_no(block));
863
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
864
buf_block_get_space(block));
865
memcpy(page_zip->data + FIL_PAGE_OFFSET,
866
page + FIL_PAGE_OFFSET, 4);
867
memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
868
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
872
#ifdef UNIV_BASIC_LOG_DEBUG
873
memset(page, 0xff, UNIV_PAGE_SIZE);
875
mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
876
memset(page + FIL_PAGE_LSN, 0, 8);
877
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
878
buf_block_get_space(block));
879
memset(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, 0, 8);
882
#ifndef UNIV_HOTBACKUP
883
/***********************************************************//**
884
Inits a file page whose prior contents should be ignored. */
889
buf_block_t* block, /*!< in: pointer to a page */
890
mtr_t* mtr) /*!< in: mtr */
892
fsp_init_file_page_low(block);
894
mlog_write_initial_log_record(buf_block_get_frame(block),
895
MLOG_INIT_FILE_PAGE, mtr);
897
#endif /* !UNIV_HOTBACKUP */
899
/***********************************************************//**
900
Parses a redo log record of a file page init.
901
@return end of log record or NULL */
904
fsp_parse_init_file_page(
905
/*=====================*/
906
byte* ptr, /*!< in: buffer */
907
byte* end_ptr __attribute__((unused)), /*!< in: buffer end */
908
buf_block_t* block) /*!< in: block or NULL */
910
ut_ad(ptr && end_ptr);
913
fsp_init_file_page_low(block);
919
/**********************************************************************//**
920
Initializes the fsp system. */
926
/* Does nothing at the moment */
929
/**********************************************************************//**
930
Writes the space id and compressed page size to a tablespace header.
931
This function is used past the buffer pool when we in fil0fil.c create
932
a new single-table tablespace. */
935
fsp_header_init_fields(
936
/*===================*/
937
page_t* page, /*!< in/out: first page in the space */
938
ulint space_id, /*!< in: space id */
939
ulint flags) /*!< in: tablespace flags (FSP_SPACE_FLAGS):
940
0, or table->flags if newer than COMPACT */
942
/* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
943
ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
944
ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
945
format, the tablespace flags should equal table->flags. */
946
ut_a(flags != DICT_TF_COMPACT);
948
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
950
mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
954
#ifndef UNIV_HOTBACKUP
955
/**********************************************************************//**
956
Initializes the space header of a new created space and creates also the
957
insert buffer tree root if space == 0. */
962
ulint space, /*!< in: space id */
963
ulint size, /*!< in: current size in blocks */
964
mtr_t* mtr) /*!< in: mini-transaction handle */
966
fsp_header_t* header;
974
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
976
zip_size = dict_table_flags_to_zip_size(flags);
977
block = buf_page_create(space, 0, zip_size, mtr);
978
buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
979
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
981
/* The prior contents of the file page should be ignored */
983
fsp_init_file_page(block, mtr);
984
page = buf_block_get_frame(block);
986
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
989
header = FSP_HEADER_OFFSET + page;
991
mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
992
mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
994
mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
995
mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
996
mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
998
mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
1000
flst_init(header + FSP_FREE, mtr);
1001
flst_init(header + FSP_FREE_FRAG, mtr);
1002
flst_init(header + FSP_FULL_FRAG, mtr);
1003
flst_init(header + FSP_SEG_INODES_FULL, mtr);
1004
flst_init(header + FSP_SEG_INODES_FREE, mtr);
1006
mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), mtr);
1008
fsp_fill_free_list(FALSE, space, header, mtr);
1009
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
1010
0, 0, ut_dulint_add(DICT_IBUF_ID_MIN, space),
1011
dict_ind_redundant, mtr);
1013
fsp_fill_free_list(TRUE, space, header, mtr);
1016
#endif /* !UNIV_HOTBACKUP */
1018
/**********************************************************************//**
1019
Reads the space id from the first page of a tablespace.
1020
@return space id, ULINT UNDEFINED if error */
1023
fsp_header_get_space_id(
1024
/*====================*/
1025
const page_t* page) /*!< in: first page of a tablespace */
1030
fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
1032
id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
1036
"InnoDB: Error: space id in fsp header %lu,"
1037
" but in the page header %lu\n",
1038
(ulong) fsp_id, (ulong) id);
1040
return(ULINT_UNDEFINED);
1046
/**********************************************************************//**
1047
Reads the space flags from the first page of a tablespace.
1051
fsp_header_get_flags(
1052
/*=================*/
1053
const page_t* page) /*!< in: first page of a tablespace */
1055
ut_ad(!page_offset(page));
1057
return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
1060
/**********************************************************************//**
1061
Reads the compressed page size from the first page of a tablespace.
1062
@return compressed page size in bytes, or 0 if uncompressed */
1065
fsp_header_get_zip_size(
1066
/*====================*/
1067
const page_t* page) /*!< in: first page of a tablespace */
1069
ulint flags = fsp_header_get_flags(page);
1071
return(dict_table_flags_to_zip_size(flags));
1074
#ifndef UNIV_HOTBACKUP
1075
/**********************************************************************//**
1076
Increases the space size field of a space. */
1079
fsp_header_inc_size(
1080
/*================*/
1081
ulint space, /*!< in: space id */
1082
ulint size_inc,/*!< in: size increment in pages */
1083
mtr_t* mtr) /*!< in: mini-transaction handle */
1085
fsp_header_t* header;
1091
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
1093
header = fsp_get_space_header(space,
1094
dict_table_flags_to_zip_size(flags),
1097
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1099
mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
1103
/**********************************************************************//**
1104
Gets the current free limit of the system tablespace. The free limit
1105
means the place of the first page which has never been put to the
1106
free list for allocation. The space above that address is initialized
1107
to zero. Sets also the global variable log_fsp_current_free_limit.
1108
@return free limit in megabytes */
1111
fsp_header_get_free_limit(void)
1112
/*===========================*/
1114
fsp_header_t* header;
1120
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1122
header = fsp_get_space_header(0, 0, &mtr);
1124
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1126
limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
1128
log_fsp_current_free_limit_set_and_checkpoint(limit);
1135
/**********************************************************************//**
1136
Gets the size of the system tablespace from the tablespace header. If
1137
we do not have an auto-extending data file, this should be equal to
1138
the size of the data files. If there is an auto-extending data file,
1139
this can be smaller.
1140
@return size in pages */
1143
fsp_header_get_tablespace_size(void)
1144
/*================================*/
1146
fsp_header_t* header;
1152
mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1154
header = fsp_get_space_header(0, 0, &mtr);
1156
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1163
/***********************************************************************//**
1164
Tries to extend a single-table tablespace so that a page would fit in the
1166
@return TRUE if success */
1169
fsp_try_extend_data_file_with_pages(
1170
/*================================*/
1171
ulint space, /*!< in: space */
1172
ulint page_no, /*!< in: page number */
1173
fsp_header_t* header, /*!< in: space header */
1174
mtr_t* mtr) /*!< in: mtr */
1182
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1184
ut_a(page_no >= size);
1186
success = fil_extend_space_to_desired_size(&actual_size, space,
1188
/* actual_size now has the space size in pages; it may be less than
1189
we wanted if we ran out of disk space */
1191
mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1196
/***********************************************************************//**
1197
Tries to extend the last data file of a tablespace if it is auto-extending.
1198
@return FALSE if not auto-extending */
1201
fsp_try_extend_data_file(
1202
/*=====================*/
1203
ulint* actual_increase,/*!< out: actual increase in pages, where
1204
we measure the tablespace size from
1205
what the header field says; it may be
1206
the actual file size rounded down to
1208
ulint space, /*!< in: space */
1209
fsp_header_t* header, /*!< in: space header */
1210
mtr_t* mtr) /*!< in: mtr */
1216
ulint size_increase;
1220
*actual_increase = 0;
1222
if (space == 0 && !srv_auto_extend_last_data_file) {
1224
/* We print the error message only once to avoid
1225
spamming the error log. Note that we don't need
1226
to reset the flag to FALSE as dealing with this
1227
error requires server restart. */
1228
if (fsp_tbs_full_error_printed == FALSE) {
1230
"InnoDB: Error: Data file(s) ran"
1232
"Please add another data file or"
1233
" use \'autoextend\' for the last"
1235
fsp_tbs_full_error_printed = TRUE;
1240
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1241
zip_size = dict_table_flags_to_zip_size(
1242
mach_read_from_4(header + FSP_SPACE_FLAGS));
1247
if (!srv_last_file_size_max) {
1248
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1250
if (srv_last_file_size_max
1251
< srv_data_file_sizes[srv_n_data_files - 1]) {
1254
"InnoDB: Error: Last data file size"
1255
" is %lu, max size allowed %lu\n",
1256
(ulong) srv_data_file_sizes[
1257
srv_n_data_files - 1],
1258
(ulong) srv_last_file_size_max);
1261
size_increase = srv_last_file_size_max
1262
- srv_data_file_sizes[srv_n_data_files - 1];
1263
if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1264
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1268
/* We extend single-table tablespaces first one extent
1269
at a time, but for bigger tablespaces more. It is not
1270
enough to extend always by one extent, because some
1271
extents are frag page extents. */
1272
ulint extent_size; /*!< one megabyte, in pages */
1275
extent_size = FSP_EXTENT_SIZE;
1277
extent_size = FSP_EXTENT_SIZE
1278
* UNIV_PAGE_SIZE / zip_size;
1281
if (size < extent_size) {
1282
/* Let us first extend the file to extent_size */
1283
success = fsp_try_extend_data_file_with_pages(
1284
space, extent_size - 1, header, mtr);
1286
new_size = mtr_read_ulint(header + FSP_SIZE,
1289
*actual_increase = new_size - old_size;
1297
if (size < 32 * extent_size) {
1298
size_increase = extent_size;
1300
/* Below in fsp_fill_free_list() we assume
1301
that we add at most FSP_FREE_ADD extents at
1303
size_increase = FSP_FREE_ADD * extent_size;
1307
if (size_increase == 0) {
1312
success = fil_extend_space_to_desired_size(&actual_size, space,
1313
size + size_increase);
1314
/* We ignore any fragments of a full megabyte when storing the size
1315
to the space header */
1318
new_size = ut_calc_align_down(actual_size,
1319
(1024 * 1024) / UNIV_PAGE_SIZE);
1321
new_size = ut_calc_align_down(actual_size,
1322
(1024 * 1024) / zip_size);
1324
mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1326
*actual_increase = new_size - old_size;
1331
/**********************************************************************//**
1332
Puts new extents to the free list if there are free extents above the free
1333
limit. If an extent happens to contain an extent descriptor page, the extent
1334
is put to the FSP_FREE_FRAG list with the page marked as used. */
1339
ibool init_space, /*!< in: TRUE if this is a single-table
1340
tablespace and we are only initing
1341
the tablespace's first extent
1342
descriptor page and ibuf bitmap page;
1343
then we do not allocate more extents */
1344
ulint space, /*!< in: space */
1345
fsp_header_t* header, /*!< in: space header */
1346
mtr_t* mtr) /*!< in: mtr */
1354
ulint actual_increase;
1358
ut_ad(header && mtr);
1359
ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
1361
/* Check if we can fill free list from above the free list limit */
1362
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1363
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1365
zip_size = dict_table_flags_to_zip_size(
1366
mach_read_from_4(FSP_SPACE_FLAGS + header));
1367
ut_a(ut_is_2pow(zip_size));
1368
ut_a(zip_size <= UNIV_PAGE_SIZE);
1369
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
1371
if (space == 0 && srv_auto_extend_last_data_file
1372
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1374
/* Try to increase the last data file size */
1375
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1376
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1379
if (space != 0 && !init_space
1380
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1382
/* Try to increase the .ibd file size */
1383
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1384
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1389
while ((init_space && i < 1)
1390
|| ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1394
init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1396
init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1399
mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1402
/* Update the free limit info in the log system and make
1406
log_fsp_current_free_limit_set_and_checkpoint(
1407
(i + FSP_EXTENT_SIZE)
1408
/ ((1024 * 1024) / UNIV_PAGE_SIZE));
1411
if (UNIV_UNLIKELY(init_xdes)) {
1415
/* We are going to initialize a new descriptor page
1416
and a new ibuf bitmap page: the prior contents of the
1417
pages should be ignored. */
1420
block = buf_page_create(
1421
space, i, zip_size, mtr);
1422
buf_page_get(space, zip_size, i,
1424
buf_block_dbg_add_level(block,
1427
fsp_init_file_page(block, mtr);
1428
mlog_write_ulint(buf_block_get_frame(block)
1434
/* Initialize the ibuf bitmap page in a separate
1435
mini-transaction because it is low in the latching
1436
order, and we must be able to release its latch
1437
before returning from the fsp routine */
1439
mtr_start(&ibuf_mtr);
1441
block = buf_page_create(space,
1442
i + FSP_IBUF_BITMAP_OFFSET,
1443
zip_size, &ibuf_mtr);
1444
buf_page_get(space, zip_size,
1445
i + FSP_IBUF_BITMAP_OFFSET,
1446
RW_X_LATCH, &ibuf_mtr);
1447
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1449
fsp_init_file_page(block, &ibuf_mtr);
1451
ibuf_bitmap_page_init(block, &ibuf_mtr);
1453
mtr_commit(&ibuf_mtr);
1456
descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1458
xdes_init(descr, mtr);
1460
#if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
1461
# error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
1463
#if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
1464
# error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
1467
if (UNIV_UNLIKELY(init_xdes)) {
1469
/* The first page in the extent is a descriptor page
1470
and the second is an ibuf bitmap page: mark them
1473
xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1474
xdes_set_bit(descr, XDES_FREE_BIT,
1475
FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1476
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1478
flst_add_last(header + FSP_FREE_FRAG,
1479
descr + XDES_FLST_NODE, mtr);
1480
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1482
mlog_write_ulint(header + FSP_FRAG_N_USED,
1483
frag_n_used + 2, MLOG_4BYTES, mtr);
1485
flst_add_last(header + FSP_FREE,
1486
descr + XDES_FLST_NODE, mtr);
1490
i += FSP_EXTENT_SIZE;
1494
/**********************************************************************//**
1495
Allocates a new free extent.
1496
@return extent descriptor, NULL if cannot be allocated */
1499
fsp_alloc_free_extent(
1500
/*==================*/
1501
ulint space, /*!< in: space id */
1502
ulint zip_size,/*!< in: compressed page size in bytes
1503
or 0 for uncompressed pages */
1504
ulint hint, /*!< in: hint of which extent would be desirable: any
1505
page offset in the extent goes; the hint must not
1506
be > FSP_FREE_LIMIT */
1507
mtr_t* mtr) /*!< in: mtr */
1509
fsp_header_t* header;
1515
header = fsp_get_space_header(space, zip_size, mtr);
1517
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1519
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1520
/* Ok, we can take this extent */
1522
/* Take the first extent in the free list */
1523
first = flst_get_first(header + FSP_FREE, mtr);
1525
if (fil_addr_is_null(first)) {
1526
fsp_fill_free_list(FALSE, space, header, mtr);
1528
first = flst_get_first(header + FSP_FREE, mtr);
1531
if (fil_addr_is_null(first)) {
1533
return(NULL); /* No free extents left */
1536
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1539
flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1544
/**********************************************************************//**
1545
Allocates a single free page from a space. The page is marked as used.
1546
@return the page offset, FIL_NULL if no page could be allocated */
1549
fsp_alloc_free_page(
1550
/*================*/
1551
ulint space, /*!< in: space id */
1552
ulint zip_size,/*!< in: compressed page size in bytes
1553
or 0 for uncompressed pages */
1554
ulint hint, /*!< in: hint of which page would be desirable */
1555
mtr_t* mtr) /*!< in: mtr handle */
1557
fsp_header_t* header;
1569
header = fsp_get_space_header(space, zip_size, mtr);
1571
/* Get the hinted descriptor */
1572
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1574
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1575
/* Ok, we can take this extent */
1577
/* Else take the first extent in free_frag list */
1578
first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1580
if (fil_addr_is_null(first)) {
1581
/* There are no partially full fragments: allocate
1582
a free extent and add it to the FREE_FRAG list. NOTE
1583
that the allocation may have as a side-effect that an
1584
extent containing a descriptor page is added to the
1585
FREE_FRAG list. But we will allocate our page from the
1586
the free extent anyway. */
1588
descr = fsp_alloc_free_extent(space, zip_size,
1591
if (descr == NULL) {
1592
/* No free space left */
1597
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1598
flst_add_last(header + FSP_FREE_FRAG,
1599
descr + XDES_FLST_NODE, mtr);
1601
descr = xdes_lst_get_descriptor(space, zip_size,
1605
/* Reset the hint */
1609
/* Now we have in descr an extent with at least one free page. Look
1610
for a free page in the extent. */
1612
free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1613
hint % FSP_EXTENT_SIZE, mtr);
1614
if (free == ULINT_UNDEFINED) {
1616
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1622
page_no = xdes_get_offset(descr) + free;
1624
space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1626
if (space_size <= page_no) {
1627
/* It must be that we are extending a single-table tablespace
1628
whose size is still < 64 pages */
1631
if (page_no >= FSP_EXTENT_SIZE) {
1633
"InnoDB: Error: trying to extend a"
1634
" single-table tablespace %lu\n"
1635
"InnoDB: by single page(s) though the"
1636
" space size %lu. Page no %lu.\n",
1637
(ulong) space, (ulong) space_size,
1641
success = fsp_try_extend_data_file_with_pages(space, page_no,
1644
/* No disk space left */
1649
xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1651
/* Update the FRAG_N_USED field */
1652
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1655
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1657
if (xdes_is_full(descr, mtr)) {
1658
/* The fragment is full: move it to another list */
1659
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1661
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1663
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1665
mlog_write_ulint(header + FSP_FRAG_N_USED,
1666
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1670
/* Initialize the allocated page to the buffer pool, so that it can
1671
be obtained immediately with buf_page_get without need for a disk
1674
buf_page_create(space, page_no, zip_size, mtr);
1676
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1677
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1679
/* Prior contents of the page should be ignored */
1680
fsp_init_file_page(block, mtr);
1685
/**********************************************************************//**
1686
Frees a single page of a space. The page is marked as free and clean. */
1691
ulint space, /*!< in: space id */
1692
ulint zip_size,/*!< in: compressed page size in bytes
1693
or 0 for uncompressed pages */
1694
ulint page, /*!< in: page offset */
1695
mtr_t* mtr) /*!< in: mtr handle */
1697
fsp_header_t* header;
1704
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1706
header = fsp_get_space_header(space, zip_size, mtr);
1708
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1710
state = xdes_get_state(descr, mtr);
1712
if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1714
"InnoDB: Error: File space extent descriptor"
1715
" of page %lu has state %lu\n",
1718
fputs("InnoDB: Dump of descriptor: ", stderr);
1719
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1722
if (state == XDES_FREE) {
1723
/* We put here some fault tolerance: if the page
1724
is already free, return without doing anything! */
1732
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1734
"InnoDB: Error: File space extent descriptor"
1735
" of page %lu says it is free\n"
1736
"InnoDB: Dump of descriptor: ", (ulong) page);
1737
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1740
/* We put here some fault tolerance: if the page
1741
is already free, return without doing anything! */
1746
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1747
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1749
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1751
if (state == XDES_FULL_FRAG) {
1752
/* The fragment was full: move it to another list */
1753
flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1755
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1756
flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1758
mlog_write_ulint(header + FSP_FRAG_N_USED,
1759
frag_n_used + FSP_EXTENT_SIZE - 1,
1762
ut_a(frag_n_used > 0);
1763
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1767
if (xdes_is_free(descr, mtr)) {
1768
/* The extent has become free: move it to another list */
1769
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1771
fsp_free_extent(space, zip_size, page, mtr);
1775
/**********************************************************************//**
1776
Returns an extent to the free list of a space. */
1781
ulint space, /*!< in: space id */
1782
ulint zip_size,/*!< in: compressed page size in bytes
1783
or 0 for uncompressed pages */
1784
ulint page, /*!< in: page offset in the extent */
1785
mtr_t* mtr) /*!< in: mtr */
1787
fsp_header_t* header;
1792
header = fsp_get_space_header(space, zip_size, mtr);
1794
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1796
if (xdes_get_state(descr, mtr) == XDES_FREE) {
1798
ut_print_buf(stderr, (byte*)descr - 500, 1000);
1804
xdes_init(descr, mtr);
1806
flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1809
/**********************************************************************//**
1810
Returns the nth inode slot on an inode page.
1811
@return segment inode */
1814
fsp_seg_inode_page_get_nth_inode(
1815
/*=============================*/
1816
page_t* page, /*!< in: segment inode page */
1817
ulint i, /*!< in: inode index on page */
1818
ulint zip_size __attribute__((unused)),
1819
/*!< in: compressed page size, or 0 */
1820
mtr_t* mtr __attribute__((unused)))
1821
/*!< in: mini-transaction handle */
1823
ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1824
ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1826
return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1829
/**********************************************************************//**
1830
Looks for a used segment inode on a segment inode page.
1831
@return segment inode index, or ULINT_UNDEFINED if not found */
1834
fsp_seg_inode_page_find_used(
1835
/*=========================*/
1836
page_t* page, /*!< in: segment inode page */
1837
ulint zip_size,/*!< in: compressed page size, or 0 */
1838
mtr_t* mtr) /*!< in: mini-transaction handle */
1841
fseg_inode_t* inode;
1843
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1845
inode = fsp_seg_inode_page_get_nth_inode(
1846
page, i, zip_size, mtr);
1848
if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
1851
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1852
== FSEG_MAGIC_N_VALUE);
1857
return(ULINT_UNDEFINED);
1860
/**********************************************************************//**
1861
Looks for an unused segment inode on a segment inode page.
1862
@return segment inode index, or ULINT_UNDEFINED if not found */
1865
fsp_seg_inode_page_find_free(
1866
/*=========================*/
1867
page_t* page, /*!< in: segment inode page */
1868
ulint i, /*!< in: search forward starting from this index */
1869
ulint zip_size,/*!< in: compressed page size, or 0 */
1870
mtr_t* mtr) /*!< in: mini-transaction handle */
1872
fseg_inode_t* inode;
1874
for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1876
inode = fsp_seg_inode_page_get_nth_inode(
1877
page, i, zip_size, mtr);
1879
if (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
1880
/* This is unused */
1885
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1886
== FSEG_MAGIC_N_VALUE);
1889
return(ULINT_UNDEFINED);
1892
/**********************************************************************//**
1893
Allocates a new file segment inode page.
1894
@return TRUE if could be allocated */
1897
fsp_alloc_seg_inode_page(
1898
/*=====================*/
1899
fsp_header_t* space_header, /*!< in: space header */
1900
mtr_t* mtr) /*!< in: mini-transaction handle */
1902
fseg_inode_t* inode;
1910
ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1912
space = page_get_space_id(page_align(space_header));
1913
zip_size = dict_table_flags_to_zip_size(
1914
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1916
page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
1918
if (page_no == FIL_NULL) {
1923
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1924
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1926
block->check_index_page_at_flush = FALSE;
1928
page = buf_block_get_frame(block);
1930
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
1933
for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1935
inode = fsp_seg_inode_page_get_nth_inode(page, i,
1938
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
1941
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1942
page + FSEG_INODE_PAGE_NODE, mtr);
1946
/**********************************************************************//**
1947
Allocates a new file segment inode.
1948
@return segment inode, or NULL if not enough space */
1951
fsp_alloc_seg_inode(
1952
/*================*/
1953
fsp_header_t* space_header, /*!< in: space header */
1954
mtr_t* mtr) /*!< in: mini-transaction handle */
1959
fseg_inode_t* inode;
1964
ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1966
if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1967
/* Allocate a new segment inode page */
1969
success = fsp_alloc_seg_inode_page(space_header, mtr);
1977
page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1979
zip_size = dict_table_flags_to_zip_size(
1980
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1981
block = buf_page_get(page_get_space_id(page_align(space_header)),
1982
zip_size, page_no, RW_X_LATCH, mtr);
1983
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1985
page = buf_block_get_frame(block);
1987
n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1989
ut_a(n != ULINT_UNDEFINED);
1991
inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1993
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1995
/* There are no other unused headers left on the page: move it
1998
flst_remove(space_header + FSP_SEG_INODES_FREE,
1999
page + FSEG_INODE_PAGE_NODE, mtr);
2001
flst_add_last(space_header + FSP_SEG_INODES_FULL,
2002
page + FSEG_INODE_PAGE_NODE, mtr);
2005
ut_ad(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))
2006
|| mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2010
/**********************************************************************//**
2011
Frees a file segment inode. */
2016
ulint space, /*!< in: space id */
2017
ulint zip_size,/*!< in: compressed page size in bytes
2018
or 0 for uncompressed pages */
2019
fseg_inode_t* inode, /*!< in: segment inode */
2020
mtr_t* mtr) /*!< in: mini-transaction handle */
2023
fsp_header_t* space_header;
2025
page = page_align(inode);
2027
space_header = fsp_get_space_header(space, zip_size, mtr);
2029
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2032
== fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
2034
/* Move the page to another list */
2036
flst_remove(space_header + FSP_SEG_INODES_FULL,
2037
page + FSEG_INODE_PAGE_NODE, mtr);
2039
flst_add_last(space_header + FSP_SEG_INODES_FREE,
2040
page + FSEG_INODE_PAGE_NODE, mtr);
2043
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
2044
mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
2047
== fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
2049
/* There are no other used headers left on the page: free it */
2051
flst_remove(space_header + FSP_SEG_INODES_FREE,
2052
page + FSEG_INODE_PAGE_NODE, mtr);
2054
fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
2058
/**********************************************************************//**
2059
Returns the file segment inode, page x-latched.
2060
@return segment inode, page x-latched; NULL if the inode is free */
2065
fseg_header_t* header, /*!< in: segment header */
2066
ulint space, /*!< in: space id */
2067
ulint zip_size,/*!< in: compressed page size in bytes
2068
or 0 for uncompressed pages */
2069
mtr_t* mtr) /*!< in: mtr handle */
2071
fil_addr_t inode_addr;
2072
fseg_inode_t* inode;
2074
inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
2075
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
2076
ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
2078
inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
2081
(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) {
2085
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2086
== FSEG_MAGIC_N_VALUE);
2092
/**********************************************************************//**
2093
Returns the file segment inode, page x-latched.
2094
@return segment inode, page x-latched */
2099
fseg_header_t* header, /*!< in: segment header */
2100
ulint space, /*!< in: space id */
2101
ulint zip_size,/*!< in: compressed page size in bytes
2102
or 0 for uncompressed pages */
2103
mtr_t* mtr) /*!< in: mtr handle */
2106
= fseg_inode_try_get(header, space, zip_size, mtr);
2111
/**********************************************************************//**
2112
Gets the page number from the nth fragment page slot.
2113
@return page number, FIL_NULL if not in use */
2116
fseg_get_nth_frag_page_no(
2117
/*======================*/
2118
fseg_inode_t* inode, /*!< in: segment inode */
2119
ulint n, /*!< in: slot index */
2120
mtr_t* mtr __attribute__((unused))) /*!< in: mtr handle */
2122
ut_ad(inode && mtr);
2123
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2124
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2125
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2126
return(mach_read_from_4(inode + FSEG_FRAG_ARR
2127
+ n * FSEG_FRAG_SLOT_SIZE));
2130
/**********************************************************************//**
2131
Sets the page number in the nth fragment page slot. */
2134
fseg_set_nth_frag_page_no(
2135
/*======================*/
2136
fseg_inode_t* inode, /*!< in: segment inode */
2137
ulint n, /*!< in: slot index */
2138
ulint page_no,/*!< in: page number to set */
2139
mtr_t* mtr) /*!< in: mtr handle */
2141
ut_ad(inode && mtr);
2142
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2143
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2144
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2146
mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
2147
page_no, MLOG_4BYTES, mtr);
2150
/**********************************************************************//**
2151
Finds a fragment page slot which is free.
2152
@return slot index; ULINT_UNDEFINED if none found */
2155
fseg_find_free_frag_page_slot(
2156
/*==========================*/
2157
fseg_inode_t* inode, /*!< in: segment inode */
2158
mtr_t* mtr) /*!< in: mtr handle */
2163
ut_ad(inode && mtr);
2165
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2166
page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
2168
if (page_no == FIL_NULL) {
2174
return(ULINT_UNDEFINED);
2177
/**********************************************************************//**
2178
Finds a fragment page slot which is used and last in the array.
2179
@return slot index; ULINT_UNDEFINED if none found */
2182
fseg_find_last_used_frag_page_slot(
2183
/*===============================*/
2184
fseg_inode_t* inode, /*!< in: segment inode */
2185
mtr_t* mtr) /*!< in: mtr handle */
2190
ut_ad(inode && mtr);
2192
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2193
page_no = fseg_get_nth_frag_page_no(
2194
inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
2196
if (page_no != FIL_NULL) {
2198
return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
2202
return(ULINT_UNDEFINED);
2205
/**********************************************************************//**
2206
Calculates reserved fragment page slots.
2207
@return number of fragment pages */
2210
fseg_get_n_frag_pages(
2211
/*==================*/
2212
fseg_inode_t* inode, /*!< in: segment inode */
2213
mtr_t* mtr) /*!< in: mtr handle */
2218
ut_ad(inode && mtr);
2220
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2221
if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2229
/**********************************************************************//**
2230
Creates a new segment.
2231
@return the block where the segment header is placed, x-latched, NULL
2232
if could not create segment because of lack of space */
2235
fseg_create_general(
2236
/*================*/
2237
ulint space, /*!< in: space id */
2238
ulint page, /*!< in: page where the segment header is placed: if
2239
this is != 0, the page must belong to another segment,
2240
if this is 0, a new page will be allocated and it
2241
will belong to the created segment */
2242
ulint byte_offset, /*!< in: byte offset of the created segment header
2244
ibool has_done_reservation, /*!< in: TRUE if the caller has already
2245
done the reservation for the pages with
2246
fsp_reserve_free_extents (at least 2 extents: one for
2247
the inode and the other for the segment) then there is
2248
no need to do the check for this individual
2250
mtr_t* mtr) /*!< in: mtr */
2254
fsp_header_t* space_header;
2255
fseg_inode_t* inode;
2257
buf_block_t* block = 0; /* remove warning */
2258
fseg_header_t* header = 0; /* remove warning */
2265
ut_ad(byte_offset + FSEG_HEADER_SIZE
2266
<= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2268
latch = fil_space_get_latch(space, &flags);
2269
zip_size = dict_table_flags_to_zip_size(flags);
2272
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2273
header = byte_offset + buf_block_get_frame(block);
2276
ut_ad(!mutex_own(&kernel_mutex)
2277
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2279
mtr_x_lock(latch, mtr);
2281
if (rw_lock_get_x_lock_count(latch) == 1) {
2282
/* This thread did not own the latch before this call: free
2283
excess pages from the insert buffer free list */
2285
if (space == IBUF_SPACE_ID) {
2286
ibuf_free_excess_pages();
2290
if (!has_done_reservation) {
2291
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2298
space_header = fsp_get_space_header(space, zip_size, mtr);
2300
inode = fsp_alloc_seg_inode(space_header, mtr);
2302
if (inode == NULL) {
2307
/* Read the next segment id from space header and increment the
2308
value in space header */
2310
seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, mtr);
2312
mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1),
2315
mlog_write_dulint(inode + FSEG_ID, seg_id, mtr);
2316
mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2318
flst_init(inode + FSEG_FREE, mtr);
2319
flst_init(inode + FSEG_NOT_FULL, mtr);
2320
flst_init(inode + FSEG_FULL, mtr);
2322
mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2324
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2325
fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2329
page = fseg_alloc_free_page_low(space, zip_size,
2330
inode, 0, FSP_UP, mtr);
2332
if (page == FIL_NULL) {
2334
fsp_free_seg_inode(space, zip_size, inode, mtr);
2339
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2340
header = byte_offset + buf_block_get_frame(block);
2341
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2342
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
2345
mlog_write_ulint(header + FSEG_HDR_OFFSET,
2346
page_offset(inode), MLOG_2BYTES, mtr);
2348
mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2349
page_get_page_no(page_align(inode)),
2352
mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2355
if (!has_done_reservation) {
2357
fil_space_release_free_extents(space, n_reserved);
2363
/**********************************************************************//**
2364
Creates a new segment.
2365
@return the block where the segment header is placed, x-latched, NULL
2366
if could not create segment because of lack of space */
2371
ulint space, /*!< in: space id */
2372
ulint page, /*!< in: page where the segment header is placed: if
2373
this is != 0, the page must belong to another segment,
2374
if this is 0, a new page will be allocated and it
2375
will belong to the created segment */
2376
ulint byte_offset, /*!< in: byte offset of the created segment header
2378
mtr_t* mtr) /*!< in: mtr */
2380
return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2383
/**********************************************************************//**
2384
Calculates the number of pages reserved by a segment, and how many pages are
2386
@return number of reserved pages */
2389
fseg_n_reserved_pages_low(
2390
/*======================*/
2391
fseg_inode_t* inode, /*!< in: segment inode */
2392
ulint* used, /*!< out: number of pages used (not
2393
more than reserved) */
2394
mtr_t* mtr) /*!< in: mtr handle */
2398
ut_ad(inode && used && mtr);
2399
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2401
*used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2402
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2403
+ fseg_get_n_frag_pages(inode, mtr);
2405
ret = fseg_get_n_frag_pages(inode, mtr)
2406
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2407
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2408
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2413
/**********************************************************************//**
2414
Calculates the number of pages reserved by a segment, and how many pages are
2416
@return number of reserved pages */
2419
fseg_n_reserved_pages(
2420
/*==================*/
2421
fseg_header_t* header, /*!< in: segment header */
2422
ulint* used, /*!< out: number of pages used (<= reserved) */
2423
mtr_t* mtr) /*!< in: mtr handle */
2426
fseg_inode_t* inode;
2432
space = page_get_space_id(page_align(header));
2433
latch = fil_space_get_latch(space, &flags);
2434
zip_size = dict_table_flags_to_zip_size(flags);
2436
ut_ad(!mutex_own(&kernel_mutex)
2437
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2439
mtr_x_lock(latch, mtr);
2441
inode = fseg_inode_get(header, space, zip_size, mtr);
2443
ret = fseg_n_reserved_pages_low(inode, used, mtr);
2448
/*********************************************************************//**
2449
Tries to fill the free list of a segment with consecutive free extents.
2450
This happens if the segment is big enough to allow extents in the free list,
2451
the free list is empty, and the extents can be allocated consecutively from
2455
fseg_fill_free_list(
2456
/*================*/
2457
fseg_inode_t* inode, /*!< in: segment inode */
2458
ulint space, /*!< in: space id */
2459
ulint zip_size,/*!< in: compressed page size in bytes
2460
or 0 for uncompressed pages */
2461
ulint hint, /*!< in: hint which extent would be good as
2463
mtr_t* mtr) /*!< in: mtr */
2471
ut_ad(inode && mtr);
2472
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2474
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2476
if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2478
/* The segment is too small to allow extents in free list */
2483
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2484
/* Free list is not empty */
2489
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2490
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2493
|| (XDES_FREE != xdes_get_state(descr, mtr))) {
2495
/* We cannot allocate the desired extent: stop */
2500
descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2502
xdes_set_state(descr, XDES_FSEG, mtr);
2504
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2505
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2506
== FSEG_MAGIC_N_VALUE);
2507
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2509
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2510
hint += FSP_EXTENT_SIZE;
2514
/*********************************************************************//**
2515
Allocates a free extent for the segment: looks first in the free list of the
2516
segment, then tries to allocate from the space free list. NOTE that the extent
2517
returned still resides in the segment free list, it is not yet taken off it!
2518
@return allocated extent, still placed in the segment free list, NULL
2519
if could not be allocated */
2522
fseg_alloc_free_extent(
2523
/*===================*/
2524
fseg_inode_t* inode, /*!< in: segment inode */
2525
ulint space, /*!< in: space id */
2526
ulint zip_size,/*!< in: compressed page size in bytes
2527
or 0 for uncompressed pages */
2528
mtr_t* mtr) /*!< in: mtr */
2534
ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2535
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2537
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2538
/* Segment free list is not empty, allocate from it */
2540
first = flst_get_first(inode + FSEG_FREE, mtr);
2542
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2544
/* Segment free list was empty, allocate from space */
2545
descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2547
if (descr == NULL) {
2552
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2554
xdes_set_state(descr, XDES_FSEG, mtr);
2555
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2556
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2558
/* Try to fill the segment free list */
2559
fseg_fill_free_list(inode, space, zip_size,
2560
xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2567
/**********************************************************************//**
2568
Allocates a single free page from a segment. This function implements
2569
the intelligent allocation strategy which tries to minimize file space
2571
@return the allocated page number, FIL_NULL if no page could be allocated */
2574
fseg_alloc_free_page_low(
2575
/*=====================*/
2576
ulint space, /*!< in: space */
2577
ulint zip_size,/*!< in: compressed page size in bytes
2578
or 0 for uncompressed pages */
2579
fseg_inode_t* seg_inode, /*!< in: segment inode */
2580
ulint hint, /*!< in: hint of which page would be desirable */
2581
byte direction, /*!< in: if the new page is needed because
2582
of an index page split, and records are
2583
inserted there in order, into which
2584
direction they go alphabetically: FSP_DOWN,
2585
FSP_UP, FSP_NO_DIR */
2586
mtr_t* mtr) /*!< in: mtr handle */
2588
fsp_header_t* space_header;
2593
xdes_t* descr; /*!< extent of the hinted page */
2594
ulint ret_page; /*!< the allocated page offset, FIL_NULL
2595
if could not be allocated */
2596
xdes_t* ret_descr; /*!< the extent of the allocated page */
2597
ibool frag_page_allocated = FALSE;
2602
ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2603
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2604
== FSEG_MAGIC_N_VALUE);
2605
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2606
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
2608
ut_ad(!ut_dulint_is_zero(seg_id));
2610
reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2612
space_header = fsp_get_space_header(space, zip_size, mtr);
2614
descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2616
if (descr == NULL) {
2617
/* Hint outside space or too high above free limit: reset
2620
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2623
/* In the big if-else below we look for ret_page and ret_descr */
2624
/*-------------------------------------------------------------*/
2625
if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2626
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2628
&& (xdes_get_bit(descr, XDES_FREE_BIT,
2629
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2631
/* 1. We can take the hinted page
2632
=================================*/
2635
/*-----------------------------------------------------------*/
2636
} else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2637
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2638
&& (used >= FSEG_FRAG_LIMIT)) {
2640
/* 2. We allocate the free extent from space and can take
2641
=========================================================
2644
ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2646
ut_a(ret_descr == descr);
2648
xdes_set_state(ret_descr, XDES_FSEG, mtr);
2649
mlog_write_dulint(ret_descr + XDES_ID, seg_id, mtr);
2650
flst_add_last(seg_inode + FSEG_FREE,
2651
ret_descr + XDES_FLST_NODE, mtr);
2653
/* Try to fill the segment free list */
2654
fseg_fill_free_list(seg_inode, space, zip_size,
2655
hint + FSP_EXTENT_SIZE, mtr);
2657
/*-----------------------------------------------------------*/
2658
} else if ((direction != FSP_NO_DIR)
2659
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2660
&& (used >= FSEG_FRAG_LIMIT)
2662
= fseg_alloc_free_extent(seg_inode,
2663
space, zip_size, mtr)))) {
2665
/* 3. We take any free extent (which was already assigned above
2666
===============================================================
2667
in the if-condition to ret_descr) and take the lowest or
2668
========================================================
2669
highest page in it, depending on the direction
2670
==============================================*/
2671
ret_page = xdes_get_offset(ret_descr);
2673
if (direction == FSP_DOWN) {
2674
ret_page += FSP_EXTENT_SIZE - 1;
2676
/*-----------------------------------------------------------*/
2677
} else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2678
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2680
&& (!xdes_is_full(descr, mtr))) {
2682
/* 4. We can take the page from the same extent as the
2683
======================================================
2684
hinted page (and the extent already belongs to the
2685
==================================================
2689
ret_page = xdes_get_offset(ret_descr)
2690
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2691
hint % FSP_EXTENT_SIZE, mtr);
2692
/*-----------------------------------------------------------*/
2693
} else if (reserved - used > 0) {
2694
/* 5. We take any unused page from the segment
2695
==============================================*/
2698
if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2699
first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2701
} else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2702
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2708
ret_descr = xdes_lst_get_descriptor(space, zip_size,
2710
ret_page = xdes_get_offset(ret_descr)
2711
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2713
/*-----------------------------------------------------------*/
2714
} else if (used < FSEG_FRAG_LIMIT) {
2715
/* 6. We allocate an individual page from the space
2716
===================================================*/
2717
ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
2720
frag_page_allocated = TRUE;
2722
if (ret_page != FIL_NULL) {
2723
/* Put the page in the fragment page array of the
2725
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2726
ut_a(n != FIL_NULL);
2728
fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2731
/*-----------------------------------------------------------*/
2733
/* 7. We allocate a new extent and take its first page
2734
======================================================*/
2735
ret_descr = fseg_alloc_free_extent(seg_inode,
2736
space, zip_size, mtr);
2738
if (ret_descr == NULL) {
2739
ret_page = FIL_NULL;
2741
ret_page = xdes_get_offset(ret_descr);
2745
if (ret_page == FIL_NULL) {
2746
/* Page could not be allocated */
2752
space_size = fil_space_get_size(space);
2754
if (space_size <= ret_page) {
2755
/* It must be that we are extending a single-table
2756
tablespace whose size is still < 64 pages */
2758
if (ret_page >= FSP_EXTENT_SIZE) {
2760
"InnoDB: Error (2): trying to extend"
2761
" a single-table tablespace %lu\n"
2762
"InnoDB: by single page(s) though"
2763
" the space size %lu. Page no %lu.\n",
2764
(ulong) space, (ulong) space_size,
2769
success = fsp_try_extend_data_file_with_pages(
2770
space, ret_page, space_header, mtr);
2772
/* No disk space left */
2778
if (!frag_page_allocated) {
2779
/* Initialize the allocated page to buffer pool, so that it
2780
can be obtained immediately with buf_page_get without need
2783
ulint zip_size = dict_table_flags_to_zip_size(
2784
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
2786
block = buf_page_create(space, ret_page, zip_size, mtr);
2787
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
2789
if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
2790
ret_page, RW_X_LATCH,
2795
/* The prior contents of the page should be ignored */
2796
fsp_init_file_page(block, mtr);
2798
/* At this point we know the extent and the page offset.
2799
The extent is still in the appropriate list (FSEG_NOT_FULL
2800
or FSEG_FREE), and the page is not yet marked as used. */
2802
ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
2804
ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2805
ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2807
fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
2810
buf_reset_check_index_page_at_flush(space, ret_page);
2815
/**********************************************************************//**
2816
Allocates a single free page from a segment. This function implements
2817
the intelligent allocation strategy which tries to minimize file space
2819
@return allocated page offset, FIL_NULL if no page could be allocated */
2822
fseg_alloc_free_page_general(
2823
/*=========================*/
2824
fseg_header_t* seg_header,/*!< in: segment header */
2825
ulint hint, /*!< in: hint of which page would be desirable */
2826
byte direction,/*!< in: if the new page is needed because
2827
of an index page split, and records are
2828
inserted there in order, into which
2829
direction they go alphabetically: FSP_DOWN,
2830
FSP_UP, FSP_NO_DIR */
2831
ibool has_done_reservation, /*!< in: TRUE if the caller has
2832
already done the reservation for the page
2833
with fsp_reserve_free_extents, then there
2834
is no need to do the check for this individual
2836
mtr_t* mtr) /*!< in: mtr handle */
2838
fseg_inode_t* inode;
2847
space = page_get_space_id(page_align(seg_header));
2849
latch = fil_space_get_latch(space, &flags);
2851
zip_size = dict_table_flags_to_zip_size(flags);
2853
ut_ad(!mutex_own(&kernel_mutex)
2854
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2856
mtr_x_lock(latch, mtr);
2858
if (rw_lock_get_x_lock_count(latch) == 1) {
2859
/* This thread did not own the latch before this call: free
2860
excess pages from the insert buffer free list */
2862
if (space == IBUF_SPACE_ID) {
2863
ibuf_free_excess_pages();
2867
inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2869
if (!has_done_reservation) {
2870
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2877
page_no = fseg_alloc_free_page_low(space, zip_size,
2878
inode, hint, direction, mtr);
2879
if (!has_done_reservation) {
2880
fil_space_release_free_extents(space, n_reserved);
2886
/**********************************************************************//**
2887
Allocates a single free page from a segment. This function implements
2888
the intelligent allocation strategy which tries to minimize file space
2890
@return allocated page offset, FIL_NULL if no page could be allocated */
2893
fseg_alloc_free_page(
2894
/*=================*/
2895
fseg_header_t* seg_header,/*!< in: segment header */
2896
ulint hint, /*!< in: hint of which page would be desirable */
2897
byte direction,/*!< in: if the new page is needed because
2898
of an index page split, and records are
2899
inserted there in order, into which
2900
direction they go alphabetically: FSP_DOWN,
2901
FSP_UP, FSP_NO_DIR */
2902
mtr_t* mtr) /*!< in: mtr handle */
2904
return(fseg_alloc_free_page_general(seg_header, hint, direction,
2908
/**********************************************************************//**
2909
Checks that we have at least 2 frag pages free in the first extent of a
2910
single-table tablespace, and they are also physically initialized to the data
2911
file. That is we have already extended the data file so that those pages are
2912
inside the data file. If not, this function extends the tablespace with
2914
@return TRUE if there were >= 3 free pages, or we were able to extend */
2917
fsp_reserve_free_pages(
2918
/*===================*/
2919
ulint space, /*!< in: space id, must be != 0 */
2920
fsp_header_t* space_header, /*!< in: header of that space,
2922
ulint size, /*!< in: size of the tablespace in pages,
2923
must be < FSP_EXTENT_SIZE / 2 */
2924
mtr_t* mtr) /*!< in: mtr */
2930
ut_a(size < FSP_EXTENT_SIZE / 2);
2932
descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2934
n_used = xdes_get_n_used(descr, mtr);
2936
ut_a(n_used <= size);
2938
if (size >= n_used + 2) {
2943
return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2944
space_header, mtr));
2947
/**********************************************************************//**
2948
Reserves free pages from a tablespace. All mini-transactions which may
2949
use several pages from the tablespace should call this function beforehand
2950
and reserve enough free extents so that they certainly will be able
2951
to do their operation, like a B-tree page split, fully. Reservations
2952
must be released with function fil_space_release_free_extents!
2954
The alloc_type below has the following meaning: FSP_NORMAL means an
2955
operation which will probably result in more space usage, like an
2956
insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
2957
deleting rows, then this allocation will in the long run result in
2958
less space usage (after a purge); FSP_CLEANING means allocation done
2959
in a physical record delete (like in a purge) or other cleaning operation
2960
which will result in less space usage in the long run. We prefer the latter
2961
two types of allocation: when space is scarce, FSP_NORMAL allocations
2962
will not succeed, but the latter two allocations will succeed, if possible.
2963
The purpose is to avoid dead end where the database is full but the
2964
user cannot free any space because these freeing operations temporarily
2967
Single-table tablespaces whose size is < 32 pages are a special case. In this
2968
function we would liberally reserve several 64 page extents for every page
2969
split or merge in a B-tree. But we do not want to waste disk space if the table
2970
only occupies < 32 pages. That is why we apply different rules in that special
2971
case, just ensuring that there are 3 free pages available.
2972
@return TRUE if we were able to make the reservation */
2975
fsp_reserve_free_extents(
2976
/*=====================*/
2977
ulint* n_reserved,/*!< out: number of extents actually reserved; if we
2978
return TRUE and the tablespace size is < 64 pages,
2979
then this can be 0, otherwise it is n_ext */
2980
ulint space, /*!< in: space id */
2981
ulint n_ext, /*!< in: number of extents to reserve */
2982
ulint alloc_type,/*!< in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
2983
mtr_t* mtr) /*!< in: mtr */
2985
fsp_header_t* space_header;
2987
ulint n_free_list_ext;
2996
ulint n_pages_added;
2999
*n_reserved = n_ext;
3001
latch = fil_space_get_latch(space, &flags);
3002
zip_size = dict_table_flags_to_zip_size(flags);
3004
ut_ad(!mutex_own(&kernel_mutex)
3005
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3007
mtr_x_lock(latch, mtr);
3009
space_header = fsp_get_space_header(space, zip_size, mtr);
3011
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
3013
if (size < FSP_EXTENT_SIZE / 2) {
3014
/* Use different rules for small single-table tablespaces */
3016
return(fsp_reserve_free_pages(space, space_header, size, mtr));
3019
n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
3021
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3024
/* Below we play safe when counting free extents above the free limit:
3025
some of them will contain extent descriptor pages, and therefore
3026
will not be free extents */
3028
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3030
if (n_free_up > 0) {
3033
n_free_up -= n_free_up
3034
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3036
n_free_up -= n_free_up
3037
/ (zip_size / FSP_EXTENT_SIZE);
3041
n_free = n_free_list_ext + n_free_up;
3043
if (alloc_type == FSP_NORMAL) {
3044
/* We reserve 1 extent + 0.5 % of the space size to undo logs
3045
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3046
code is duplicated in the function below! */
3048
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3050
if (n_free <= reserve + n_ext) {
3054
} else if (alloc_type == FSP_UNDO) {
3055
/* We reserve 0.5 % of the space size to cleaning operations */
3057
reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
3059
if (n_free <= reserve + n_ext) {
3064
ut_a(alloc_type == FSP_CLEANING);
3067
success = fil_space_reserve_free_extents(space, n_free, n_ext);
3073
success = fsp_try_extend_data_file(&n_pages_added, space,
3075
if (success && n_pages_added > 0) {
3083
/**********************************************************************//**
3084
This function should be used to get information on how much we still
3085
will be able to insert new data to the database without running out the
3086
tablespace. Only free extents are taken into account and we also subtract
3087
the safety margin required by the above function fsp_reserve_free_extents.
3088
@return available space in kB */
3091
fsp_get_available_space_in_free_extents(
3092
/*====================================*/
3093
ulint space) /*!< in: space id */
3095
fsp_header_t* space_header;
3096
ulint n_free_list_ext;
3107
ut_ad(!mutex_own(&kernel_mutex));
3111
latch = fil_space_get_latch(space, &flags);
3112
zip_size = dict_table_flags_to_zip_size(flags);
3114
mtr_x_lock(latch, &mtr);
3116
space_header = fsp_get_space_header(space, zip_size, &mtr);
3118
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
3120
n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
3122
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3126
if (size < FSP_EXTENT_SIZE) {
3127
ut_a(space != 0); /* This must be a single-table
3130
return(0); /* TODO: count free frag pages and
3131
return a value based on that */
3134
/* Below we play safe when counting free extents above the free limit:
3135
some of them will contain extent descriptor pages, and therefore
3136
will not be free extents */
3138
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3140
if (n_free_up > 0) {
3143
n_free_up -= n_free_up
3144
/ (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3146
n_free_up -= n_free_up
3147
/ (zip_size / FSP_EXTENT_SIZE);
3151
n_free = n_free_list_ext + n_free_up;
3153
/* We reserve 1 extent + 0.5 % of the space size to undo logs
3154
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3155
code is duplicated in the function above! */
3157
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3159
if (reserve > n_free) {
3164
return((ullint) (n_free - reserve)
3166
* (UNIV_PAGE_SIZE / 1024));
3168
return((ullint) (n_free - reserve)
3170
* (zip_size / 1024));
3174
/********************************************************************//**
3175
Marks a page used. The page must reside within the extents of the given
3179
fseg_mark_page_used(
3180
/*================*/
3181
fseg_inode_t* seg_inode,/*!< in: segment inode */
3182
ulint space, /*!< in: space id */
3183
ulint zip_size,/*!< in: compressed page size in bytes
3184
or 0 for uncompressed pages */
3185
ulint page, /*!< in: page offset */
3186
mtr_t* mtr) /*!< in: mtr */
3189
ulint not_full_n_used;
3191
ut_ad(seg_inode && mtr);
3192
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3193
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3194
== FSEG_MAGIC_N_VALUE);
3196
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3198
ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
3199
== mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
3201
if (xdes_is_free(descr, mtr)) {
3202
/* We move the extent from the free list to the
3204
flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3206
flst_add_last(seg_inode + FSEG_NOT_FULL,
3207
descr + XDES_FLST_NODE, mtr);
3210
ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
3212
/* We mark the page as used */
3213
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3215
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3218
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3220
if (xdes_is_full(descr, mtr)) {
3221
/* We move the extent from the NOT_FULL list to the
3223
flst_remove(seg_inode + FSEG_NOT_FULL,
3224
descr + XDES_FLST_NODE, mtr);
3225
flst_add_last(seg_inode + FSEG_FULL,
3226
descr + XDES_FLST_NODE, mtr);
3228
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3229
not_full_n_used - FSP_EXTENT_SIZE,
3234
/**********************************************************************//**
3235
Frees a single page of a segment. */
3240
fseg_inode_t* seg_inode, /*!< in: segment inode */
3241
ulint space, /*!< in: space id */
3242
ulint zip_size,/*!< in: compressed page size in bytes
3243
or 0 for uncompressed pages */
3244
ulint page, /*!< in: page offset */
3245
mtr_t* mtr) /*!< in: mtr handle */
3248
ulint not_full_n_used;
3254
ut_ad(seg_inode && mtr);
3255
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3256
== FSEG_MAGIC_N_VALUE);
3257
ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3259
/* Drop search system page hash index if the page is found in
3260
the pool and is hashed */
3262
btr_search_drop_page_hash_when_freed(space, zip_size, page);
3264
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3267
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
3268
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3270
ut_print_buf(stderr, descr, 40);
3272
fprintf(stderr, "\n"
3273
"InnoDB: Serious error! InnoDB is trying to"
3275
"InnoDB: though it is already marked as free"
3276
" in the tablespace!\n"
3277
"InnoDB: The tablespace free space info is corrupt.\n"
3278
"InnoDB: You may need to dump your"
3279
" InnoDB tables and recreate the whole\n"
3280
"InnoDB: database!\n", (ulong) page);
3282
fputs("InnoDB: Please refer to\n"
3283
"InnoDB: " REFMAN "forcing-recovery.html\n"
3284
"InnoDB: about forcing recovery.\n", stderr);
3288
state = xdes_get_state(descr, mtr);
3290
if (state != XDES_FSEG) {
3291
/* The page is in the fragment pages of the segment */
3294
if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3297
fseg_set_nth_frag_page_no(seg_inode, i,
3303
fsp_free_page(space, zip_size, page, mtr);
3308
/* If we get here, the page is in some extent of the segment */
3310
descr_id = mtr_read_dulint(descr + XDES_ID, mtr);
3311
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
3314
"InnoDB: InnoDB is freeing space %lu page %lu,\n"
3315
"InnoDB: which belongs to descr seg %lu %lu\n"
3316
"InnoDB: segment %lu %lu.\n",
3317
(ulong) space, (ulong) page,
3318
(ulong) ut_dulint_get_high(descr_id),
3319
(ulong) ut_dulint_get_low(descr_id),
3320
(ulong) ut_dulint_get_high(seg_id),
3321
(ulong) ut_dulint_get_low(seg_id));
3323
if (0 != ut_dulint_cmp(descr_id, seg_id)) {
3324
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3326
ut_print_buf(stderr, descr, 40);
3327
fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3328
ut_print_buf(stderr, seg_inode, 40);
3332
"InnoDB: Serious error: InnoDB is trying to"
3333
" free space %lu page %lu,\n"
3334
"InnoDB: which does not belong to"
3335
" segment %lu %lu but belongs\n"
3336
"InnoDB: to segment %lu %lu.\n",
3337
(ulong) space, (ulong) page,
3338
(ulong) ut_dulint_get_high(descr_id),
3339
(ulong) ut_dulint_get_low(descr_id),
3340
(ulong) ut_dulint_get_high(seg_id),
3341
(ulong) ut_dulint_get_low(seg_id));
3345
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3347
if (xdes_is_full(descr, mtr)) {
3348
/* The fragment is full: move it to another list */
3349
flst_remove(seg_inode + FSEG_FULL,
3350
descr + XDES_FLST_NODE, mtr);
3351
flst_add_last(seg_inode + FSEG_NOT_FULL,
3352
descr + XDES_FLST_NODE, mtr);
3353
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3354
not_full_n_used + FSP_EXTENT_SIZE - 1,
3357
ut_a(not_full_n_used > 0);
3358
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3359
not_full_n_used - 1, MLOG_4BYTES, mtr);
3362
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3363
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3365
if (xdes_is_free(descr, mtr)) {
3366
/* The extent has become free: free it to space */
3367
flst_remove(seg_inode + FSEG_NOT_FULL,
3368
descr + XDES_FLST_NODE, mtr);
3369
fsp_free_extent(space, zip_size, page, mtr);
3373
/**********************************************************************//**
3374
Frees a single page of a segment. */
3379
fseg_header_t* seg_header, /*!< in: segment header */
3380
ulint space, /*!< in: space id */
3381
ulint page, /*!< in: page offset */
3382
mtr_t* mtr) /*!< in: mtr handle */
3386
fseg_inode_t* seg_inode;
3389
latch = fil_space_get_latch(space, &flags);
3390
zip_size = dict_table_flags_to_zip_size(flags);
3392
ut_ad(!mutex_own(&kernel_mutex)
3393
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3395
mtr_x_lock(latch, mtr);
3397
seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3399
fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3401
#ifdef UNIV_DEBUG_FILE_ACCESSES
3402
buf_page_set_file_page_was_freed(space, page);
3406
/**********************************************************************//**
3407
Frees an extent of a segment to the space free list. */
3412
fseg_inode_t* seg_inode, /*!< in: segment inode */
3413
ulint space, /*!< in: space id */
3414
ulint zip_size,/*!< in: compressed page size in bytes
3415
or 0 for uncompressed pages */
3416
ulint page, /*!< in: a page in the extent */
3417
mtr_t* mtr) /*!< in: mtr handle */
3419
ulint first_page_in_extent;
3421
ulint not_full_n_used;
3425
ut_ad(seg_inode && mtr);
3427
descr = xdes_get_descriptor(space, zip_size, page, mtr);
3429
ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3430
ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr),
3431
mtr_read_dulint(seg_inode + FSEG_ID, mtr)));
3432
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3433
== FSEG_MAGIC_N_VALUE);
3435
first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3437
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3438
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3440
/* Drop search system page hash index if the page is
3441
found in the pool and is hashed */
3443
btr_search_drop_page_hash_when_freed(
3444
space, zip_size, first_page_in_extent + i);
3448
if (xdes_is_full(descr, mtr)) {
3449
flst_remove(seg_inode + FSEG_FULL,
3450
descr + XDES_FLST_NODE, mtr);
3451
} else if (xdes_is_free(descr, mtr)) {
3452
flst_remove(seg_inode + FSEG_FREE,
3453
descr + XDES_FLST_NODE, mtr);
3455
flst_remove(seg_inode + FSEG_NOT_FULL,
3456
descr + XDES_FLST_NODE, mtr);
3458
not_full_n_used = mtr_read_ulint(
3459
seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3461
descr_n_used = xdes_get_n_used(descr, mtr);
3462
ut_a(not_full_n_used >= descr_n_used);
3463
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3464
not_full_n_used - descr_n_used,
3468
fsp_free_extent(space, zip_size, page, mtr);
3470
#ifdef UNIV_DEBUG_FILE_ACCESSES
3471
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3473
buf_page_set_file_page_was_freed(space,
3474
first_page_in_extent + i);
3479
/**********************************************************************//**
3480
Frees part of a segment. This function can be used to free a segment by
3481
repeatedly calling this function in different mini-transactions. Doing
3482
the freeing in a single mini-transaction might result in too big a
3484
@return TRUE if freeing completed */
3489
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
3490
resides on the first page of the frag list
3491
of the segment, this pointer becomes obsolete
3492
after the last freeing step */
3493
mtr_t* mtr) /*!< in: mtr */
3498
fseg_inode_t* inode;
3505
space = page_get_space_id(page_align(header));
3506
header_page = page_get_page_no(page_align(header));
3508
latch = fil_space_get_latch(space, &flags);
3509
zip_size = dict_table_flags_to_zip_size(flags);
3511
ut_ad(!mutex_own(&kernel_mutex)
3512
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3514
mtr_x_lock(latch, mtr);
3516
descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3518
/* Check that the header resides on a page which has not been
3522
ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
3523
header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3524
inode = fseg_inode_try_get(header, space, zip_size, mtr);
3526
if (UNIV_UNLIKELY(inode == NULL)) {
3527
fprintf(stderr, "double free of inode from %u:%u\n",
3528
(unsigned) space, (unsigned) header_page);
3532
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3534
if (descr != NULL) {
3535
/* Free the extent held by the segment */
3536
page = xdes_get_offset(descr);
3538
fseg_free_extent(inode, space, zip_size, page, mtr);
3543
/* Free a frag page */
3544
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3546
if (n == ULINT_UNDEFINED) {
3547
/* Freeing completed: free the segment inode */
3548
fsp_free_seg_inode(space, zip_size, inode, mtr);
3553
fseg_free_page_low(inode, space, zip_size,
3554
fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3556
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3558
if (n == ULINT_UNDEFINED) {
3559
/* Freeing completed: free the segment inode */
3560
fsp_free_seg_inode(space, zip_size, inode, mtr);
3568
/**********************************************************************//**
3569
Frees part of a segment. Differs from fseg_free_step because this function
3570
leaves the header page unfreed.
3571
@return TRUE if freeing completed, except the header page */
3574
fseg_free_step_not_header(
3575
/*======================*/
3576
fseg_header_t* header, /*!< in: segment header which must reside on
3577
the first fragment page of the segment */
3578
mtr_t* mtr) /*!< in: mtr */
3583
fseg_inode_t* inode;
3590
space = page_get_space_id(page_align(header));
3592
latch = fil_space_get_latch(space, &flags);
3593
zip_size = dict_table_flags_to_zip_size(flags);
3595
ut_ad(!mutex_own(&kernel_mutex)
3596
|| mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3598
mtr_x_lock(latch, mtr);
3600
inode = fseg_inode_get(header, space, zip_size, mtr);
3602
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3604
if (descr != NULL) {
3605
/* Free the extent held by the segment */
3606
page = xdes_get_offset(descr);
3608
fseg_free_extent(inode, space, zip_size, page, mtr);
3613
/* Free a frag page */
3615
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3617
if (n == ULINT_UNDEFINED) {
3621
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3623
if (page_no == page_get_page_no(page_align(header))) {
3628
fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3633
/**********************************************************************//**
3634
Returns the first extent descriptor for a segment. We think of the extent
3635
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
3637
@return the first extent descriptor, or NULL if none */
3640
fseg_get_first_extent(
3641
/*==================*/
3642
fseg_inode_t* inode, /*!< in: segment inode */
3643
ulint space, /*!< in: space id */
3644
ulint zip_size,/*!< in: compressed page size in bytes
3645
or 0 for uncompressed pages */
3646
mtr_t* mtr) /*!< in: mtr */
3651
ut_ad(inode && mtr);
3653
ut_ad(space == page_get_space_id(page_align(inode)));
3654
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3656
first = fil_addr_null;
3658
if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3660
first = flst_get_first(inode + FSEG_FULL, mtr);
3662
} else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3664
first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3666
} else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3668
first = flst_get_first(inode + FSEG_FREE, mtr);
3671
if (first.page == FIL_NULL) {
3675
descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3680
/*******************************************************************//**
3681
Validates a segment.
3682
@return TRUE if ok */
3687
fseg_inode_t* inode, /*!< in: segment inode */
3688
mtr_t* mtr2) /*!< in: mtr */
3694
fil_addr_t node_addr;
3698
ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3699
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3701
space = page_get_space_id(page_align(inode));
3703
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr2);
3704
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3706
flst_validate(inode + FSEG_FREE, mtr2);
3707
flst_validate(inode + FSEG_NOT_FULL, mtr2);
3708
flst_validate(inode + FSEG_FULL, mtr2);
3710
/* Validate FSEG_FREE list */
3711
node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3713
while (!fil_addr_is_null(node_addr)) {
3718
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3719
zip_size = dict_table_flags_to_zip_size(flags);
3721
descr = xdes_lst_get_descriptor(space, zip_size,
3724
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3725
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3726
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3729
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3733
/* Validate FSEG_NOT_FULL list */
3735
node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3737
while (!fil_addr_is_null(node_addr)) {
3742
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3743
zip_size = dict_table_flags_to_zip_size(flags);
3745
descr = xdes_lst_get_descriptor(space, zip_size,
3748
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3749
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3750
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3751
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3754
n_used2 += xdes_get_n_used(descr, &mtr);
3756
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3760
/* Validate FSEG_FULL list */
3762
node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3764
while (!fil_addr_is_null(node_addr)) {
3769
mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3770
zip_size = dict_table_flags_to_zip_size(flags);
3772
descr = xdes_lst_get_descriptor(space, zip_size,
3775
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3776
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3777
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3780
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3784
ut_a(n_used == n_used2);
3790
/*******************************************************************//**
3791
Validates a segment.
3792
@return TRUE if ok */
3797
fseg_header_t* header, /*!< in: segment header */
3798
mtr_t* mtr) /*!< in: mtr */
3800
fseg_inode_t* inode;
3806
space = page_get_space_id(page_align(header));
3808
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3809
zip_size = dict_table_flags_to_zip_size(flags);
3811
inode = fseg_inode_get(header, space, zip_size, mtr);
3813
ret = fseg_validate_low(inode, mtr);
3817
#endif /* UNIV_DEBUG */
3819
/*******************************************************************//**
3820
Writes info of a segment. */
3825
fseg_inode_t* inode, /*!< in: segment inode */
3826
mtr_t* mtr) /*!< in: mtr */
3841
ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3842
space = page_get_space_id(page_align(inode));
3843
page_no = page_get_page_no(page_align(inode));
3845
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3847
d_var = mtr_read_dulint(inode + FSEG_ID, mtr);
3849
seg_id_low = ut_dulint_get_low(d_var);
3850
seg_id_high = ut_dulint_get_high(d_var);
3852
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3854
n_frag = fseg_get_n_frag_pages(inode, mtr);
3855
n_free = flst_get_len(inode + FSEG_FREE, mtr);
3856
n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3857
n_full = flst_get_len(inode + FSEG_FULL, mtr);
3860
"SEGMENT id %lu %lu space %lu; page %lu;"
3861
" res %lu used %lu; full ext %lu\n"
3862
"fragm pages %lu; free extents %lu;"
3863
" not full extents %lu: pages %lu\n",
3864
(ulong) seg_id_high, (ulong) seg_id_low,
3865
(ulong) space, (ulong) page_no,
3866
(ulong) reserved, (ulong) used, (ulong) n_full,
3867
(ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3869
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3872
#ifdef UNIV_BTR_PRINT
3873
/*******************************************************************//**
3874
Writes info of a segment. */
3879
fseg_header_t* header, /*!< in: segment header */
3880
mtr_t* mtr) /*!< in: mtr */
3882
fseg_inode_t* inode;
3887
space = page_get_space_id(page_align(header));
3889
mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3890
zip_size = dict_table_flags_to_zip_size(flags);
3892
inode = fseg_inode_get(header, space, zip_size, mtr);
3894
fseg_print_low(inode, mtr);
3896
#endif /* UNIV_BTR_PRINT */
3898
/*******************************************************************//**
3899
Validates the file space system and its segments.
3900
@return TRUE if ok */
3905
ulint space) /*!< in: space id */
3907
fsp_header_t* header;
3908
fseg_inode_t* seg_inode;
3909
page_t* seg_inode_page;
3919
fil_addr_t node_addr;
3920
fil_addr_t next_node_addr;
3921
ulint descr_count = 0;
3924
ulint n_full_frag_pages;
3926
ulint seg_inode_len_free;
3927
ulint seg_inode_len_full;
3929
latch = fil_space_get_latch(space, &flags);
3930
zip_size = dict_table_flags_to_zip_size(flags);
3931
ut_a(ut_is_2pow(zip_size));
3932
ut_a(zip_size <= UNIV_PAGE_SIZE);
3933
ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
3935
/* Start first a mini-transaction mtr2 to lock out all other threads
3936
from the fsp system */
3938
mtr_x_lock(latch, &mtr2);
3941
mtr_x_lock(latch, &mtr);
3943
header = fsp_get_space_header(space, zip_size, &mtr);
3945
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3946
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3948
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3951
n_full_frag_pages = FSP_EXTENT_SIZE
3952
* flst_get_len(header + FSP_FULL_FRAG, &mtr);
3954
if (UNIV_UNLIKELY(free_limit > size)) {
3957
ut_a(size < FSP_EXTENT_SIZE);
3960
flst_validate(header + FSP_FREE, &mtr);
3961
flst_validate(header + FSP_FREE_FRAG, &mtr);
3962
flst_validate(header + FSP_FULL_FRAG, &mtr);
3966
/* Validate FSP_FREE list */
3968
mtr_x_lock(latch, &mtr);
3970
header = fsp_get_space_header(space, zip_size, &mtr);
3971
node_addr = flst_get_first(header + FSP_FREE, &mtr);
3975
while (!fil_addr_is_null(node_addr)) {
3977
mtr_x_lock(latch, &mtr);
3980
descr = xdes_lst_get_descriptor(space, zip_size,
3983
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3984
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3986
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3990
/* Validate FSP_FREE_FRAG list */
3992
mtr_x_lock(latch, &mtr);
3994
header = fsp_get_space_header(space, zip_size, &mtr);
3995
node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
3999
while (!fil_addr_is_null(node_addr)) {
4001
mtr_x_lock(latch, &mtr);
4004
descr = xdes_lst_get_descriptor(space, zip_size,
4007
ut_a(xdes_get_n_used(descr, &mtr) > 0);
4008
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
4009
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
4011
n_used += xdes_get_n_used(descr, &mtr);
4012
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4017
/* Validate FSP_FULL_FRAG list */
4019
mtr_x_lock(latch, &mtr);
4021
header = fsp_get_space_header(space, zip_size, &mtr);
4022
node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
4026
while (!fil_addr_is_null(node_addr)) {
4028
mtr_x_lock(latch, &mtr);
4031
descr = xdes_lst_get_descriptor(space, zip_size,
4034
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
4035
ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
4037
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4041
/* Validate segments */
4043
mtr_x_lock(latch, &mtr);
4045
header = fsp_get_space_header(space, zip_size, &mtr);
4047
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4049
seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
4053
while (!fil_addr_is_null(node_addr)) {
4058
mtr_x_lock(latch, &mtr);
4060
seg_inode_page = fut_get_ptr(
4061
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4062
- FSEG_INODE_PAGE_NODE;
4064
seg_inode = fsp_seg_inode_page_get_nth_inode(
4065
seg_inode_page, n, zip_size, &mtr);
4066
ut_a(!ut_dulint_is_zero(
4067
mach_read_from_8(seg_inode + FSEG_ID)));
4068
fseg_validate_low(seg_inode, &mtr);
4070
descr_count += flst_get_len(seg_inode + FSEG_FREE,
4072
descr_count += flst_get_len(seg_inode + FSEG_FULL,
4074
descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
4077
n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
4079
next_node_addr = flst_get_next_addr(
4080
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4082
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4084
node_addr = next_node_addr;
4088
mtr_x_lock(latch, &mtr);
4090
header = fsp_get_space_header(space, zip_size, &mtr);
4092
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4094
seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
4098
while (!fil_addr_is_null(node_addr)) {
4104
mtr_x_lock(latch, &mtr);
4106
seg_inode_page = fut_get_ptr(
4107
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4108
- FSEG_INODE_PAGE_NODE;
4110
seg_inode = fsp_seg_inode_page_get_nth_inode(
4111
seg_inode_page, n, zip_size, &mtr);
4112
if (!ut_dulint_is_zero(
4113
mach_read_from_8(seg_inode + FSEG_ID))) {
4114
fseg_validate_low(seg_inode, &mtr);
4116
descr_count += flst_get_len(
4117
seg_inode + FSEG_FREE, &mtr);
4118
descr_count += flst_get_len(
4119
seg_inode + FSEG_FULL, &mtr);
4120
descr_count += flst_get_len(
4121
seg_inode + FSEG_NOT_FULL, &mtr);
4122
n_used2 += fseg_get_n_frag_pages(
4126
next_node_addr = flst_get_next_addr(
4127
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4129
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4131
node_addr = next_node_addr;
4134
ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
4136
ut_a(n_used + n_full_frag_pages
4137
== n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
4139
+ seg_inode_len_full + seg_inode_len_free);
4141
ut_a(n_used + n_full_frag_pages
4142
== n_used2 + 2 * ((free_limit + (zip_size - 1))
4144
+ seg_inode_len_full + seg_inode_len_free);
4146
ut_a(frag_n_used == n_used);
4153
/*******************************************************************//**
4154
Prints info of a file space. */
4159
ulint space) /*!< in: space id */
4161
fsp_header_t* header;
4162
fseg_inode_t* seg_inode;
4163
page_t* seg_inode_page;
4170
fil_addr_t node_addr;
4171
fil_addr_t next_node_addr;
4183
latch = fil_space_get_latch(space, &flags);
4184
zip_size = dict_table_flags_to_zip_size(flags);
4186
/* Start first a mini-transaction mtr2 to lock out all other threads
4187
from the fsp system */
4191
mtr_x_lock(latch, &mtr2);
4195
mtr_x_lock(latch, &mtr);
4197
header = fsp_get_space_header(space, zip_size, &mtr);
4199
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4201
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4203
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4205
n_free = flst_get_len(header + FSP_FREE, &mtr);
4206
n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4207
n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4209
d_var = mtr_read_dulint(header + FSP_SEG_ID, &mtr);
4211
seg_id_low = ut_dulint_get_low(d_var);
4212
seg_id_high = ut_dulint_get_high(d_var);
4215
"FILE SPACE INFO: id %lu\n"
4216
"size %lu, free limit %lu, free extents %lu\n"
4217
"not full frag extents %lu: used pages %lu,"
4218
" full frag extents %lu\n"
4219
"first seg id not used %lu %lu\n",
4221
(ulong) size, (ulong) free_limit, (ulong) n_free,
4222
(ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4223
(ulong) seg_id_high, (ulong) seg_id_low);
4227
/* Print segments */
4230
mtr_x_lock(latch, &mtr);
4232
header = fsp_get_space_header(space, zip_size, &mtr);
4234
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4238
while (!fil_addr_is_null(node_addr)) {
4245
mtr_x_lock(latch, &mtr);
4247
seg_inode_page = fut_get_ptr(
4248
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4249
- FSEG_INODE_PAGE_NODE;
4251
seg_inode = fsp_seg_inode_page_get_nth_inode(
4252
seg_inode_page, n, zip_size, &mtr);
4253
ut_a(!ut_dulint_is_zero(
4254
mach_read_from_8(seg_inode + FSEG_ID)));
4255
fseg_print_low(seg_inode, &mtr);
4259
next_node_addr = flst_get_next_addr(
4260
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4262
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4264
node_addr = next_node_addr;
4268
mtr_x_lock(latch, &mtr);
4270
header = fsp_get_space_header(space, zip_size, &mtr);
4272
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4276
while (!fil_addr_is_null(node_addr)) {
4283
mtr_x_lock(latch, &mtr);
4285
seg_inode_page = fut_get_ptr(
4286
space, zip_size, node_addr, RW_X_LATCH, &mtr)
4287
- FSEG_INODE_PAGE_NODE;
4289
seg_inode = fsp_seg_inode_page_get_nth_inode(
4290
seg_inode_page, n, zip_size, &mtr);
4291
if (!ut_dulint_is_zero(
4292
mach_read_from_8(seg_inode + FSEG_ID))) {
4294
fseg_print_low(seg_inode, &mtr);
4298
next_node_addr = flst_get_next_addr(
4299
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4301
} while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4303
node_addr = next_node_addr;
4308
fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
4310
#endif /* !UNIV_HOTBACKUP */